comparison src/curl/curl.c @ 763:58dcfb61cf76 trunk

[svn] Add support for resuming lost connections.
author iabervon
date Wed, 28 Feb 2007 23:01:41 -0800
parents a77533b76084
children 5810f14fc8e6
comparison
equal deleted inserted replaced
762:59b4bce10c3b 763:58dcfb61cf76
30 30
31 #define BUFFER_SIZE 256 * 1024 31 #define BUFFER_SIZE 256 * 1024
32 #define REVERSE_SEEK_SIZE 2048 32 #define REVERSE_SEEK_SIZE 2048
33 33
34 #define DEBUG_CONNECTION 0 34 #define DEBUG_CONNECTION 0
35 #define DEBUG_OPEN_CLOSE 1 35 #define DEBUG_OPEN_CLOSE 0
36 #define DEBUG_SEEK 0 36 #define DEBUG_SEEK 0
37 #define DEBUG_READ 0 37 #define DEBUG_READ 0
38 #define DEBUG_HEADERS 0 38 #define DEBUG_HEADERS 0
39 #define DEBUG_ICY 0 39 #define DEBUG_ICY 0
40 #define DEBUG_ICY_WRAP 0 40 #define DEBUG_ICY_WRAP 0
59 gchar *buffer; 59 gchar *buffer;
60 60
61 gsize rd_index; 61 gsize rd_index;
62 gsize wr_index; 62 gsize wr_index;
63 63
64 gsize hdrs_start;
64 gsize hdr_index; 65 gsize hdr_index;
65 66
66 GSList *stream_stack; // stack for stream functions (getc, ungetc) 67 GSList *stream_stack; // stack for stream functions (getc, ungetc)
67 68
68 gboolean header; // true if we haven't finished the header yet 69 gboolean header; // true if we haven't finished the header yet
397 { 398 {
398 size_t leftover; 399 size_t leftover;
399 // Empty header means the end of the headers 400 // Empty header means the end of the headers
400 handle->header = 0; 401 handle->header = 0;
401 handle->hdr_index = (i + 2) % handle->buffer_length; 402 handle->hdr_index = (i + 2) % handle->buffer_length;
402 // We read from the start of the data in the request 403 // There's some after the header; we have to put
403 handle->rd_index = handle->hdr_index; 404 // it in the buffer where we started the headers
404 // We've already written the amount that's after 405 // and account for it in wr_abs.
405 // the header. 406 leftover = (handle->wr_index - handle->hdr_index +
406 leftover = (handle->wr_index - handle->hdr_index + handle->buffer_length) % handle->buffer_length; 407 handle->buffer_length) %
408 handle->buffer_length;
407 handle->wr_abs += leftover; 409 handle->wr_abs += leftover;
408 if (handle->download) 410 if (handle->download)
409 { 411 {
410 // the data which has to go into the 412 // the data which has to go into the
411 // beginning of the file must be at the end 413 // beginning of the file must be at the end
412 // of the input that we've dealt with. 414 // of the input that we've dealt with.
413 vfs_fwrite(ptr + ret - leftover, leftover, 1, 415 vfs_fwrite(ptr + ret - leftover, leftover, 1,
414 handle->download); 416 handle->download);
415 } 417 }
418 handle->wr_index = handle->hdrs_start;
419 if (handle->wr_index + leftover > handle->buffer_length)
420 {
421 g_print("Wrapped rewrite\n");
422 memcpy(handle->buffer + handle->wr_index, ptr + ret,
423 handle->buffer_length - handle->wr_index);
424 memcpy(handle->buffer, ptr + ret +
425 handle->buffer_length - handle->wr_index,
426 leftover - handle->buffer_length +
427 handle->wr_index);
428 }
429 else
430 {
431 memcpy(handle->buffer + handle->wr_index, ptr + ret,
432 leftover);
433 }
434 handle->wr_index = (handle->wr_index + leftover) %
435 handle->buffer_length;
416 handle->icy_left = handle->icy_interval; 436 handle->icy_left = handle->icy_interval;
417 if (handle->icy_interval) 437 if (handle->icy_interval)
418 { 438 {
419 handle->icy_left -= 439 handle->icy_left -=
420 (handle->wr_index - handle->hdr_index + handle->buffer_length) % handle->buffer_length; 440 (handle->wr_index - handle->hdr_index + handle->buffer_length) % handle->buffer_length;
436 static gpointer 456 static gpointer
437 curl_manage_request(gpointer arg) 457 curl_manage_request(gpointer arg)
438 { 458 {
439 CurlHandle *handle = arg; 459 CurlHandle *handle = arg;
440 CURLcode result; 460 CURLcode result;
441 if (DEBUG_CONNECTION) 461 do
442 g_print("Connect %p\n", handle);
443
444 if (handle->no_data)
445 curl_easy_setopt(handle->curl, CURLOPT_NOBODY, 1);
446 else
447 { 462 {
448 if (DEBUG_CONNECTION) 463 if (DEBUG_CONNECTION)
449 g_print("Start from %d\n", handle->wr_abs); 464 g_print("Connect %p\n", handle);
450 curl_easy_setopt(handle->curl, CURLOPT_RESUME_FROM, handle->wr_abs); 465
451 466 if (handle->no_data)
452 curl_easy_setopt(handle->curl, CURLOPT_NOBODY, 0); 467 curl_easy_setopt(handle->curl, CURLOPT_NOBODY, 1);
453 curl_easy_setopt(handle->curl, CURLOPT_HTTPGET, 1); 468 else
454 } 469 {
455 470 if (DEBUG_CONNECTION)
456 handle->header = 1; 471 g_print("Start from %d\n", handle->wr_abs);
457 handle->hdr_index = 0; 472 curl_easy_setopt(handle->curl, CURLOPT_RESUME_FROM, handle->wr_abs);
458 handle->icy_interval = 0; 473
459 474 curl_easy_setopt(handle->curl, CURLOPT_NOBODY, 0);
460 result = curl_easy_perform(handle->curl); 475 curl_easy_setopt(handle->curl, CURLOPT_HTTPGET, 1);
461 if (result == CURLE_OK) 476 }
462 update_length(handle); 477
463 // We expect to get CURLE_WRITE_ERROR if we cancel. 478 handle->header = 1;
464 // We get CURLE_GOT_NOTHING if we send a HEAD request to a shoutcast server. 479 handle->hdr_index = handle->wr_index;
465 // We get CURLE_HTTP_RANGE_ERROR if we try to use range with shoutcast. 480 handle->hdrs_start = handle->wr_index;
466 if (result != CURLE_OK && result != CURLE_WRITE_ERROR && 481 handle->icy_interval = 0;
467 result != CURLE_GOT_NOTHING && result != CURLE_HTTP_RANGE_ERROR && 482
468 result != CURLE_PARTIAL_FILE) 483 if (DEBUG_CONNECTION)
469 { 484 g_print("About to perform %p\n", handle);
470 g_print("Got curl error %d\n", result); 485 result = curl_easy_perform(handle->curl);
471 handle->failed = 1; 486 if (result == CURLE_OK)
472 } 487 {
473 if (DEBUG_CONNECTION) 488 update_length(handle);
474 g_print("Done %p%s", handle, handle->cancel ? " (aborted)\n" : "\n"); 489 //g_print("Length: %d\n", handle->length);
490 }
491 // We expect to get CURLE_WRITE_ERROR if we cancel.
492 // We get CURLE_GOT_NOTHING if we send a HEAD request to a shoutcast server.
493 // We get CURLE_HTTP_RANGE_ERROR if we try to use range with shoutcast.
494 // Why do we get CURLE_PARTIAL_FILE?
495 if (result != CURLE_OK && result != CURLE_WRITE_ERROR &&
496 result != CURLE_GOT_NOTHING && result != CURLE_HTTP_RANGE_ERROR &&
497 result != CURLE_PARTIAL_FILE)
498 {
499 g_print("Got curl error %d\n", result);
500 handle->failed = 1;
501 }
502 if (DEBUG_CONNECTION)
503 g_print("Got curl error %d\n", result);
504 if (result == CURLE_PARTIAL_FILE)
505 {
506 if (DEBUG_CONNECTION)
507 g_print("Lost connection %p; restarting\n", handle);
508 continue;
509 }
510 if (DEBUG_CONNECTION)
511 g_print("Done %p%s", handle, handle->cancel ? " (aborted)\n" : "\n");
512 break;
513 }
514 while (1);
475 handle->cancel = 1; 515 handle->cancel = 1;
476 return NULL; 516 return NULL;
477 } 517 }
478 518
479 static void curl_req_xfer(CurlHandle *handle) 519 static void curl_req_xfer(CurlHandle *handle)
484 return; 524 return;
485 } 525 }
486 if (!handle->thread) 526 if (!handle->thread)
487 { 527 {
488 handle->cancel = 0; 528 handle->cancel = 0;
489 handle->wr_index = 0; 529 handle->rd_index = 0; //BUFFER_SIZE - 100;
490 handle->rd_index = 0; 530 handle->wr_index = handle->rd_index;
491 handle->wr_abs = handle->rd_abs; 531 handle->wr_abs = handle->rd_abs;
492 if (DEBUG_CONNECTION) 532 if (DEBUG_CONNECTION)
493 g_print("Starting connection %p at %d\n", handle, handle->wr_abs); 533 g_print("Starting connection %p at %d\n", handle, handle->wr_abs);
494 handle->thread = g_thread_create(curl_manage_request, handle, 534 handle->thread = g_thread_create(curl_manage_request, handle,
495 TRUE, NULL); 535 TRUE, NULL);
825 posn = handle->rd_abs; 865 posn = handle->rd_abs;
826 866
827 if (whence == SEEK_SET) 867 if (whence == SEEK_SET)
828 handle->rd_abs = offset; 868 handle->rd_abs = offset;
829 else if (whence == SEEK_END) 869 else if (whence == SEEK_END)
830 handle->rd_abs = handle->length + offset; 870 {
871 if (-offset > handle->length)
872 handle->rd_abs = 0;
873 else
874 handle->rd_abs = handle->length + offset;
875 }
831 else 876 else
832 handle->rd_abs = handle->rd_abs + offset; 877 {
878 if (-offset > handle->rd_abs)
879 handle->rd_abs = 0;
880 else
881 handle->rd_abs = handle->rd_abs + offset;
882 }
883
884 if (handle->rd_abs > handle->length)
885 {
886 g_print("Seek before start of file: %d %d = %d\n", posn, offset,
887 handle->rd_abs);
888 }
833 889
834 // XXXX 890 // XXXX
835 // There's a race here between finding available space and 891 // There's a race here between finding available space and
836 // allocating it and the check below. 892 // allocating it and the check below.
837 893