[xiph-commits] r2871 - in liboggplay/trunk: include/oggplay plugin src/liboggplay

tahn at svn.annodex.net tahn at svn.annodex.net
Thu Jun 7 21:20:54 PDT 2007


Author: tahn
Date: 2007-06-07 21:20:54 -0700 (Thu, 07 Jun 2007)
New Revision: 2871

Modified:
   liboggplay/trunk/include/oggplay/oggplay.h
   liboggplay/trunk/include/oggplay/oggplay_enums.h
   liboggplay/trunk/include/oggplay/oggplay_reader.h
   liboggplay/trunk/include/oggplay/oggplay_tools.h
   liboggplay/trunk/plugin/plugin_gui_linux.c
   liboggplay/trunk/plugin/plugin_gui_mac.c
   liboggplay/trunk/plugin/plugin_oggplay.c
   liboggplay/trunk/src/liboggplay/oggplay.c
   liboggplay/trunk/src/liboggplay/oggplay_file_reader.c
   liboggplay/trunk/src/liboggplay/oggplay_tcp_reader.c
   liboggplay/trunk/src/liboggplay/oggplay_tcp_reader.h
Log:
Reworked the timeout for oggplay_initialise; it now has small "local" timeouts for each socket I/O call, and the plugin tracks the overall timeout of ~30s.
Also made a couple of simple utility functions; oggplay_millisleep and oggplay_sys_time_in_ms.


Modified: liboggplay/trunk/include/oggplay/oggplay.h
===================================================================
--- liboggplay/trunk/include/oggplay/oggplay.h	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/include/oggplay/oggplay.h	2007-06-08 04:20:54 UTC (rev 2871)
@@ -34,6 +34,7 @@
  * oggplay.h
  * 
  * Shane Stephens <shane.stephens at annodex.net>
+ * Michael Martin
  */
 
 #ifndef __OGGPLAY_H__
@@ -68,8 +69,8 @@
 oggplay_new_with_reader(OggPlayReader *reader, char *location);
 
 OggPlayErrorCode
-oggplay_initialise(OggPlay *me, int timeout_in_ms);
-  
+oggplay_initialise(OggPlay *me, int block);
+
 OggPlayErrorCode
 oggplay_set_source(OggPlay *OS, char *source);
 

Modified: liboggplay/trunk/include/oggplay/oggplay_enums.h
===================================================================
--- liboggplay/trunk/include/oggplay/oggplay_enums.h	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/include/oggplay/oggplay_enums.h	2007-06-08 04:20:54 UTC (rev 2871)
@@ -34,10 +34,11 @@
  * oggplay_enums.h
  * 
  * Shane Stephens <shane.stephens at annodex.net>
+ * Michael Martin
  */
 
-#ifndef __OGGSYNC_ENUMS_H__
-#define __OGGSYNC_ENUMS_H__
+#ifndef __OGGPLAY_ENUMS_H__
+#define __OGGPLAY_ENUMS_H__
 
 typedef enum OggPlayErrorCode {
   E_OGGPLAY_CONTINUE          = 1,

Modified: liboggplay/trunk/include/oggplay/oggplay_reader.h
===================================================================
--- liboggplay/trunk/include/oggplay/oggplay_reader.h	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/include/oggplay/oggplay_reader.h	2007-06-08 04:20:54 UTC (rev 2871)
@@ -34,16 +34,17 @@
  * oggplay_reader.h
  * 
  * Shane Stephens <shane.stephens at annodex.net>
+ * Michael Martin
  */
 
-#ifndef __OGGSYNC_READER_H__
-#define __OGGSYNC_READER_H__
+#ifndef __OGGPLAY_READER_H__
+#define __OGGPLAY_READER_H__
 
 struct _OggPlayReader;
 
 typedef struct _OggPlayReader {
   OggPlayErrorCode  (*initialise)(struct _OggPlayReader * me, char * source,
-                                  int timeout_in_ms);
+                                  int block);
   OggPlayErrorCode  (*destroy)(struct _OggPlayReader * me);
   OggPlayErrorCode  (*get_next_chunk)(struct _OggPlayReader *me, 
                                 unsigned char **position, int *size, int *base);

Modified: liboggplay/trunk/include/oggplay/oggplay_tools.h
===================================================================
--- liboggplay/trunk/include/oggplay/oggplay_tools.h	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/include/oggplay/oggplay_tools.h	2007-06-08 04:20:54 UTC (rev 2871)
@@ -31,9 +31,10 @@
 */
 
 /*
- * oggplay.h
+ * oggplay_tools.h
  * 
  * Shane Stephens <shane.stephens at annodex.net>
+ * Michael Martin
  */
 
 #ifndef __OGGPLAY_TOOLS_H__
@@ -67,6 +68,12 @@
 void 
 oggplay_yuv2bgr(OggPlayYUVChannels* yuv, OggPlayRGBChannels * rgb);
 
+ogg_int64_t
+oggplay_sys_time_in_ms();
+
+void
+oggplay_millisleep(long ms);
+
 #ifdef __cplusplus
 }
 #endif

