Changeset 12127 for trunk/libtransmission/announcer.c
- Timestamp:
- Mar 11, 2011, 4:19:01 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/announcer.c
r12120 r12127 15 15 16 16 #include <event2/buffer.h> 17 #include <event2/event.h> 18 #include <event2/http.h> /* for HTTP_OK */ 17 #include <event2/event.h> /* evtimer */ 18 19 #define __LIBTRANSMISSION_ANNOUNCER_MODULE___ 19 20 20 21 #include "transmission.h" 21 22 #include "announcer.h" 23 #include "announcer-common.h" 22 24 #include "crypto.h" 23 25 #include "net.h" … … 31 33 #include "web.h" 32 34 33 #define STARTED "started" 35 struct tr_tier; 36 37 static void tier_build_log_name( const struct tr_tier * tier, 38 char * buf, size_t buflen ); 34 39 35 40 #define dbgmsg( tier, ... ) \ 36 41 if( tr_deepLoggingIsActive( ) ) do { \ 37 42 char name[128]; \ 38 tr_snprintf( name, sizeof( name ), "[%s--%s]", tr_torrentName( tier->tor ), \ 39 ( tier->currentTracker ? tier->currentTracker->hostname : "" ) ); \ 43 tier_build_log_name( tier, name, sizeof( name ) ); \ 40 44 tr_deepLog( __FILE__, __LINE__, name, __VA_ARGS__ ); \ 41 45 } while( 0 ) … … 62 66 /* this is an upper limit for the frequency of LDS announces */ 63 67 LPD_HOUSEKEEPING_INTERVAL_SECS = 5 64 65 68 }; 66 69 … … 69 72 ***/ 70 73 71 /** 72 * Since we can't poll a tr_torrent's fields after it's destroyed, 73 * we pre-build the "stop" announcement message when a torrent 74 * is removed from Transmission 75 */ 76 struct stop_message 77 { 78 char * url; 79 uint64_t up; 80 uint64_t down; 81 }; 82 83 static void 84 stopFree( struct stop_message * stop ) 85 { 86 tr_free( stop->url ); 87 tr_free( stop ); 88 } 74 const char* 75 tr_announce_event_get_string( tr_announce_event e ) 76 { 77 switch( e ) 78 { 79 case TR_ANNOUNCE_EVENT_COMPLETED: return "completed"; 80 case TR_ANNOUNCE_EVENT_STARTED: return "started"; 81 case TR_ANNOUNCE_EVENT_STOPPED: return "stopped"; 82 default: return ""; 83 } 84 } 85 86 /*** 87 **** 88 ***/ 89 89 90 90 static int … … 106 106 compareStops( const void * va, const void * vb ) 107 107 { 108 const struct stop_message* a = va;109 const struct stop_message* b = vb;108 const tr_announce_request * a = va; 109 const tr_announce_request * b = vb; 110 110 return compareTransfer( a->up, a->down, b->up, b->down); 111 111 } … … 120 120 typedef struct tr_announcer 121 121 { 122 tr_ptrArray stops; /* struct stop_message */ 122 /* Since we can't poll a tr_torrent's fields after it's destroyed, 123 * we pre-build the "stop" tr_announce_request when a torrent is 124 * removed from Transmission */ 125 tr_ptrArray stops; 126 123 127 tr_session * session; 124 128 struct event * upkeepTimer; … … 135 139 } 136 140 137 /* format: hostname + ':' + port */138 static char *139 getHostName( const char * url )140 {141 int port = 0;142 char * host = NULL;143 char * ret;144 tr_urlParse( url, -1, NULL, &host, &port, NULL );145 ret = tr_strdup_printf( "%s:%d", ( host ? host : "invalid" ), port );146 tr_free( host );147 return ret;148 }149 150 141 static inline time_t 151 142 calcRescheduleWithJitter( const int minPeriod ) 152 143 { 153 const double jitter Fac= 0.1;144 const double jitter = 0.1; 154 145 155 146 assert( minPeriod > 0 ); … … 157 148 return tr_time() 158 149 + minPeriod 159 + tr_cryptoWeakRandInt( (int) ( minPeriod * jitter Fac) + 1 );150 + tr_cryptoWeakRandInt( (int) ( minPeriod * jitter ) + 1 ); 160 151 } 161 152 … … 214 205 char * scrape; 215 206 216 char * tracker_id ;207 char * tracker_id_str; 217 208 218 209 int seederCount; … … 225 216 uint32_t id; 226 217 } 227 tr_tracker_item; 228 229 static tr_tracker_item* 230 trackerNew( const char * announce, 231 const char * scrape, 232 uint32_t id ) 233 { 234 tr_tracker_item * tracker = tr_new0( tr_tracker_item, 1 ); 218 tr_tracker; 219 220 /* format: hostname + ':' + port */ 221 static char * 222 getHostName( const char * url ) 223 { 224 int port = 0; 225 char * host = NULL; 226 char * ret; 227 tr_urlParse( url, -1, NULL, &host, &port, NULL ); 228 ret = tr_strdup_printf( "%s:%d", ( host ? host : "invalid" ), port ); 229 tr_free( host ); 230 return ret; 231 } 232 233 static tr_tracker* 234 trackerNew( const char * announce, const char * scrape, uint32_t id ) 235 { 236 tr_tracker * tracker = tr_new0( tr_tracker, 1 ); 235 237 tracker->hostname = getHostName( announce ); 236 238 tracker->announce = tr_strdup( announce ); … … 246 248 trackerFree( void * vtracker ) 247 249 { 248 tr_tracker _item* tracker = vtracker;249 250 tr_free( tracker->tracker_id );250 tr_tracker * tracker = vtracker; 251 252 tr_free( tracker->tracker_id_str ); 251 253 tr_free( tracker->scrape ); 252 254 tr_free( tracker->announce ); … … 262 264 263 265 /** @brief A group of trackers in a single tier, as per the multitracker spec */ 264 typedef struct 266 typedef struct tr_tier 265 267 { 266 268 /* number of up/down/corrupt bytes since the last time we sent an … … 268 270 uint64_t byteCounts[3]; 269 271 270 tr_ptrArray trackers; /* tr_tracker _item*/271 tr_tracker _item* currentTracker;272 tr_ptrArray trackers; /* tr_tracker */ 273 tr_tracker * currentTracker; 272 274 int currentTrackerIndex; 273 275 … … 287 289 tr_bool lastAnnounceTimedOut; 288 290 289 tr_ptrArray announceEvents; /* const char* */ 291 tr_announce_event * announce_events; 292 int announce_event_count; 293 int announce_event_alloc; 290 294 291 295 /* unique lookup key */ … … 317 321 t = tr_new0( tr_tier, 1 ); 318 322 t->key = nextKey++; 319 t->announceEvents = TR_PTR_ARRAY_INIT; 323 t->announce_events = NULL; 324 t->announce_event_count = 0; 325 t->announce_event_alloc = 0; 320 326 t->trackers = TR_PTR_ARRAY_INIT; 321 327 t->currentTracker = NULL; … … 335 341 tr_tier * tier = vtier; 336 342 tr_ptrArrayDestruct( &tier->trackers, trackerFree ); 337 tr_ ptrArrayDestruct( &tier->announceEvents, NULL);343 tr_free( tier->announce_events ); 338 344 tr_free( tier ); 345 } 346 347 static void 348 tier_build_log_name( const tr_tier * tier, char * buf, size_t buflen ) 349 { 350 tr_snprintf( buf, buflen, "[%s---%s]", 351 ( tier && tier->tor ) ? tr_torrentName( tier->tor ) : "?", 352 ( tier && tier->currentTracker ) ? tier->currentTracker->hostname : "?" ); 339 353 } 340 354 … … 359 373 360 374 static void 361 tierAddTracker( tr_tier 362 const char 363 const char 364 uint32_t 365 { 366 tr_tracker _item* tracker = trackerNew( announce, scrape, id );375 tierAddTracker( tr_tier * tier, 376 const char * announce, 377 const char * scrape, 378 uint32_t id ) 379 { 380 tr_tracker * tracker = trackerNew( announce, scrape, id ); 367 381 368 382 tr_ptrArrayAppend( &tier->trackers, tracker ); … … 407 421 408 422 static tr_tier* 409 getTier( tr_announcer * announcer, int torrentId, int tierId )423 getTier( tr_announcer * announcer, const uint8_t * info_hash, int tierId ) 410 424 { 411 425 tr_tier * tier = NULL; 412 426 413 if( announcer ) 414 { 415 tr_torrent * tor = tr_torrentFindFromId( announcer->session, torrentId ); 427 if( announcer != NULL ) 428 { 429 tr_session * session = announcer->session; 430 tr_torrent * tor = tr_torrentFindFromHash( session, info_hash ); 416 431 417 432 if( tor && tor->tiers ) … … 436 451 ***/ 437 452 438 static const tr_tracker_event emptyEvent = { 0, NULL, NULL, NULL, 0, 0 };453 static const tr_tracker_event TRACKER_EVENT_INIT = { 0, 0, 0, 0, 0, 0 }; 439 454 440 455 static void … … 444 459 { 445 460 tr_torrent_tiers * tiers = tier->tor->tiers; 446 tr_tracker_event event = emptyEvent;461 tr_tracker_event event = TRACKER_EVENT_INIT; 447 462 event.messageType = type; 448 463 event.text = msg; 449 event.tracker = tier->currentTracker ? tier->currentTracker->announce : NULL; 464 if( tier->currentTracker ) 465 event.tracker = tier->currentTracker->announce; 450 466 451 467 if( tiers->callback != NULL ) … … 466 482 } 467 483 484 static void 485 publishError( tr_tier * tier, const char * msg ) 486 { 487 publishMessage( tier, msg, TR_TRACKER_ERROR ); 488 } 489 468 490 static int8_t 469 491 getSeedProbability( int seeds, int leechers ) … … 482 504 const tr_pex * pex, int n ) 483 505 { 484 tr_tracker_event e = emptyEvent;506 tr_tracker_event e = TRACKER_EVENT_INIT; 485 507 486 508 e.messageType = TR_TRACKER_PEERS; … … 493 515 } 494 516 495 static size_t496 publishPeersCompact( tr_tier * tier, int seeds, int leechers,497 const void * compact, int compactLen )498 {499 size_t n = 0;500 tr_pex * pex = tr_peerMgrCompactToPex( compact, compactLen, NULL, 0, &n );501 publishPeersPex( tier, seeds, leechers, pex, n );502 dbgmsg( tier, "got IPv4 list of %zu peers", n );503 tr_free( pex );504 return n;505 }506 507 static size_t508 publishPeersCompact6( tr_tier * tier, int seeds, int leechers,509 const void * compact, int compactLen )510 {511 size_t n = 0;512 tr_pex * pex = tr_peerMgrCompact6ToPex( compact, compactLen, NULL, 0, &n );513 dbgmsg( tier, "got IPv6 list of %zu peers", n );514 publishPeersPex( tier, seeds, leechers, pex, n );515 tr_free( pex );516 return n;517 }518 519 static size_t520 publishPeersDict( tr_tier * tier, int seeds, int leechers, tr_benc * peerList )521 {522 size_t i;523 size_t n;524 const size_t len = tr_bencListSize( peerList );525 tr_pex * pex = tr_new0( tr_pex, len );526 527 for( i=n=0; i<len; ++i )528 {529 int64_t port;530 const char * ip;531 tr_address addr;532 tr_benc * peer = tr_bencListChild( peerList, i );533 534 if( peer == NULL )535 continue;536 if( !tr_bencDictFindStr( peer, "ip", &ip ) )537 continue;538 if( tr_pton( ip, &addr ) == NULL )539 continue;540 if( !tr_bencDictFindInt( peer, "port", &port ) )541 continue;542 if( ( port < 0 ) || ( port > USHRT_MAX ) )543 continue;544 if( !tr_isValidPeerAddress( &addr, port ) )545 continue;546 547 pex[n].addr = addr;548 pex[n].port = htons( (uint16_t)port );549 ++n;550 }551 552 dbgmsg( tier, "got benc list of %zu peers", n );553 publishPeersPex( tier, seeds, leechers, pex, n );554 tr_free( pex );555 return n;556 }557 558 static char*559 createAnnounceURL( const tr_announcer * announcer,560 const tr_torrent * torrent,561 const tr_tier * tier,562 const char * eventName )563 {564 const int isStopping = !strcmp( eventName, "stopped" );565 const int numwant = isStopping ? 0 : NUMWANT;566 const tr_tracker_item * tracker = tier->currentTracker;567 const char * ann = tracker->announce;568 struct evbuffer * buf = evbuffer_new( );569 const char * str;570 const unsigned char * ipv6;571 572 evbuffer_expand( buf, 2048 );573 574 evbuffer_add_printf( buf, "%s"575 "%c"576 "info_hash=%s"577 "&peer_id=%s"578 "&port=%d"579 "&uploaded=%" PRIu64580 "&downloaded=%" PRIu64581 "&left=%" PRIu64582 "&numwant=%d"583 "&key=%x"584 "&compact=1"585 "&supportcrypto=1",586 ann,587 strchr( ann, '?' ) ? '&' : '?',588 torrent->info.hashEscaped,589 torrent->peer_id,590 (int)tr_sessionGetPublicPeerPort( announcer->session ),591 tier->byteCounts[TR_ANN_UP],592 tier->byteCounts[TR_ANN_DOWN],593 tr_cpLeftUntilComplete( &torrent->completion ),594 numwant,595 announcer->key );596 597 if( announcer->session->encryptionMode == TR_ENCRYPTION_REQUIRED )598 evbuffer_add_printf( buf, "&requirecrypto=1" );599 600 if( tier->byteCounts[TR_ANN_CORRUPT] )601 evbuffer_add_printf( buf, "&corrupt=%" PRIu64, tier->byteCounts[TR_ANN_CORRUPT] );602 603 str = eventName;604 if( str && *str )605 evbuffer_add_printf( buf, "&event=%s", str );606 607 str = tracker->tracker_id;608 if( str && *str )609 evbuffer_add_printf( buf, "&trackerid=%s", str );610 611 /* There are two incompatible techniques for announcing an IPv6 address.612 BEP-7 suggests adding an "ipv6=" parameter to the announce URL,613 while OpenTracker requires that peers announce twice, once over IPv4614 and once over IPv6.615 616 To be safe, we should do both: add the "ipv6=" parameter and617 announce twice. At any rate, we're already computing our IPv6618 address (for the LTEP handshake), so this comes for free. */619 620 ipv6 = tr_globalIPv6( );621 if( ipv6 ) {622 char ipv6_readable[INET6_ADDRSTRLEN];623 inet_ntop( AF_INET6, ipv6, ipv6_readable, INET6_ADDRSTRLEN );624 evbuffer_add_printf( buf, "&ipv6=");625 tr_http_escape( buf, ipv6_readable, -1, TRUE );626 }627 628 return evbuffer_free_to_str( buf );629 }630 631 632 517 /*** 633 518 **** … … 635 520 636 521 static void 637 addTorrentToTier( tr_torrent_tiers * tiers, 638 tr_torrent * tor ) 522 addTorrentToTier( tr_torrent_tiers * tiers, tr_torrent * tor ) 639 523 { 640 524 int i, n; … … 749 633 750 634 static void 751 tierAddAnnounce( tr_tier * tier, const char * announceEvent, time_t announceAt ) 752 { 635 dbgmsg_tier_announce_queue( const tr_tier * tier ) 636 { 637 if( tr_deepLoggingIsActive( ) ) 638 { 639 int i; 640 char * str; 641 char name[128]; 642 struct evbuffer * buf = evbuffer_new( ); 643 644 tier_build_log_name( tier, name, sizeof( name ) ); 645 for( i=0; i<tier->announce_event_count; ++i ) 646 { 647 const tr_announce_event e = tier->announce_events[i]; 648 const char * str = tr_announce_event_get_string( e ); 649 evbuffer_add_printf( buf, "[%d:%s]", i, str ); 650 } 651 str = evbuffer_free_to_str( buf ); 652 tr_deepLog( __FILE__, __LINE__, name, "announce queue is %s", str ); 653 tr_free( str ); 654 } 655 } 656 657 static void 658 tier_announce_remove_trailing( tr_tier * tier, tr_announce_event e ) 659 { 660 while( ( tier->announce_event_count > 0 ) && ( tier->announce_events[tier->announce_event_count-1] == e ) ) 661 --tier->announce_event_count; 662 } 663 664 static void 665 tier_announce_event_push( tr_tier * tier, tr_announce_event e, time_t announceAt ) 666 { 667 int i; 668 753 669 assert( tier != NULL ); 754 assert( announceEvent != NULL ); 755 756 tr_ptrArrayAppend( &tier->announceEvents, (void*)announceEvent ); 670 671 dbgmsg_tier_announce_queue( tier ); 672 dbgmsg( tier, "appending \"%s\" to announce queue", tr_announce_event_get_string( e ) ); 673 674 if( tier->announce_event_count > 0 ) 675 { 676 /* special case #1: if we're adding a "stopped" event, 677 * dump everything leading up to it except "completed" */ 678 if( e == TR_ANNOUNCE_EVENT_STOPPED ) { 679 tr_bool has_completed = FALSE; 680 const tr_announce_event c = TR_ANNOUNCE_EVENT_COMPLETED; 681 for( i=0; !has_completed && i<tier->announce_event_count; ++i ) 682 has_completed = c == tier->announce_events[i]; 683 tier->announce_event_count = 0; 684 if( has_completed ) 685 tier->announce_events[tier->announce_event_count++] = c; 686 } 687 688 /* special case #2: dump all empty strings leading up to this event */ 689 tier_announce_remove_trailing( tier, TR_ANNOUNCE_EVENT_NONE ); 690 691 /* special case #3: no consecutive duplicates */ 692 tier_announce_remove_trailing( tier, e ); 693 } 694 695 /* make room in the array for another event */ 696 if( tier->announce_event_alloc <= tier->announce_event_count ) { 697 tier->announce_event_alloc += 4; 698 tier->announce_events = tr_renew( tr_announce_event, 699 tier->announce_events, 700 tier->announce_event_alloc ); 701 } 702 703 /* add it */ 704 tier->announce_events[tier->announce_event_count++] = e; 757 705 tier->announceAt = announceAt; 758 706 759 dbgmsg( tier, "appended event \"%s\"; announcing in %d seconds", announceEvent, (int)difftime(announceAt,time(NULL)) ); 760 } 761 762 static void 763 torrentAddAnnounce( tr_torrent * tor, const char * announceEvent, time_t announceAt ) 707 dbgmsg_tier_announce_queue( tier ); 708 dbgmsg( tier, "announcing in %d seconds", (int)difftime(announceAt,tr_time()) ); 709 } 710 711 static tr_bool 712 tier_announce_event_pull( tr_tier * tier, tr_announce_event * setme ) 713 { 714 const tr_bool success = tier->announce_event_count > 0; 715 716 if( success ) 717 { 718 *setme = tier->announce_events[0]; 719 720 tr_removeElementFromArray( tier->announce_events, 721 0, sizeof( tr_announce_event ), 722 tier->announce_event_count-- ); 723 } 724 725 return success; 726 } 727 728 static void 729 torrentAddAnnounce( tr_torrent * tor, tr_announce_event e, time_t announceAt ) 764 730 { 765 731 int i; … … 772 738 n = tr_ptrArraySize( &tiers->tiers ); 773 739 for( i=0; i<n; ++i ) 774 tierAddAnnounce( tr_ptrArrayNth( &tiers->tiers, i ), announceEvent, announceAt ); 740 { 741 tr_tier * tier = tr_ptrArrayNth( &tiers->tiers, i ); 742 tier_announce_event_push( tier, e, announceAt ); 743 } 775 744 } 776 745 … … 778 747 tr_announcerTorrentStarted( tr_torrent * tor ) 779 748 { 780 torrentAddAnnounce( tor, STARTED, tr_time( ) );749 torrentAddAnnounce( tor, TR_ANNOUNCE_EVENT_STARTED, tr_time( ) ); 781 750 } 782 751 void 783 752 tr_announcerManualAnnounce( tr_torrent * tor ) 784 753 { 785 torrentAddAnnounce( tor, "", tr_time( ) );754 torrentAddAnnounce( tor, TR_ANNOUNCE_EVENT_NONE, tr_time( ) ); 786 755 } 787 756 void 788 757 tr_announcerTorrentStopped( tr_torrent * tor ) 789 758 { 790 torrentAddAnnounce( tor, "stopped", tr_time( ) );759 torrentAddAnnounce( tor, TR_ANNOUNCE_EVENT_STOPPED, tr_time( ) ); 791 760 } 792 761 void 793 762 tr_announcerTorrentCompleted( tr_torrent * tor ) 794 763 { 795 torrentAddAnnounce( tor, "completed", tr_time( ) );764 torrentAddAnnounce( tor, TR_ANNOUNCE_EVENT_COMPLETED, tr_time( ) ); 796 765 } 797 766 void … … 826 795 **** 827 796 ***/ 797 798 static tr_announce_request * 799 announce_request_new( const tr_announcer * announcer, 800 const tr_torrent * tor, 801 const tr_tier * tier, 802 tr_announce_event event ) 803 { 804 tr_announce_request * req = tr_new0( tr_announce_request, 1 ); 805 req->url = tr_strdup( tier->currentTracker->announce ); 806 req->tracker_id_str = tr_strdup( tier->currentTracker->tracker_id_str ); 807 memcpy( req->info_hash, tor->info.hash, SHA_DIGEST_LENGTH ); 808 memcpy( req->peer_id, tor->peer_id, PEER_ID_LEN ); 809 req->up = tier->byteCounts[TR_ANN_UP]; 810 req->down = tier->byteCounts[TR_ANN_DOWN]; 811 req->corrupt = tier->byteCounts[TR_ANN_CORRUPT]; 812 req->left = tr_cpLeftUntilComplete( &tor->completion ), 813 req->event = event; 814 req->numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : NUMWANT; 815 req->key = announcer->key; 816 req->partial_seed = tr_cpGetStatus( &tor->completion ) == TR_PARTIAL_SEED; 817 tier_build_log_name( tier, req->log_name, sizeof( req->log_name ) ); 818 return req; 819 } 828 820 829 821 void … … 839 831 { 840 832 tr_tier * tier = tr_ptrArrayNth( &tor->tiers->tiers, i ); 841 842 833 if( tier->isRunning ) 843 834 { 844 struct stop_message * s = tr_new0( struct stop_message, 1 ); 845 s->up = tier->byteCounts[TR_ANN_UP]; 846 s->down = tier->byteCounts[TR_ANN_DOWN]; 847 s->url = createAnnounceURL( announcer, tor, tier, "stopped" ); 848 tr_ptrArrayInsertSorted( &announcer->stops, s, compareStops ); 835 const tr_announce_event e = TR_ANNOUNCE_EVENT_STOPPED; 836 tr_announce_request * req = announce_request_new( announcer, tor, tier, e ); 837 tr_ptrArrayInsertSorted( &announcer->stops, req, compareStops ); 849 838 } 850 839 } … … 855 844 } 856 845 857 /***858 ****859 ***/860 861 static tr_bool862 parseAnnounceResponse( tr_tier * tier,863 const char * response,864 size_t responseLen,865 tr_bool * gotScrape )866 {867 tr_benc benc;868 tr_bool success = FALSE;869 int scrapeFields = 0;870 const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, NULL );871 872 if( getenv( "TR_CURL_VERBOSE" ) != NULL )873 {874 char * str = tr_bencToStr( &benc, TR_FMT_JSON, NULL );875 fprintf( stderr, "Announce response:\n< %s\n", str );876 tr_free( str );877 }878 879 dbgmsg( tier, "response len: %d, isBenc: %d", (int)responseLen, (int)bencLoaded );880 publishErrorClear( tier );881 if( bencLoaded && tr_bencIsDict( &benc ) )882 {883 size_t rawlen;884 int64_t i;885 tr_benc * tmp;886 const char * str;887 const uint8_t * raw;888 tr_bool gotPeers = FALSE;889 int peerCount = 0;890 891 success = TRUE;892 893 if( tr_bencDictFindStr( &benc, "failure reason", &str ) )894 {895 tr_strlcpy( tier->lastAnnounceStr, str,896 sizeof( tier->lastAnnounceStr ) );897 dbgmsg( tier, "tracker gave \"%s\"", str );898 publishMessage( tier, str, TR_TRACKER_ERROR );899 success = FALSE;900 }901 902 if( tr_bencDictFindStr( &benc, "warning message", &str ) )903 {904 tr_strlcpy( tier->lastAnnounceStr, str,905 sizeof( tier->lastAnnounceStr ) );906 dbgmsg( tier, "tracker gave \"%s\"", str );907 publishWarning( tier, str );908 }909 910 if( tr_bencDictFindInt( &benc, "interval", &i ) )911 {912 dbgmsg( tier, "setting interval to %d", (int)i );913 tier->announceIntervalSec = i;914 }915 916 if( tr_bencDictFindInt( &benc, "min interval", &i ) )917 {918 dbgmsg( tier, "setting min interval to %d", (int)i );919 tier->announceMinIntervalSec = i;920 }921 922 if( tr_bencDictFindStr( &benc, "tracker id", &str ) )923 {924 tier->currentTracker->tracker_id = tr_strdup( str );925 }926 927 if( !tr_bencDictFindInt( &benc, "complete", &i ) )928 tier->currentTracker->seederCount = 0;929 else {930 ++scrapeFields;931 tier->currentTracker->seederCount = i;932 }933 934 if( !tr_bencDictFindInt( &benc, "incomplete", &i ) )935 tier->currentTracker->leecherCount = 0;936 else {937 ++scrapeFields;938 tier->currentTracker->leecherCount = i;939 }940 941 if( tr_bencDictFindInt( &benc, "downloaded", &i ) )942 {943 ++scrapeFields;944 tier->currentTracker->downloadCount = i;945 }946 947 if( tr_bencDictFindRaw( &benc, "peers", &raw, &rawlen ) )948 {949 /* "compact" extension */950 const int seeders = tier->currentTracker->seederCount;951 const int leechers = tier->currentTracker->leecherCount;952 peerCount += publishPeersCompact( tier, seeders, leechers, raw, rawlen );953 gotPeers = TRUE;954 }955 else if( tr_bencDictFindList( &benc, "peers", &tmp ) )956 {957 /* original version of peers */958 const int seeders = tier->currentTracker->seederCount;959 const int leechers = tier->currentTracker->leecherCount;960 peerCount += publishPeersDict( tier, seeders, leechers, tmp );961 gotPeers = TRUE;962 }963 964 if( tr_bencDictFindRaw( &benc, "peers6", &raw, &rawlen ) )965 {966 /* "compact" extension */967 const int seeders = tier->currentTracker->seederCount;968 const int leechers = tier->currentTracker->leecherCount;969 peerCount += publishPeersCompact6( tier, seeders, leechers, raw, rawlen );970 gotPeers = TRUE;971 }972 973 if( tier->lastAnnounceStr[0] == '\0' )974 tr_strlcpy( tier->lastAnnounceStr, _( "Success" ),975 sizeof( tier->lastAnnounceStr ) );976 977 if( gotPeers )978 tier->lastAnnouncePeerCount = peerCount;979 }980 981 if( bencLoaded )982 tr_bencFree( &benc );983 984 *gotScrape = scrapeFields >= 2;985 986 return success;987 }988 989 846 static int 990 getRetryInterval( const tr_tracker _item* t )847 getRetryInterval( const tr_tracker * t ) 991 848 { 992 849 int minutes; … … 1005 862 struct announce_data 1006 863 { 1007 int torrentId;1008 864 int tierId; 1009 865 time_t timeSent; 1010 const char *event;866 tr_announce_event event; 1011 867 1012 868 /** If the request succeeds, the value for tier's "isRunning" flag */ … … 1015 871 1016 872 static void 1017 onAnnounceDone( tr_session * session, 1018 tr_bool didConnect, 1019 tr_bool didTimeout, 1020 long responseCode, 1021 const void * response, 1022 size_t responseLen, 1023 void * vdata ) 873 on_announce_error( tr_tier * tier, const char * err, tr_announce_event e ) 874 { 875 int interval; 876 877 /* set the error message */ 878 dbgmsg( tier, "%s", err ); 879 tr_torinf( tier->tor, "%s", err ); 880 tr_strlcpy( tier->lastAnnounceStr, err, sizeof( tier->lastAnnounceStr ) ); 881 882 /* switch to the next tracker */ 883 tierIncrementTracker( tier ); 884 885 /* schedule a reannounce */ 886 interval = getRetryInterval( tier->currentTracker ); 887 dbgmsg( tier, "Retrying announce in %d seconds.", interval ); 888 tier_announce_event_push( tier, e, tr_time( ) + interval ); 889 } 890 891 static void 892 on_announce_done( tr_session * session, 893 const tr_announce_response * response, 894 void * vdata ) 1024 895 { 1025 896 tr_announcer * announcer = session->announcer; 1026 897 struct announce_data * data = vdata; 1027 tr_tier * tier = getTier( announcer, data->torrentId, data->tierId );898 tr_tier * tier = getTier( announcer, response->info_hash, data->tierId ); 1028 899 const time_t now = tr_time( ); 1029 const char * announceEvent = data->event; 1030 1031 if( tier ) 1032 { 1033 tr_tracker_item * tracker; 900 const tr_announce_event event = data->event; 901 902 if( tier != NULL ) 903 { 904 tr_tracker * tracker; 905 906 dbgmsg( tier, "Got announce response: " 907 "connected:%d " 908 "timeout:%d " 909 "seeders:%d " 910 "leechers:%d " 911 "downloads:%d " 912 "interval:%d " 913 "min_interval:%d " 914 "tracker_id_str:%s " 915 "pex:%zu " 916 "pex6:%zu " 917 "err:%s " 918 "warn:%s", 919 (int)response->did_connect, 920 (int)response->did_timeout, 921 response->seeders, 922 response->leechers, 923 response->downloads, 924 response->interval, 925 response->min_interval, 926 response->tracker_id_str ? response->tracker_id_str : "none", 927 response->pex_count, 928 response->pex6_count, 929 response->errmsg ? response->errmsg : "none", 930 response->warning ? response->warning : "none" ); 1034 931 1035 932 tier->lastAnnounceTime = now; 1036 tier->lastAnnounceTimedOut = didTimeout;933 tier->lastAnnounceTimedOut = response->did_timeout; 1037 934 tier->lastAnnounceSucceeded = FALSE; 1038 935 tier->isAnnouncing = FALSE; … … 1042 939 ++tracker->consecutiveAnnounceFailures; 1043 940 1044 if( responseCode == HTTP_OK)941 if( !response->did_connect ) 1045 942 { 1046 tr_bool gotScrape; 1047 const tr_bool isStopped = !strcmp( announceEvent, "stopped" ); 1048 1049 if( parseAnnounceResponse( tier, response, responseLen, &gotScrape ) ) 943 on_announce_error( tier, _( "Could not connect to tracker" ), event ); 944 } 945 else if( response->did_timeout ) 946 { 947 on_announce_error( tier, _( "Tracker did not respond" ), event ); 948 } 949 else if( response->errmsg ) 950 { 951 publishError( tier, response->errmsg ); 952 on_announce_error( tier, response->errmsg, event ); 953 } 954 else 955 { 956 int i; 957 const char * str; 958 const tr_bool isStopped = event == TR_ANNOUNCE_EVENT_STOPPED; 959 960 publishErrorClear( tier ); 961 962 if(( tracker = tier->currentTracker )) 963 tracker->consecutiveAnnounceFailures = 0; 964 965 if(( str = response->warning )) 1050 966 { 1051 tier->lastAnnounceSucceeded = TRUE; 1052 tier->isRunning = data->isRunningOnSuccess; 1053 1054 if(( tracker = tier->currentTracker )) 1055 { 1056 tracker->consecutiveAnnounceFailures = 0; 1057 } 1058 1059 if( gotScrape ) 1060 { 1061 tier->lastScrapeTime = now; 1062 tier->lastScrapeSucceeded = TRUE; 1063 tier->scrapeAt = now + tier->scrapeIntervalSec; 1064 } 967 tr_strlcpy( tier->lastAnnounceStr, str, sizeof( tier->lastAnnounceStr ) ); 968 dbgmsg( tier, "tracker gave \"%s\"", str ); 969 publishWarning( tier, str ); 1065 970 } 971 972 if(( i = response->min_interval )) 973 tier->announceMinIntervalSec = i; 974 975 if(( i = response->interval )) 976 tier->announceIntervalSec = i; 977 978 if(( str = response->tracker_id_str )) 979 { 980 tr_free( tier->currentTracker->tracker_id_str ); 981 tier->currentTracker->tracker_id_str = tr_strdup( str ); 982 } 983 984 tier->currentTracker->seederCount = response->seeders; 985 tier->currentTracker->leecherCount = response->leechers; 986 tier->currentTracker->downloadCount = response->downloads; 987 988 if( response->pex_count > 0 ) 989 publishPeersPex( tier, response->seeders, response->leechers, 990 response->pex, response->pex_count ); 991 992 if( response->pex6_count > 0 ) 993 publishPeersPex( tier, response->seeders, response->leechers, 994 response->pex6, response->pex6_count ); 995 996 if( !*tier->lastAnnounceStr ) 997 tr_strlcpy( tier->lastAnnounceStr, _( "Success" ), 998 sizeof( tier->lastAnnounceStr ) ); 999 1000 tier->isRunning = data->isRunningOnSuccess; 1001 tier->scrapeAt = now + tier->scrapeIntervalSec; 1002 tier->lastScrapeTime = now; 1003 tier->lastScrapeSucceeded = TRUE; 1004 tier->lastAnnounceSucceeded = TRUE; 1005 tier->lastAnnouncePeerCount = response->pex_count 1006 + response->pex6_count; 1066 1007 1067 1008 if( isStopped ) … … 1075 1016 } 1076 1017 1077 if( !isStopped && !t r_ptrArraySize( &tier->announceEvents ))1018 if( !isStopped && !tier->announce_event_count ) 1078 1019 { 1079 1020 /* the queue is empty, so enqueue a perodic update */ 1080 const int interval= tier->announceIntervalSec;1081 dbgmsg( tier, "Sending periodic reannounce in %d seconds", i nterval);1082 tier AddAnnounce( tier, "", now + interval);1021 i = tier->announceIntervalSec; 1022 dbgmsg( tier, "Sending periodic reannounce in %d seconds", i ); 1023 tier_announce_event_push( tier, TR_ANNOUNCE_EVENT_NONE, now + i ); 1083 1024 } 1084 }1085 else1086 {1087 int interval;1088 1089 if( !didConnect )1090 tr_strlcpy( tier->lastAnnounceStr, _( "Could not connect to tracker" ),1091 sizeof( tier->lastAnnounceStr ) );1092 else if( !responseCode )1093 tr_strlcpy( tier->lastAnnounceStr, _( "Tracker did not respond" ),1094 sizeof( tier->lastAnnounceStr ) );1095 else {1096 /* %1$ld - http status code, such as 4041097 * %2$s - human-readable explanation of the http status code */1098 tr_snprintf( tier->lastAnnounceStr, sizeof( tier->lastAnnounceStr ),1099 _( "Tracker gave HTTP response code %1$ld (%2$s)" ),1100 responseCode,1101 tr_webGetResponseStr( responseCode ) );1102 if( responseCode >= 400 )1103 if( tr_torrentIsPrivate( tier->tor ) || ( tier->tor->info.trackerCount == 1 ) )1104 publishWarning( tier, tier->lastAnnounceStr );1105 }1106 dbgmsg( tier, "%s", tier->lastAnnounceStr );1107 tr_torinf( tier->tor, "%s", tier->lastAnnounceStr );1108 1109 tierIncrementTracker( tier );1110 1111 /* schedule the next announce */1112 interval = getRetryInterval( tier->currentTracker );1113 dbgmsg( tier, "Retrying announce in %d seconds.", interval );1114 tierAddAnnounce( tier, announceEvent, now + interval );1115 1025 } 1116 1026 } … … 1122 1032 } 1123 1033 1124 static const char* 1125 getNextAnnounceEvent( tr_tier * tier ) 1126 { 1127 int i, n; 1128 int pos = -1; 1129 tr_ptrArray tmp; 1130 const char ** events; 1131 const char * str = NULL; 1132 1133 assert( tier != NULL ); 1134 assert( tr_isTorrent( tier->tor ) ); 1135 1136 events = (const char**) tr_ptrArrayPeek( &tier->announceEvents, &n ); 1137 1138 /* special case #1: if "stopped" is in the queue, 1139 * ignore everything before it except "completed" */ 1140 if( pos == -1 ) { 1141 tr_bool completed = FALSE; 1142 for( i = 0; i < n; ++i ) { 1143 if( !strcmp( events[i], "completed" ) ) 1144 completed = TRUE; 1145 if( !strcmp( events[i], "stopped" ) ) 1146 break; 1147 } 1148 if( !completed && ( i < n ) ) 1149 pos = i; 1150 } 1151 1152 /* special case #2: don't use empty strings if something follows them */ 1153 if( pos == -1 ) { 1154 for( i = 0; i < n; ++i ) 1155 if( *events[i] ) 1156 break; 1157 if( i < n ) 1158 pos = i; 1159 } 1160 1161 /* default: use the next in the queue */ 1162 if( ( pos == -1 ) && ( n > 0 ) ) 1163 pos = 0; 1164 1165 /* special case #3: if there are duplicate requests in a row, skip to the last one */ 1166 if( pos >= 0 ) { 1167 for( i=pos+1; i<n; ++i ) 1168 if( strcmp( events[pos], events[i] ) ) 1169 break; 1170 pos = i - 1; 1171 } 1172 1173 /* special case #4: BEP 21: "In order to tell the tracker that a peer is a 1174 * partial seed, it MUST send an event=paused parameter in every 1175 * announce while it is a partial seed." */ 1176 str = pos>=0 ? events[pos] : NULL; 1177 if( tr_cpGetStatus( &tier->tor->completion ) == TR_PARTIAL_SEED ) 1178 if( !str || strcmp( str, "stopped" ) ) 1179 str = "paused"; 1180 1181 #if 0 1182 for( i=0; i<n; ++i ) fprintf( stderr, "(%d)\"%s\" ", i, events[i] ); 1183 fprintf( stderr, "\n" ); 1184 fprintf( stderr, "using (%d)\"%s\"\n", pos, events[pos] ); 1185 if( strcmp( events[pos], str ) ) fprintf( stderr, "...but really using [%s]\n", str ); 1186 #endif 1187 1188 /* announceEvents array upkeep */ 1189 tmp = TR_PTR_ARRAY_INIT; 1190 for( i=pos+1; i<n; ++i ) 1191 tr_ptrArrayAppend( &tmp, (void*)events[i] ); 1192 tr_ptrArrayDestruct( &tier->announceEvents, NULL ); 1193 tier->announceEvents = tmp; 1194 1195 return str; 1034 static void 1035 announce_request_delegate( tr_announcer * announcer, 1036 tr_announce_request * request, 1037 tr_announce_response_func * callback, 1038 void * callback_data ) 1039 { 1040 tr_session * session = announcer->session; 1041 1042 if( strstr( request->url, "http://" ) ) 1043 tr_tracker_http_announce( session, request, callback, callback_data ); 1044 else 1045 fprintf( stderr, "can't handle [%s] yet\n", request->url ); 1046 1047 tr_free( request->tracker_id_str ); 1048 tr_free( request->url ); 1049 tr_free( request ); 1196 1050 } 1197 1051 … … 1199 1053 tierAnnounce( tr_announcer * announcer, tr_tier * tier ) 1200 1054 { 1201 const char * announceEvent = getNextAnnounceEvent( tier );1055 tr_announce_event announce_event; 1202 1056 1203 1057 assert( !tier->isAnnouncing ); 1204 1058 1205 if( announceEvent != NULL ) 1206 { 1207 char * url; 1059 if( tier_announce_event_pull( tier, &announce_event ) ) 1060 { 1208 1061 struct announce_data * data; 1209 1062 const tr_torrent * tor = tier->tor; 1210 1063 const time_t now = tr_time( ); 1211 1064 1065 tr_announce_request * req = announce_request_new( announcer, tor, tier, announce_event ); 1066 1212 1067 data = tr_new0( struct announce_data, 1 ); 1213 data->torrentId = tr_torrentId( tor );1214 1068 data->tierId = tier->key; 1215 1069 data->isRunningOnSuccess = tor->isRunning; 1216 1070 data->timeSent = now; 1217 data->event = announceEvent; 1218 url = createAnnounceURL( announcer, tor, tier, data->event ); 1071 data->event = announce_event; 1219 1072 1220 1073 tier->isAnnouncing = TRUE; 1221 1074 tier->lastAnnounceStartTime = now; 1222 1075 --announcer->slotsAvailable; 1223 tr_webRun( announcer->session, url, NULL, onAnnounceDone, data ); 1224 1225 tr_free( url ); 1076 1077 announce_request_delegate( announcer, req, on_announce_done, data ); 1226 1078 } 1227 1079 } … … 1229 1081 /*** 1230 1082 **** 1083 **** SCRAPE 1084 **** 1231 1085 ***/ 1232 1086 1233 static tr_bool 1234 parseScrapeResponse( tr_tier * tier, 1235 const char * response, 1236 size_t responseLen, 1237 char * result, 1238 size_t resultlen ) 1239 { 1240 tr_bool success = FALSE; 1241 tr_benc benc, *files; 1242 const int bencLoaded = !tr_bencLoad( response, responseLen, &benc, NULL ); 1243 if( bencLoaded && tr_bencDictFindDict( &benc, "files", &files ) ) 1244 { 1245 const char * key; 1246 tr_benc * val; 1247 int i = 0; 1248 while( tr_bencDictChild( files, i++, &key, &val )) 1087 static void 1088 on_scrape_error( tr_tier * tier, const char * errmsg ) 1089 { 1090 int interval; 1091 1092 /* set the error message */ 1093 dbgmsg( tier, "Scrape error: %s", errmsg ); 1094 tr_torinf( tier->tor, "Scrape error: %s", errmsg ); 1095 tr_strlcpy( tier->lastScrapeStr, errmsg, sizeof( tier->lastScrapeStr ) ); 1096 1097 /* switch to the next tracker */ 1098 tierIncrementTracker( tier ); 1099 1100 /* schedule a rescrape */ 1101 interval = getRetryInterval( tier->currentTracker ); 1102 dbgmsg( tier, "Retrying scrape in %d seconds.", interval ); 1103 tier->lastScrapeSucceeded = FALSE; 1104 tier->scrapeAt = tr_time() + interval; 1105 } 1106 1107 static tr_tier * 1108 find_tier( tr_torrent * tor, const char * url ) 1109 { 1110 int i; 1111 int n = tr_ptrArraySize( &tor->tiers->tiers ); 1112 tr_tier ** tiers = (tr_tier**) tr_ptrArrayBase( &tor->tiers->tiers ); 1113 1114 for( i=0; i<n; ++i ) { 1115 tr_tracker * tracker = tiers[i]->currentTracker; 1116 if( tracker && !tr_strcmp0( tracker->scrape, url ) ) 1117 return tiers[i]; 1118 } 1119 1120 return NULL; 1121 } 1122 1123 static void 1124 on_scrape_done( tr_session * session, 1125 const tr_scrape_response * response, 1126 void * user_data UNUSED ) 1127 { 1128 int i; 1129 const time_t now = tr_time( ); 1130 tr_announcer * announcer = session->announcer; 1131 1132 for( i=0; i<response->row_count; ++i ) 1133 { 1134 const struct tr_scrape_response_row * row = &response->rows[i]; 1135 tr_torrent * tor = tr_torrentFindFromHash( session, row->info_hash ); 1136 1137 if( tor != NULL ) 1249 1138 { 1250 int64_t intVal; 1251 tr_benc * flags; 1252 1253 if( memcmp( tier->tor->info.hash, key, SHA_DIGEST_LENGTH ) ) 1254 continue; 1255 1256 success = TRUE; 1257 publishErrorClear( tier ); 1258 1259 if( ( tr_bencDictFindInt( val, "complete", &intVal ) ) ) 1260 tier->currentTracker->seederCount = intVal; 1261 1262 if( ( tr_bencDictFindInt( val, "incomplete", &intVal ) ) ) 1263 tier->currentTracker->leecherCount = intVal; 1264 1265 if( ( tr_bencDictFindInt( val, "downloaded", &intVal ) ) ) 1266 tier->currentTracker->downloadCount = intVal; 1267 1268 if( ( tr_bencDictFindInt( val, "downloaders", &intVal ) ) ) 1269 tier->currentTracker->downloaderCount = intVal; 1270 1271 if( tr_bencDictFindDict( val, "flags", &flags ) ) 1272 if( ( tr_bencDictFindInt( flags, "min_request_interval", &intVal ) ) ) 1273 tier->scrapeIntervalSec = MAX( DEFAULT_SCRAPE_INTERVAL_SEC, (int)intVal ); 1274 1275 tr_tordbg( tier->tor, 1276 "Scrape successful. Rescraping in %d seconds.", 1277 tier->scrapeIntervalSec ); 1278 } 1279 } 1280 1281 if( bencLoaded ) 1282 tr_bencFree( &benc ); 1283 1284 if( success ) 1285 tr_strlcpy( result, _( "Success" ), resultlen ); 1286 else 1287 tr_strlcpy( result, _( "Error parsing response" ), resultlen ); 1288 1289 return success; 1290 } 1291 1292 static void 1293 onScrapeDone( tr_session * session, 1294 tr_bool didConnect, 1295 tr_bool didTimeout, 1296 long responseCode, 1297 const void * response, 1298 size_t responseLen, 1299 void * vdata ) 1300 { 1301 tr_bool success = FALSE; 1302 tr_announcer * announcer = session->announcer; 1303 struct announce_data * data = vdata; 1304 tr_tier * tier = getTier( announcer, data->torrentId, data->tierId ); 1305 const time_t now = tr_time( ); 1139 tr_tier * tier = find_tier( tor, response->url ); 1140 1141 if( tier != NULL ) 1142 { 1143 dbgmsg( tier, "scraped url:%s -- " 1144 "did_connect:%d " 1145 "did_timeout:%d " 1146 "seeders:%d " 1147 "leechers:%d " 1148 "downloads:%d " 1149 "downloaders:%d " 1150 "min_request_interval:%d " 1151 "err:%s ", 1152 response->url, 1153 (int)response->did_connect, 1154 (int)response->did_timeout, 1155 row->seeders, 1156 row->leechers, 1157 row->downloads, 1158 row->downloaders, 1159 response->min_request_interval, 1160 response->errmsg ? response->errmsg : "none" ); 1161 1162 tier->isScraping = FALSE; 1163 tier->lastScrapeTime = now; 1164 tier->lastScrapeSucceeded = FALSE; 1165 tier->lastScrapeTimedOut = response->did_timeout; 1166 1167 if( !response->did_connect ) 1168 { 1169 on_scrape_error( tier, _( "Could not connect to tracker" ) ); 1170 } 1171 else if( response->did_timeout ) 1172 { 1173 on_scrape_error( tier, _( "Tracker did not respond" ) ); 1174 } 1175 else if( response->errmsg ) 1176 { 1177 on_scrape_error( tier, response->errmsg ); 1178 } 1179 else 1180 { 1181 tr_tracker * tracker; 1182 1183 tier->lastScrapeSucceeded = TRUE; 1184 tier->scrapeIntervalSec = MAX( DEFAULT_SCRAPE_INTERVAL_SEC, 1185 response->min_request_interval ); 1186 tier->scrapeAt = now + tier->scrapeIntervalSec; 1187 tr_tordbg( tier->tor, "Scrape successful. Rescraping in %d seconds.", 1188 tier->scrapeIntervalSec ); 1189 1190 if(( tracker = tier->currentTracker )) 1191 { 1192 tracker->seederCount = row->seeders; 1193 tracker->leecherCount = row->leechers; 1194 tracker->downloadCount = row->downloads; 1195 tracker->downloaderCount = row->downloaders; 1196 } 1197 } 1198 } 1199 } 1200 } 1306 1201 1307 1202 if( announcer ) 1308 1203 ++announcer->slotsAvailable; 1309 1310 if( announcer && tier ) 1311 { 1312 tier->isScraping = FALSE; 1313 tier->lastScrapeTime = now; 1314 1315 if( 200 <= responseCode && responseCode <= 299 ) 1316 { 1317 const int interval = tier->scrapeIntervalSec; 1318 tier->scrapeAt = now + interval; 1319 1320 if( responseCode == HTTP_OK ) 1321 success = parseScrapeResponse( tier, response, responseLen, 1322 tier->lastScrapeStr, sizeof( tier->lastScrapeStr ) ); 1323 else 1324 tr_snprintf( tier->lastScrapeStr, sizeof( tier->lastScrapeStr ), 1325 _( "tracker gave HTTP Response Code %1$ld (%2$s)" ), 1326 responseCode, tr_webGetResponseStr( responseCode ) ); 1327 dbgmsg( tier, "%s", tier->lastScrapeStr ); 1328 } 1329 else if( 300 <= responseCode && responseCode <= 399 ) 1330 { 1331 /* this shouldn't happen; libcurl should handle this */ 1332 const int interval = 5; 1333 tier->scrapeAt = now + interval; 1334 tr_snprintf( tier->lastScrapeStr, sizeof( tier->lastScrapeStr ), 1335 "Got a redirect. Retrying in %d seconds", interval ); 1336 dbgmsg( tier, "%s", tier->lastScrapeStr ); 1337 } 1338 else 1339 { 1340 const int interval = getRetryInterval( tier->currentTracker ); 1341 1342 /* Don't retry on a 4xx. 1343 * Retry at growing intervals on a 5xx */ 1344 if( 400 <= responseCode && responseCode <= 499 ) 1345 tier->scrapeAt = 0; 1346 else 1347 tier->scrapeAt = now + interval; 1348 1349 /* %1$ld - http status code, such as 404 1350 * %2$s - human-readable explanation of the http status code */ 1351 if( !didConnect ) 1352 tr_strlcpy( tier->lastScrapeStr, _( "Could not connect to tracker" ), 1353 sizeof( tier->lastScrapeStr ) ); 1354 else if( !responseCode ) 1355 tr_strlcpy( tier->lastScrapeStr, _( "tracker did not respond" ), 1356 sizeof( tier->lastScrapeStr ) ); 1357 else 1358 tr_snprintf( tier->lastScrapeStr, sizeof( tier->lastScrapeStr ), 1359 _( "tracker gave HTTP Response Code %1$ld (%2$s)" ), 1360 responseCode, tr_webGetResponseStr( responseCode ) ); 1361 } 1362 1363 tier->lastScrapeSucceeded = success; 1364 tier->lastScrapeTimedOut = didTimeout; 1365 } 1366 1367 tr_free( data ); 1204 } 1205 1206 static void 1207 scrape_request_delegate( tr_announcer * announcer, 1208 tr_scrape_request * request, 1209 tr_scrape_response_func * callback, 1210 void * callback_data ) 1211 { 1212 tr_session * session = announcer->session; 1213 1214 if( strstr( request->url, "http://" ) ) 1215 tr_tracker_http_scrape( session, request, callback, callback_data ); 1216 else 1217 fprintf( stderr, "can't handle [%s] yet\n", request->url ); 1368 1218 } 1369 1219 … … 1371 1221 tierScrape( tr_announcer * announcer, tr_tier * tier ) 1372 1222 { 1373 char * url; 1374 const char * scrape; 1375 struct announce_data * data; 1376 1223 tr_scrape_request request; 1224 1225 /* sanity clause */ 1377 1226 assert( tier ); 1378 1227 assert( !tier->isScraping ); … … 1380 1229 assert( tr_isTorrent( tier->tor ) ); 1381 1230 1382 data = tr_new0( struct announce_data, 1 ); 1383 data->torrentId = tr_torrentId( tier->tor ); 1384 data->tierId = tier->key; 1385 1386 scrape = tier->currentTracker->scrape; 1387 1388 url = tr_strdup_printf( "%s%cinfo_hash=%s", 1389 scrape, 1390 strchr( scrape, '?' ) ? '&' : '?', 1391 tier->tor->info.hashEscaped ); 1392 1231 /* initialize the request */ 1232 request.url = tier->currentTracker->scrape; 1233 request.info_hash_count = 1; 1234 memcpy( request.info_hash[0], tier->tor->info.hash, SHA_DIGEST_LENGTH ); 1235 tier_build_log_name( tier, request.log_name, sizeof( request.log_name ) ); 1236 1237 /* start scraping */ 1238 dbgmsg( tier, "scraping \"%s\"", request.url ); 1393 1239 tier->isScraping = TRUE; 1394 1240 tier->lastScrapeStartTime = tr_time( ); 1395 1241 --announcer->slotsAvailable; 1396 dbgmsg( tier, "scraping \"%s\"", url ); 1397 tr_webRun( announcer->session, url, NULL, onScrapeDone, data ); 1398 1399 tr_free( url ); 1242 scrape_request_delegate( announcer, &request, on_scrape_done, NULL ); 1400 1243 } 1401 1244 … … 1407 1250 1408 1251 for( i=0; i<n; ++i ) 1409 { 1410 struct stop_message * stop = tr_ptrArrayNth( &announcer->stops, i ); 1411 tr_webRun( announcer->session, stop->url, NULL, NULL, NULL ); 1412 stopFree( stop ); 1413 } 1252 announce_request_delegate( announcer, tr_ptrArrayNth( &announcer->stops, i ), NULL, NULL ); 1414 1253 1415 1254 tr_ptrArrayClear( &announcer->stops ); … … 1423 1262 && ( tier->announceAt != 0 ) 1424 1263 && ( tier->announceAt <= now ) 1425 && ( t r_ptrArraySize( &tier->announceEvents ) !=0 );1264 && ( tier->announce_event_count > 0 ); 1426 1265 } 1427 1266 … … 1495 1334 1496 1335 /* scrape some */ 1336 /* FIXME: multiscrape */ 1497 1337 n = MIN( tr_ptrArraySize( &scrapeMe ), announcer->slotsAvailable ); 1498 1338 for( i=0; i<n; ++i ) { … … 1590 1430 1591 1431 /* count the trackers... */ 1592 for( i=n=0, tierCount=tr_ptrArraySize( &torrent->tiers->tiers ); i<tierCount; ++i ) { 1432 tierCount = tr_ptrArraySize( &torrent->tiers->tiers ); 1433 for( i=n=0; i<tierCount; ++i ) { 1593 1434 const tr_tier * tier = tr_ptrArrayNth( &torrent->tiers->tiers, i ); 1594 1435 n += tr_ptrArraySize( &tier->trackers ); … … 1600 1441 1601 1442 /* populate the stats */ 1602 for( i=0, tierCount=tr_ptrArraySize( &torrent->tiers->tiers ); i<tierCount; ++i ) 1443 tierCount = tr_ptrArraySize( &torrent->tiers->tiers ); 1444 for( i=0; i<tierCount; ++i ) 1603 1445 { 1604 1446 int j; … … 1607 1449 for( j=0; j<n; ++j ) 1608 1450 { 1609 const tr_tracker _item* tracker = tr_ptrArrayNth( (tr_ptrArray*)&tier->trackers, j );1451 const tr_tracker * tracker = tr_ptrArrayNth( (tr_ptrArray*)&tier->trackers, j ); 1610 1452 tr_tracker_stat * st = ret + out++; 1611 1453 … … 1693 1535 1694 1536 static void 1695 trackerItemCopyAttributes( tr_tracker _item * t, const tr_tracker_item* o )1537 trackerItemCopyAttributes( tr_tracker * t, const tr_tracker * o ) 1696 1538 { 1697 1539 assert( t != o ); … … 1708 1550 tierCopyAttributes( tr_tier * t, const tr_tier * o ) 1709 1551 { 1710 int i, n;1711 1552 tr_tier bak; 1712 1553 … … 1719 1560 t->tor = bak.tor; 1720 1561 t->trackers = bak.trackers; 1721 t->announceEvents = bak.announceEvents; 1562 t->announce_events = tr_memdup( o->announce_events, sizeof( tr_announce_event ) * o->announce_event_count ); 1563 t->announce_event_count = o->announce_event_count; 1564 t->announce_event_alloc = o->announce_event_count; 1722 1565 t->currentTracker = bak.currentTracker; 1723 1566 t->currentTrackerIndex = bak.currentTrackerIndex; 1724 1725 tr_ptrArrayClear( &t->announceEvents );1726 for( i=0, n=tr_ptrArraySize(&o->announceEvents); i<n; ++i )1727 tr_ptrArrayAppend( &t->announceEvents, tr_ptrArrayNth((tr_ptrArray*)&o->announceEvents,i) );1728 1567 } 1729 1568 … … 1762 1601 for( k=0, kn=tr_ptrArraySize(&t->trackers); k<kn; ++k ) 1763 1602 { 1764 tr_tracker _item* item = tr_ptrArrayNth(&t->trackers,k);1603 tr_tracker * item = tr_ptrArrayNth(&t->trackers,k); 1765 1604 if( strcmp( o->currentTracker->announce, item->announce ) ) 1766 1605 continue; … … 1788 1627 tr_tier * tier = tiers[i]; 1789 1628 if( !tier->wasCopied ) 1790 tier AddAnnounce( tier,STARTED, now );1629 tier_announce_event_push( tier, TR_ANNOUNCE_EVENT_STARTED, now ); 1791 1630 } 1792 1631 }
Note: See TracChangeset
for help on using the changeset viewer.