changeset 763:58dcfb61cf76 trunk

[svn] Add support for resuming lost connections.
author iabervon
date Wed, 28 Feb 2007 23:01:41 -0800
parents 59b4bce10c3b
children 5810f14fc8e6
files ChangeLog src/curl/curl.c
diffstat 2 files changed, 104 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Feb 28 21:16:10 2007 -0800
+++ b/ChangeLog	Wed Feb 28 23:01:41 2007 -0800
@@ -1,3 +1,12 @@
+2007-03-01 05:16:10 +0000  William Pitcock <nenolod@sacredspiral.co.uk>
+  revision [1622]
+  - enable seeking on HTTP streams.
+  
+  trunk/src/madplug/decoder.c |    2 +-
+  trunk/src/madplug/plugin.c  |    1 -
+  2 files changed, 1 insertion(+), 2 deletions(-)
+
+
 2007-03-01 05:02:06 +0000  William Pitcock <nenolod@sacredspiral.co.uk>
   revision [1620]
   - support id3 reading of static files
--- a/src/curl/curl.c	Wed Feb 28 21:16:10 2007 -0800
+++ b/src/curl/curl.c	Wed Feb 28 23:01:41 2007 -0800
@@ -32,7 +32,7 @@
 #define REVERSE_SEEK_SIZE 2048
 
 #define DEBUG_CONNECTION 0
-#define DEBUG_OPEN_CLOSE 1
+#define DEBUG_OPEN_CLOSE 0
 #define DEBUG_SEEK 0
 #define DEBUG_READ 0
 #define DEBUG_HEADERS 0
@@ -61,6 +61,7 @@
   gsize rd_index;
   gsize wr_index;
 
+  gsize hdrs_start;
   gsize hdr_index;
 
   GSList *stream_stack; // stack for stream functions (getc, ungetc)
@@ -399,11 +400,12 @@
 		      // Empty header means the end of the headers
 		      handle->header = 0;
 		      handle->hdr_index = (i + 2) % handle->buffer_length;
-		      // We read from the start of the data in the request
-		      handle->rd_index = handle->hdr_index;
-		      // We've already written the amount that's after
-		      // the header.
-		      leftover = (handle->wr_index - handle->hdr_index + handle->buffer_length) % handle->buffer_length;
+		      // There's some after the header; we have to put
+		      // it in the buffer where we started the headers
+		      // and account for it in wr_abs.
+		      leftover = (handle->wr_index - handle->hdr_index + 
+				  handle->buffer_length) % 
+			handle->buffer_length;
 		      handle->wr_abs += leftover;
 		      if (handle->download)
 			{
@@ -413,6 +415,24 @@
 			  vfs_fwrite(ptr + ret - leftover, leftover, 1, 
 				     handle->download);
 			}