Modified: liboggplay/trunk/plugin/plugin_gui_linux.c
===================================================================
--- liboggplay/trunk/plugin/plugin_gui_linux.c	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/plugin/plugin_gui_linux.c	2007-06-08 04:20:54 UTC (rev 2871)
@@ -16,7 +16,7 @@
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
- * Contributor(s): Shane Stephens
+ * Contributor(s): Shane Stephens, Michael Martin
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -437,8 +437,7 @@
   g_signal_emit_by_name(info->window, "destroy-event", NULL, &result);
 
   while (info->shutdown_gui) {
-    struct timespec t = {0, 10000};
-    nanosleep(&t, NULL);
+    oggplay_millisleep(10);
   }
 
   shut_oggplay(info->ogg_handle);

Modified: liboggplay/trunk/plugin/plugin_gui_mac.c
===================================================================
--- liboggplay/trunk/plugin/plugin_gui_mac.c	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/plugin/plugin_gui_mac.c	2007-06-08 04:20:54 UTC (rev 2871)
@@ -105,26 +105,6 @@
 
 /*
  * -----------------------------------------------------------------------------
- * Helper functions
- * -----------------------------------------------------------------------------
- */
-
-static void
-millisleep(long ms) {
-  struct timespec ts = {0, ms * 1000000};
-  nanosleep(&ts, NULL);
-}
-
-static int64_t
-get_curr_time() {
-  struct timeval tv;
-  gettimeofday(&tv, NULL);
-  return (int64_t)tv.tv_sec * 1000 + (int64_t)tv.tv_usec / 1000;
-}
-
-
-/*
- * -----------------------------------------------------------------------------
  * Display thread functions
  * -----------------------------------------------------------------------------
  */
@@ -369,9 +349,9 @@
 
   PluginWindowInfo  * info = (PluginWindowInfo *)_info;
   ThreadData          td;
-  int64_t             playback_target = 0;
   bool                paused = FALSE;
   bool                drop_video_frame = FALSE;
+  int64_t             playback_target = 0;
   int64_t             time_ref;
   int64_t             cur_time;
   int64_t             offset;
@@ -446,7 +426,7 @@
      */
     if (!have_video && !have_audio) {
       free_oggplay_frame(info->oggplay_handle, &td.frame_data);
-      millisleep(5);
+      oggplay_millisleep(5);
       continue;
     }
 
@@ -520,9 +500,9 @@
      */
     if (cur_time == -1) {
       if (playback_target == 0) {
-        time_ref = get_curr_time();
+        time_ref = oggplay_sys_time_in_ms();
       }
-      cur_time = get_curr_time() - time_ref;
+      cur_time = oggplay_sys_time_in_ms() - time_ref;
     }
 
     /*
@@ -545,7 +525,7 @@
     }
 
     free_oggplay_frame(info->oggplay_handle, &td.frame_data);
-    millisleep(offset);
+    oggplay_millisleep(offset);
 
   } /* while (!info->shutdown_gui) */
 
@@ -677,7 +657,7 @@
    */
   info->shutdown_gui = 1;
   while (info->shutdown_gui) {
-    millisleep(1);
+    oggplay_millisleep(1);
   }
 
   SEM_CLOSE(info->display_resize_sem);

Modified: liboggplay/trunk/plugin/plugin_oggplay.c
===================================================================
--- liboggplay/trunk/plugin/plugin_oggplay.c	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/plugin/plugin_oggplay.c	2007-06-08 04:20:54 UTC (rev 2871)
@@ -131,7 +131,32 @@
   SEM_CREATE(pointers->sem, LIBOGGPLAY_BUFFER_SIZE);
   SEM_SIGNAL(pointers->start_stop_sem);
   
