Mercurial > audlegacy-plugins
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 |