+		      handle->wr_index = handle->hdrs_start;
+		      if (handle->wr_index + leftover > handle->buffer_length)
+			{
+			  g_print("Wrapped rewrite\n");
+			  memcpy(handle->buffer + handle->wr_index, ptr + ret,
+				 handle->buffer_length - handle->wr_index);
+			  memcpy(handle->buffer, ptr + ret +
+				 handle->buffer_length - handle->wr_index,
+				 leftover - handle->buffer_length +
+				 handle->wr_index);
+			}
+		      else
+			{
+			  memcpy(handle->buffer + handle->wr_index, ptr + ret,
+				 leftover);
+			}
+		      handle->wr_index = (handle->wr_index + leftover) %
+			handle->buffer_length;
 		      handle->icy_left = handle->icy_interval;
 		      if (handle->icy_interval)
 			{
@@ -438,40 +458,60 @@
 {
   CurlHandle *handle = arg;
   CURLcode result;
-  if (DEBUG_CONNECTION)
-    g_print("Connect %p\n", handle);
-
-  if (handle->no_data)
-    curl_easy_setopt(handle->curl, CURLOPT_NOBODY, 1);
-  else
+  do
     {
       if (DEBUG_CONNECTION)
-	g_print("Start from %d\n", handle->wr_abs);
-      curl_easy_setopt(handle->curl, CURLOPT_RESUME_FROM, handle->wr_abs);
+	g_print("Connect %p\n", handle);
 
-      curl_easy_setopt(handle->curl, CURLOPT_NOBODY, 0);
-      curl_easy_setopt(handle->curl, CURLOPT_HTTPGET, 1);
-    }
-
-  handle->header = 1;
-  handle->hdr_index = 0;
-  handle->icy_interval = 0;
+      if (handle->no_data)
+	curl_easy_setopt(handle->curl, CURLOPT_NOBODY, 1);
+      else
+	{
+	  if (DEBUG_CONNECTION)
+	    g_print("Start from %d\n", handle->wr_abs);
+	  curl_easy_setopt(handle->curl, CURLOPT_RESUME_FROM, handle->wr_abs);
+	  
+	  curl_easy_setopt(handle->curl, CURLOPT_NOBODY, 0);
+	  curl_easy_setopt(handle->curl, CURLOPT_HTTPGET, 1);
+	}
+      
+      handle->header = 1;
+      handle->hdr_index = handle->wr_index;
+      handle->hdrs_start = handle->wr_index;
+      handle->icy_interval = 0;
 
-  result = curl_easy_perform(handle->curl);
-  if (result == CURLE_OK)
-    update_length(handle);
-  // We expect to get CURLE_WRITE_ERROR if we cancel.
-  // We get CURLE_GOT_NOTHING if we send a HEAD request to a shoutcast server.
-  // We get CURLE_HTTP_RANGE_ERROR if we try to use range with shoutcast.
-  if (result != CURLE_OK && result != CURLE_WRITE_ERROR && 
-      result != CURLE_GOT_NOTHING && result != CURLE_HTTP_RANGE_ERROR &&
-      result != CURLE_PARTIAL_FILE)
-    {
-      g_print("Got curl error %d\n", result);
-      handle->failed = 1;
+      if (DEBUG_CONNECTION)
+	g_print("About to perform %p\n", handle);
+      result = curl_easy_perform(handle->curl);
+      if (result == CURLE_OK)
+	{
+	  update_length(handle);
+	  //g_print("Length: %d\n", handle->length);
+	}
+      // We expect to get CURLE_WRITE_ERROR if we cancel.
+      // We get CURLE_GOT_NOTHING if we send a HEAD request to a shoutcast server.
+      // We get CURLE_HTTP_RANGE_ERROR if we try to use range with shoutcast.
+      // Why do we get CURLE_PARTIAL_FILE?
+      if (result != CURLE_OK && result != CURLE_WRITE_ERROR && 
+	  result != CURLE_GOT_NOTHING && result != CURLE_HTTP_RANGE_ERROR &&
+	  result != CURLE_PARTIAL_FILE)
+	{
+	  g_print("Got curl error %d\n", result);
+	  handle->failed = 1;
+	}
+      if (DEBUG_CONNECTION)
+	g_print("Got curl error %d\n", result);
+      if (result == CURLE_PARTIAL_FILE)
+	{
+	  if (DEBUG_CONNECTION)
+	    g_print("Lost connection %p; restarting\n", handle);
+	  continue;
+	}
+      if (DEBUG_CONNECTION)
+	g_print("Done %p%s", handle, handle->cancel ? " (aborted)\n" : "\n");
+      break;
     }
-  if (DEBUG_CONNECTION)
-    g_print("Done %p%s", handle, handle->cancel ? " (aborted)\n" : "\n");
+  while (1);
   handle->cancel = 1;
   return NULL;
 }
@@ -486,8 +526,8 @@
   if (!handle->thread)
     {
       handle->cancel = 0;
-      handle->wr_index = 0;
-      handle->rd_index = 0;
+      handle->rd_index = 0; //BUFFER_SIZE - 100;
+      handle->wr_index = handle->rd_index;
       handle->wr_abs = handle->rd_abs;
       if (DEBUG_CONNECTION)
 	g_print("Starting connection %p at %d\n", handle, handle->wr_abs);
@@ -827,9 +867,25 @@
   if (whence == SEEK_SET)
     handle->rd_abs = offset;
   else if (whence == SEEK_END)
-    handle->rd_abs = handle->length + offset;
+    {
+      if (-offset > handle->length)
+	handle->rd_abs = 0;
+      else
+	handle->rd_abs = handle->length + offset;
+    }
   else
-    handle->rd_abs = handle->rd_abs + offset;
+    {
+      if (-offset > handle->rd_abs)
+	handle->rd_abs = 0;
+      else
+	handle->rd_abs = handle->rd_abs + offset;
+    }
+
+  if (handle->rd_abs > handle->length)
+    {
+      g_print("Seek before start of file: %d %d = %d\n", posn, offset, 
+	      handle->rd_abs);
+    }
 
   // XXXX
   // There's a race here between finding available space and