-  oggplay_initialise(player, 0);
+  /*
+   * Wrap the oggplay startup process in a ~30 sec timeout. If we tell
+   * oggplay_initialise() not to block, it will use non-blocking I/O
+   * calls and return if any operation takes longer than some small
+   * period of time to complete.
+   */
+  ogg_int64_t time_ref = oggplay_sys_time_in_ms();
+  while (1) {
+    OggPlayErrorCode res = oggplay_initialise(player, 0);
+    if (res == E_OGGPLAY_OK) {
+      break;
+    }
+    if (pointers->shutdown_oggplay) {
+      goto thread_shutdown;
+    }
+    if (res == E_OGGPLAY_TIMEOUT) {
+      if (oggplay_sys_time_in_ms() - time_ref < 30000) {
+        continue;
+      }
+    }
+    printf("Failed to initialise oggplay; error %d\n", res);
+    while (!pointers->shutdown_oggplay) {
+      oggplay_millisleep(10);
+    }
+    goto thread_shutdown;
+  }
 
   for (i = 0; i < oggplay_get_num_tracks(player); i++) {
     if (oggplay_get_track_type(player, i) == OGGZ_CONTENT_THEORA) {
@@ -182,7 +207,6 @@
     SEM_WAIT(pointers->sem);
     
     if (pointers->shutdown_oggplay) {
-      pointers->shutdown_oggplay = 0;
       break;
     }
     
@@ -192,8 +216,10 @@
     }
   }
 
+thread_shutdown:
+  pointers->shutdown_oggplay = 0;
+
   SEM_CLOSE(pointers->sem); 
-  //SEM_CLOSE(pointers->start_stop_sem);
   oggplay_close(pointers->player);
   free(pointers->location);
   free(pointers);
@@ -252,25 +278,6 @@
   /*
    * we don't actually need to wait for the oggplay object to shut itself down.
    */
-    
-#if 0  
-#if defined(XP_UX)
-  while (pointers->shutdown_oggplay) {
-    struct timespec t = {0, 10000};
-    nanosleep(&t, NULL);
-  }
-#elif defined(XP_WIN)
-  while (pointers->shutdown_oggplay) {
-    Sleep(10);
-  }
-#elif defined(XP_MACOSX)
-  while (pointers->shutdown_oggplay) {
-    struct timespec t = {0, 10000};
-    nanosleep(&t, NULL);
-  }
-#endif
-#endif
-
 }
 
 void

Modified: liboggplay/trunk/src/liboggplay/oggplay.c
===================================================================
--- liboggplay/trunk/src/liboggplay/oggplay.c	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/src/liboggplay/oggplay.c	2007-06-08 04:20:54 UTC (rev 2871)
@@ -31,9 +31,10 @@
 */
 
 /*
- * oggsync.c
+ * oggplay.c
  * 
  * Shane Stephens <shane.stephens at annodex.net>
+ * Michael Martin
  */
 
 #include "oggplay_private.h"
@@ -42,6 +43,10 @@
 #include <string.h>
 #include <stdlib.h>
 
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+
 OggPlay *
 oggplay_new_with_reader(OggPlayReader *reader, char *location) {
 
@@ -65,12 +70,12 @@
 }
 
 OggPlayErrorCode
-oggplay_initialise(OggPlay *me, int timeout_in_ms) {
+oggplay_initialise(OggPlay *me, int block) {
 
   OggPlayErrorCode  return_val;
   int               i;
   
-  return_val = me->reader->initialise(me->reader, me->input_name, timeout_in_ms);
+  return_val = me->reader->initialise(me->reader, me->input_name, block);
   
   if (return_val != E_OGGPLAY_OK) {
     return return_val;
@@ -509,6 +514,10 @@
     return E_OGGPLAY_BAD_OGGPLAY;
   }
 
+  if (me->reader != NULL) {
+    me->reader->destroy(me->reader);
+  }
+
   for (i = 0; i < me->num_tracks; i++) {
     oggplay_callback_shutdown(me->decode_data[i]);
   } 
@@ -523,3 +532,27 @@
 
   return E_OGGPLAY_OK;
 }
+
+
+ogg_int64_t
+oggplay_sys_time_in_ms() {
+#ifdef WIN32
+  FILETIME ft;
+  GetSystemTimeAsFileTime(&ft);
+  return ((ogg_int64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime) / 10000;
+#else
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  return (ogg_int64_t)tv.tv_sec * 1000 + (ogg_int64_t)tv.tv_usec / 1000;
+#endif
+}
+
+void
+oggplay_millisleep(long ms) {
+#ifdef WIN32	
+  Sleep(ms);
+#else
+  struct timespec ts = {0, ms * 1000000};
+  nanosleep(&ts, NULL);
+#endif
+}

Modified: liboggplay/trunk/src/liboggplay/oggplay_file_reader.c
===================================================================
--- liboggplay/trunk/src/liboggplay/oggplay_file_reader.c	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/src/liboggplay/oggplay_file_reader.c	2007-06-08 04:20:54 UTC (rev 2871)
@@ -34,6 +34,7 @@
  * oggplay_file_reader.c
  * 
  * Shane Stephens <shane.stephens at annodex.net>
+ * Michael Martin
  */
 
 #include "oggplay_private.h"
@@ -43,11 +44,10 @@
 #include <string.h>
 
 OggPlayErrorCode
-oggplay_file_reader_initialise(OggPlayReader * opr, char * file_name,
-                                  int timeout_in_ms) {
+oggplay_file_reader_initialise(OggPlayReader * opr, char * file_name, int block) {
 
   OggPlayFileReader * me = (OggPlayFileReader *)opr;
-  (void)timeout_in_ms; /* unused for file readers */
+  (void)block; /* unused for file readers */
 
   if (me == NULL) {
     return E_OGGPLAY_BAD_READER;

Modified: liboggplay/trunk/src/liboggplay/oggplay_tcp_reader.c
===================================================================
--- liboggplay/trunk/src/liboggplay/oggplay_tcp_reader.c	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/src/liboggplay/oggplay_tcp_reader.c	2007-06-08 04:20:54 UTC (rev 2871)
@@ -34,6 +34,7 @@
  * oggplay_tcp_reader.c
  * 
  * Shane Stephens <shane.stephens at annodex.net>
+ * Michael Martin
  */
 
 #include "oggplay_private.h"
@@ -65,305 +66,295 @@
 #endif
 
 
-static void
-millisleep(long ms) {
-#ifdef WIN32	
-  Sleep(ms);
-#else
-  struct timespec ts = {0, ms * 1000000};
-  nanosleep(&ts, NULL);
-#endif
-}
-
-
-static ogg_int64_t
-curr_time_in_ms() {
+static int
+set_socket_blocking_state(OggPlayTCPReader *me, int is_blocking) {
 #ifdef WIN32
-  FILETIME ft;
-  GetSystemTimeAsFileTime(&ft);
-  return ((ogg_int64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime) / 10000;
+  u_long  io_mode = !is_blocking;
+  if (ioctlsocket(me->socket, FIONBIO, &io_mode) == SOCKET_ERROR) {
 #else
-  struct timeval tv;
-  gettimeofday(&tv, NULL);
-  return (ogg_int64_t)tv.tv_sec * 1000 + (ogg_int64_t)tv.tv_usec / 1000;
+  if (fcntl(me->socket, F_SETFL, is_blocking ? 0 : O_NONBLOCK) == -1) {
 #endif
+    return 0;
+  }
+  return 1;
 }
 
 
-static void
-close_socket(OggPlayTCPReader *me) {
+#define START_TIMEOUT(ref) \
+  (ref) = oggplay_sys_time_in_ms()
 
-  if (me->socket != INVALID_SOCKET) {
-#ifdef WIN32
-#ifdef HAVE_WINSOCK2
-    shutdown(me->socket, SD_BOTH);
-#endif
-    closesocket(me->socket);
-    WSACleanup();
-#else
-    close(me->socket);
-#endif
-    me->socket = INVALID_SOCKET;
+#define RETURN_ON_TIMEOUT_OR_CONTINUE(ref)        \
+  if (oggplay_sys_time_in_ms() - (ref) > 500) {   \
+    return E_OGGPLAY_TIMEOUT;                     \
+  } else {                                        \
+    oggplay_millisleep(10);                       \
+    continue;                                     \
   }
-}
 
-
 OggPlayErrorCode
-oggplay_tcp_reader_initialise(OggPlayReader * opr, char * location,
-                                int timeout_in_ms) {
+oggplay_tcp_reader_initialise(OggPlayReader * opr, char * location, int block) {
 
-  OggPlayTCPReader    * me   = (OggPlayTCPReader *)opr;
+  OggPlayTCPReader    * me = (OggPlayTCPReader *)opr;
   struct hostent      * he;
   struct sockaddr_in    addr;
+  char                * _location;
   char                * host;
   char                * path;
   char                * pos;
-  int                   r;
-  int                   offset;
-  int                   port = 80;
   int                   len;
-  int                   has_http = 0;
-  int                   remaining = TCP_READER_MAX_BUFFER_SIZE;
-  char                  buf[1024];
+  int                   nbytes;
+  int                   has_http;
+  int                   remaining;
+  char                  http_request_header[1024];
   ogg_int64_t           time_ref;
-#ifdef WIN32
-  u_long                io_mode;
-#endif
 
   if (me == NULL) {
     return E_OGGPLAY_BAD_READER;
   }
-
-  /*
-   * The easiest way to implement a no-timeout option is to make the
-   * timeout ridiculously long (like 24.8 days...)
-   */
-  time_ref = curr_time_in_ms();
-  if (timeout_in_ms <= 0) {
-    timeout_in_ms = 0x7fffffff;
+  if (me->state == OTRS_INIT_COMPLETE) {
+    return E_OGGPLAY_OK;
   }
 
   /*
-   * extract the host name and the path from the location
+   * Create the socket.
    */
-  len = strlen(location);
-  me->location = (char*)malloc(len + 1);
-  strcpy(me->location, location);
-  
+  if (me->state == OTRS_UNINITIALISED) {
+    assert(me->socket == INVALID_SOCKET);
 #ifdef WIN32	
 #ifdef HAVE_WINSOCK2        
-  WORD wVersionRequested = MAKEWORD(2,2);
+    WORD wVersionRequested = MAKEWORD(2,2);
 #else
-  WORD wVersionRequested = MAKEWORD(1,1);
+    WORD wVersionRequested = MAKEWORD(1,1);
 #endif
-  WSADATA wsaData;
-  if (WSAStartup(wVersionRequested, &wsaData) == -1) {
-    printf("Socket open error\n");
-    return E_OGGPLAY_SOCKET_ERROR;
-  }
-  if (wsaData.wVersion != wVersionRequested) {
-    printf("Incorrect winsock version [%d]\n", wVersionRequested);
-    WSACleanup();
-    return E_OGGPLAY_SOCKET_ERROR;
-  }
+    WSADATA wsaData;
+    if (WSAStartup(wVersionRequested, &wsaData) == -1) {
+      printf("Socket open error\n");
+      return E_OGGPLAY_SOCKET_ERROR;
+    }
+    if (wsaData.wVersion != wVersionRequested) {
+      printf("Incorrect winsock version [%d]\n", wVersionRequested);
+      WSACleanup();
+      return E_OGGPLAY_SOCKET_ERROR;
+    }
 #endif
 
-  me->socket = socket(PF_INET, SOCK_STREAM, 0);
-  if (me->socket == INVALID_SOCKET) {
+    me->socket = socket(PF_INET, SOCK_STREAM, 0);
+    if (me->socket == INVALID_SOCKET) {
+      printf("Could not create socket\n");
 #ifdef WIN32
-    WSACleanup();
+      WSACleanup();
 #endif
-    return E_OGGPLAY_SOCKET_ERROR;
+      return E_OGGPLAY_SOCKET_ERROR;
+    }
+
+    me->state = OTRS_SOCKET_CREATED;
   }
 
-  /* 
-   * Set the socket to non-blocking mode.
+  /*
+   * If required, set the socket to non-blocking mode so we can
+   * timeout and return control to the caller.
    */
-#ifdef WIN32
-  io_mode = 1;
-  if (ioctlsocket(me->socket, FIONBIO, &io_mode) == SOCKET_ERROR) {
-#else
-  if (fcntl(me->socket, F_SETFL, O_NONBLOCK) == -1) {
-#endif
-    close_socket(me);
-    return E_OGGPLAY_SOCKET_ERROR;
+  if (!block) {
+    if (!set_socket_blocking_state(me, 0)) {
+      return E_OGGPLAY_SOCKET_ERROR;
+    }
   }
 
-  if (strncmp(me->location, "http://", 7) == 0) {
-    path = strchr(me->location + 7, '/');
+  /*
+   * Extract the host name and the path from the location.
+   */
+  len = strlen(location);
+  _location = (char*)malloc(len + 2);
+  strcpy(_location, location);
+
+  if (strncmp(_location, "http://", 7) == 0) {
+    path = strchr(_location + 7, '/');
     has_http = 1;
   } else {
-    path = strchr(me->location, '/');
+    path = strchr(_location, '/');
+    has_http = 0;
   }
-  
+
   if (path == NULL) {
-    me->location = (char*)realloc(me->location, len + 2);
-    me->location[len] = '/';
-    me->location[len + 1] = '\0';
-    path = me->location + len;
-    len += 1;
+    _location[len] = '/';
+    _location[len + 1] = '\0';
+    path = _location + len;
   }
 
   if (has_http) {
-    host = (char*)malloc((path - me->location) - 6);
-    strncpy(host, me->location + 7, (path - me->location) - 7);
-    host[(path - me->location) - 7] = '\0';
+    host = (char*)malloc((path - _location) - 6);
+    strncpy(host, _location + 7, (path - _location) - 7);
+    host[(path - _location) - 7] = '\0';
   } else {
-    host = (char*)malloc((path - me->location) + 1);
-    strncpy(host, me->location, path - me->location);
-    host[path - me->location] = '\0';
+    host = (char*)malloc((path - _location) + 1);
+    strncpy(host, _location, path - _location);
+    host[path - _location] = '\0';
   }
+  printf("host: %s, path: %s\n", host, path);
+
+  /*
+   * Prepare the HTTP request header now, so we can free all our
+   * allocated memory before returning on any errors.
+   */
+  snprintf(http_request_header, 1024,
+    "GET %s HTTP/1.0\n"
+    "Host: %s\n"
+    "User-Agent: AnnodexFirefoxPlugin/0.1\n"
+    "Accept: */*\n"
+    "Connection: Keep-Alive\n\n", path, host);
+
   he = gethostbyname(host);
+  free(_location);
+  free(host);
   if (he == NULL) {
-    printf("Host %s not found\n", host);
-    close_socket(me);
+    printf("Host not found\n");
     return E_OGGPLAY_BAD_INPUT;
   }
-
-  printf("host: %s, path: %s\n", host, path);
-
   memcpy(&addr.sin_addr.s_addr, he->h_addr, he->h_length);
   addr.sin_family = AF_INET;
-  addr.sin_port = htons(port);
- 
+  addr.sin_port = htons(80);
+
   /*
-   * connect to the host
+   * Connect to the host.
    */
-  while (connect(me->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-    if (errno == EINPROGRESS || errno == EALREADY) {
-      if ((int)(curr_time_in_ms() - time_ref) > timeout_in_ms) {
-        close_socket(me);
-        return E_OGGPLAY_TIMEOUT;
+  if (me->state == OTRS_SOCKET_CREATED) {
+    START_TIMEOUT(time_ref);
+    while (connect(me->socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+      if (errno == EINPROGRESS || errno == EALREADY
+#ifdef WIN32
+          /* see http://msdn2.microsoft.com/en-us/library/ms737625.aspx */
+          || errno == EWOULDBLOCK || errno == EINVAL
+#endif      
+      ) {
+        RETURN_ON_TIMEOUT_OR_CONTINUE(time_ref);
+      } else if (errno == EISCONN) {
+        break;
       }
-      millisleep(1);
-      continue;
-    } else if (errno == EISCONN) {
-      break;
+      printf("Could not connect to host; error code is %d\n", errno);
+      return (errno == ETIMEDOUT) ? E_OGGPLAY_TIMEOUT : E_OGGPLAY_SOCKET_ERROR;
     }
-    printf("Could not connect to host; error code is %d\n", errno);
-    close_socket(me);
-    return (errno == ETIMEDOUT) ? E_OGGPLAY_TIMEOUT : E_OGGPLAY_SOCKET_ERROR;
+    me->state = OTRS_CONNECTED;
   }
 
   /*
-   * prepare and send an HTTP request header
+   * Send the HTTP request header.
+   *
+   * If this times out after sending some, but not all, of the request header,
+   * we'll end up sending the entire header string again. This is probably not
+   * the best idea, so we may want to rework it at some time...
    */
-  snprintf(buf, 1024,
-    "GET %s HTTP/1.0\n"
-    "Host: %s\n"
-    "User-Agent: AnnodexFirefoxPlugin/0.1\n"
-    "Accept: */*\n"
-    "Connection: Keep-Alive\n\n", path, host);
-
-  pos = buf;
-  len = strlen(buf);
-  while (1) {
+  if (me->state == OTRS_CONNECTED) {
+    pos = http_request_header;
+    len = strlen(http_request_header);
+    START_TIMEOUT(time_ref);
+    while (1) {
 #if WIN32  
-    r = send(me->socket, pos, len, 0);
+      nbytes = send(me->socket, pos, len, 0);
 #else  
-    r = write(me->socket, pos, len);
+      nbytes = write(me->socket, pos, len);
 #endif
-    if (r < 0) {
-      if (errno == EAGAIN) {
-        if ((int)(curr_time_in_ms() - time_ref) > timeout_in_ms) {
-          close_socket(me);
-          return E_OGGPLAY_TIMEOUT;
+      if (nbytes < 0) {
+        if (errno == EAGAIN) {
+          RETURN_ON_TIMEOUT_OR_CONTINUE(time_ref);
         }
-        millisleep(1);
-        continue;
+        return E_OGGPLAY_SOCKET_ERROR;
+      } else if (nbytes >= len) {
+        break;
       }
-      close_socket(me);
-      return E_OGGPLAY_SOCKET_ERROR;
-    } else if (r >= len) {
-      break;
+      pos += nbytes;
+      len -= nbytes;
     }
-    pos += r;
-    len -= r;
+    me->state = OTRS_SENT_HEADER;
   }
 
   /*
-   * fill the buffers before returning
-   */
-  me->buffer = (unsigned char*)malloc (TCP_READER_MAX_BUFFER_SIZE);
-  me->buffer_size = 0;
- 
-  /*
-   * strip out the HTTP response by finding the first Ogg packet
+   * Strip out the HTTP response by finding the first Ogg packet.
    */    
-  while (1) {
+  if (me->state == OTRS_SENT_HEADER) {
+    int offset;
+
+    if (me->buffer == NULL) {
+      me->buffer = (unsigned char*)malloc(TCP_READER_MAX_BUFFER_SIZE);
+      me->buffer_size = 0;
+    }
+
+    START_TIMEOUT(time_ref);
+    while (1) {
+      remaining = TCP_READER_MAX_BUFFER_SIZE - me->buffer_size;
 #if WIN32
-    r = recv(me->socket, (char*)(me->buffer + me->buffer_size), remaining - 1, 0);
+      nbytes = recv(me->socket, (char*)(me->buffer + me->buffer_size), remaining - 1, 0);
 #else
-    r = read(me->socket, (char*)(me->buffer + me->buffer_size), remaining - 1);
+      nbytes = read(me->socket, (char*)(me->buffer + me->buffer_size), remaining - 1);
 #endif
-    if (r < 0) {
-      if (errno == EAGAIN) {
-        if ((int)(curr_time_in_ms() - time_ref) > timeout_in_ms) {
-          close_socket(me);
-          return E_OGGPLAY_TIMEOUT;
+      if (nbytes < 0) {
+        if (errno == EAGAIN) {
+          RETURN_ON_TIMEOUT_OR_CONTINUE(time_ref);
         }
-        millisleep(1);
-        continue;
+        return E_OGGPLAY_SOCKET_ERROR;
+      } else if (nbytes == 0) {
+        /*
+         * End-of-file is an error here, because we should at least be able
+         * to read a complete HTTP response header.
+         */
+        return E_OGGPLAY_END_OF_FILE;
       }
-      close_socket(me);
-      return E_OGGPLAY_SOCKET_ERROR;
-    } else if (r == 0) {
-      close_socket(me);
-      return E_OGGPLAY_END_OF_FILE;
+      me->buffer[me->buffer_size + nbytes] = '\0';
+      pos = strstr((char *)(me->buffer), "OggS");
+      if (pos != NULL) {
+        break;
+      }
+      /* TODO: make this more robust */
+      if (strncmp((char *)me->buffer, "HTTP/1.1 200 OK", 15) != 0 &&
+          strncmp((char *)me->buffer, "HTTP/1.0 200 OK", 15) != 0) {
+        return E_OGGPLAY_BAD_INPUT;
+      }
+      if (nbytes > 4) {
+        memmove(me->buffer, me->buffer + nbytes - 4, 4);
+        me->buffer_size = 4;
+      } else {
+        me->buffer_size = nbytes;
+      }
     }
-    me->buffer[r] = '\0';
-    pos = strstr((char *)(me->buffer), "OggS");
-    if (pos == NULL) {
-      memmove(me->buffer, me->buffer + r - 4, 4);
-      me->buffer_size = 4;
-      remaining = TCP_READER_MAX_BUFFER_SIZE - 4;
-    } else {
-      break;
-    }
+    offset = pos - (char *)(me->buffer); 
+    memmove(me->buffer, pos, nbytes - offset);
+    me->buffer_size = nbytes - offset;
+
+    me->state = OTRS_HTTP_RESPONDED;
   }
 
-  offset = pos - (char *)(me->buffer); 
-  memmove(me->buffer, pos, r - offset);
-  me->buffer_size = r - offset;
-  remaining = TCP_READER_MAX_BUFFER_SIZE - me->buffer_size;
-  
   /*
-   * read in some more data
+   * Read in enough data to fill the buffer.
    */
-  while (remaining > 0) {
+  if (me->state == OTRS_HTTP_RESPONDED) {
+    remaining = TCP_READER_MAX_BUFFER_SIZE - me->buffer_size;
+    START_TIMEOUT(time_ref);
+    while (remaining > 0) {
 #ifdef WIN32
-    r = recv(me->socket, (char*)(me->buffer + me->buffer_size), remaining, 0);
+      nbytes = recv(me->socket, (char*)(me->buffer + me->buffer_size), remaining, 0);
 #else
-    r = read(me->socket, me->buffer + me->buffer_size, remaining);
+      nbytes = read(me->socket, me->buffer + me->buffer_size, remaining);
 #endif
-    if (r < 0) {
-      if (errno == EAGAIN) {
-        if ((int)(curr_time_in_ms() - time_ref) > timeout_in_ms) {
-          close_socket(me);
-          return E_OGGPLAY_TIMEOUT;
+      if (nbytes < 0) {
+        if (errno == EAGAIN) {
+          RETURN_ON_TIMEOUT_OR_CONTINUE(time_ref);
         }
-        millisleep(1);
-        continue;
+        return E_OGGPLAY_SOCKET_ERROR;
+      } else if (nbytes == 0) {
+        /*
+         * End-of-file is *not* an error here, it's just a really small file.
+         */
+        break;
       }
-      close_socket(me);
-      return E_OGGPLAY_SOCKET_ERROR;
-    } else if (r == 0) {
-      break;
+      me->buffer_size += nbytes;
+      remaining -= nbytes;
     }
-    me->buffer_size += r;
-    remaining -= r;
+    me->state = OTRS_INIT_COMPLETE;
   }
 
-  /* 
+  /*
    * Set the socket back to blocking mode.
    */
-#ifdef WIN32
-  io_mode = 0;
-  if (ioctlsocket(me->socket, FIONBIO, &io_mode) == SOCKET_ERROR) {
-#else
-  if (fcntl(me->socket, F_SETFL, 0) == -1) {
-#endif
-    close_socket(me);
+  if (!set_socket_blocking_state(me, 1)) {
     return E_OGGPLAY_SOCKET_ERROR;
   }
 
@@ -376,7 +367,18 @@
 
   OggPlayTCPReader * me = (OggPlayTCPReader *)opr;
 
-  close_socket(me);
+  if (me->socket != INVALID_SOCKET) {
+#ifdef WIN32
+#ifdef HAVE_WINSOCK2
+    shutdown(me->socket, SD_BOTH);
+#endif
+    closesocket(me->socket);
+    WSACleanup();
+#else
+    close(me->socket);
+#endif
+  }
+
   free(me->buffer);
   free(me);
   return E_OGGPLAY_OK;
@@ -423,7 +425,6 @@
   if (r < 0) {
     return E_OGGPLAY_SOCKET_ERROR;
   } else if (r == 0) {
-    close_socket(me);
     return E_OGGPLAY_END_OF_FILE;
   }
 
@@ -494,13 +495,14 @@
 
   OggPlayTCPReader * me = (OggPlayTCPReader *)malloc (sizeof (OggPlayTCPReader));
 
-  me->location = NULL;
+  me->state = OTRS_UNINITIALISED;
   me->socket = INVALID_SOCKET;
+  me->buffer = NULL;
+  me->buffer_size = 0;
   me->current_position = 0;
 
   me->functions.initialise = &oggplay_tcp_reader_initialise;
   me->functions.destroy = &oggplay_tcp_reader_destroy;
-  
   me->functions.get_next_chunk = &oggplay_tcp_reader_get_next_chunk;
   me->functions.mark_chunk_consumed = &oggplay_tcp_reader_mark_chunk_consumed;
   

Modified: liboggplay/trunk/src/liboggplay/oggplay_tcp_reader.h
===================================================================
--- liboggplay/trunk/src/liboggplay/oggplay_tcp_reader.h	2007-06-08 04:14:46 UTC (rev 2870)
+++ liboggplay/trunk/src/liboggplay/oggplay_tcp_reader.h	2007-06-08 04:20:54 UTC (rev 2871)
@@ -31,21 +31,31 @@
 */
 
 /*
- * oggsync_tcp_reader.h
+ * oggplay_tcp_reader.h
  * 
  * Shane Stephens <shane.stephens at annodex.net>
+ * Michael Martin
  */
 
-#ifndef __OGGSYNC_FILE_READER_H__
-#define __OGGSYNC_FILE_READER_H__
+#ifndef __OGGPLAY_FILE_READER_H__
+#define __OGGPLAY_FILE_READER_H__
 
 #include <stdio.h>
 
 #define TCP_READER_MAX_BUFFER_SIZE              16384
 
+typedef enum {
+  OTRS_UNINITIALISED,
+  OTRS_SOCKET_CREATED,
+  OTRS_CONNECTED,
+  OTRS_SENT_HEADER,
+  OTRS_HTTP_RESPONDED,
+  OTRS_INIT_COMPLETE
+} OPTCPReaderState;
+
 typedef struct {
   OggPlayReader     functions;
-  char            * location;
+  OPTCPReaderState  state;
 #ifdef _WIN32
   SOCKET            socket;
 #else



More information about the commits mailing list