From 44df1d5548a8345aed993ffd18ca7d4ef1dcc68f Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 10 Nov 2009 17:03:23 +0000 Subject: [PATCH] (trunk libT) #2112: provide "ipv6=" parameter to trackers --- libtransmission/announcer.c | 26 ++++++++++++++++++++++---- libtransmission/net.c | 22 ++++++++++++++++++++++ libtransmission/net.h | 2 ++ libtransmission/peer-msgs.c | 24 +----------------------- libtransmission/web.c | 37 +++++++++++++++++++++++++++++++++++++ libtransmission/web.h | 1 + libtransmission/webseed.c | 36 +++--------------------------------- 7 files changed, 88 insertions(+), 60 deletions(-) diff --git a/libtransmission/announcer.c b/libtransmission/announcer.c index c018a121d..89c6c3bde 100644 --- a/libtransmission/announcer.c +++ b/libtransmission/announcer.c @@ -649,6 +649,7 @@ createAnnounceURL( const tr_announcer * announcer, const char * ann = tracker->announce; struct evbuffer * buf = evbuffer_new( ); char * ret; + const unsigned char * ipv6; evbuffer_add_printf( buf, "%s" "%c" @@ -688,6 +689,23 @@ createAnnounceURL( const tr_announcer * announcer, if( tracker->tracker_id && *tracker->tracker_id ) evbuffer_add_printf( buf, "&trackerid=%s", tracker->tracker_id ); + /* There are two incompatible techniques for announcing an IPv6 address. + BEP-7 suggests adding an "ipv6=" parameter to the announce URL, + while OpenTracker requires that peers announce twice, once over IPv4 + and once over IPv6. + + To be safe, we should do both: add the "ipv6=" parameter and + announce twice. At any rate, we're already computing our IPv6 + address (for the LTEP handshake), so this comes for free. */ + + ipv6 = tr_globalIPv6( ); + if( ipv6 ) { + char ipv6_readable[INET6_ADDRSTRLEN]; + inet_ntop( AF_INET6, ipv6, ipv6_readable, INET6_ADDRSTRLEN ); + evbuffer_add_printf( buf, "&ipv6="); + tr_http_escape( buf, ipv6_readable, strlen(ipv6_readable), 0 ); + } + ret = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) ); evbuffer_free( buf ); @@ -1444,7 +1462,7 @@ onScrapeDone( tr_session * session, { tier->isScraping = FALSE; tier->lastScrapeTime = now; - + if( tier->currentTracker->host ) { tr_host * host = tier->currentTracker->host; @@ -1557,7 +1575,7 @@ flushCloseMessages( tr_announcer * announcer ) static tr_bool tierNeedsToAnnounce( const tr_tier * tier, const time_t now ) { - return !tier->isAnnouncing + return !tier->isAnnouncing && !tier->isScraping && ( tier->announceEvent != NULL ) && ( tier->announceAt <= now ); @@ -1726,7 +1744,7 @@ tr_announcerStats( const tr_torrent * torrent, else if( tier->scrapeAt > now ) { st->scrapeState = TR_TRACKER_WAITING; - st->nextScrapeTime = tier->scrapeAt; + st->nextScrapeTime = tier->scrapeAt; } else st->scrapeState = TR_TRACKER_QUEUED; @@ -1748,7 +1766,7 @@ tr_announcerStats( const tr_torrent * torrent, else if( tier->announceAt > now ) { st->announceState = TR_TRACKER_WAITING; - st->nextAnnounceTime = tier->announceAt; + st->nextAnnounceTime = tier->announceAt; } else st->announceState = TR_TRACKER_QUEUED; diff --git a/libtransmission/net.c b/libtransmission/net.c index c78d16f24..4d860e0d4 100644 --- a/libtransmission/net.c +++ b/libtransmission/net.c @@ -603,3 +603,25 @@ tr_globalAddress( int af, void *addr, int *addr_len ) return -1; } } + +/* Return our global IPv6 address, with caching. */ + +const unsigned char * +tr_globalIPv6( void ) +{ + static unsigned char ipv6[16]; + static time_t last_time = 0; + static int have_ipv6 = 0; + const time_t now = time( NULL ); + + /* Re-check every half hour */ + if( last_time < now - 1800 ) + { + int addrlen = 16; + const int rc = tr_globalAddress( AF_INET6, ipv6, &addrlen ); + have_ipv6 = ( rc >= 0 ) && ( addrlen == 16 ); + last_time = now; + } + + return have_ipv6 ? ipv6 : NULL; +} diff --git a/libtransmission/net.h b/libtransmission/net.h index 3008b7528..1f1fb2b0e 100644 --- a/libtransmission/net.h +++ b/libtransmission/net.h @@ -122,4 +122,6 @@ void tr_netInit( void ); int tr_globalAddress(int af, void *addr, int *addr_len); +const unsigned char *tr_globalIPv6( void ); + #endif /* _TR_NET_H_ */ diff --git a/libtransmission/peer-msgs.c b/libtransmission/peer-msgs.c index 0fee108ea..acd3be441 100644 --- a/libtransmission/peer-msgs.c +++ b/libtransmission/peer-msgs.c @@ -807,28 +807,6 @@ tr_peerMsgsCancel( tr_peermsgs * msgs, tr_block_index_t block ) *** **/ -/* Return our global IPv6 address, with caching. */ - -static const unsigned char * -globalIPv6( void ) -{ - static unsigned char ipv6[16]; - static time_t last_time = 0; - static int have_ipv6 = 0; - const time_t now = time( NULL ); - - /* Re-check every half hour */ - if( last_time < now - 1800 ) - { - int addrlen = 16; - const int rc = tr_globalAddress( AF_INET6, ipv6, &addrlen ); - have_ipv6 = ( rc >= 0 ) && ( addrlen == 16 ); - last_time = now; - } - - return have_ipv6 ? ipv6 : NULL; -} - static void sendLtepHandshake( tr_peermsgs * msgs ) { @@ -837,7 +815,7 @@ sendLtepHandshake( tr_peermsgs * msgs ) int len; int pex; struct evbuffer * out = msgs->outMessages; - const unsigned char * ipv6 = globalIPv6(); + const unsigned char * ipv6 = tr_globalIPv6(); if( msgs->clientSentLtepHandshake ) return; diff --git a/libtransmission/web.c b/libtransmission/web.c index a590966e0..a71ab72ff 100644 --- a/libtransmission/web.c +++ b/libtransmission/web.c @@ -647,3 +647,40 @@ tr_webGetResponseStr( long code ) compareResponseCodes ); return msg ? msg->text : "Unknown Error"; } + +/* escapes a string to be URI-legal as per RFC 2396. + like curl_escape() but can optionally avoid munging slashes. */ +void +tr_http_escape( struct evbuffer *out, const char *str, int len, int keep_slashes ) +{ + int i; + + for( i = 0; i < len; i++ ) { + switch( str[i] ) { + case ',': case '-': case '.': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': + evbuffer_add( out, &str[i], 1 ); + break; + case '/': + if(keep_slashes) { + evbuffer_add( out, &str[i], 1 ); + break; + } + /* Fall through. */ + default: + evbuffer_add_printf( out, "%%%02X", (unsigned)(str[i]&0xFF) ); + break; + } + } +} diff --git a/libtransmission/web.h b/libtransmission/web.h index 7305308c5..751ff56b2 100644 --- a/libtransmission/web.h +++ b/libtransmission/web.h @@ -36,5 +36,6 @@ void tr_webRun( tr_session * session, tr_web_done_func done_func, void * done_func_user_data ); +void tr_http_escape( struct evbuffer *out, const char *str, int len, int noslashes ); #endif diff --git a/libtransmission/webseed.c b/libtransmission/webseed.c index 3b99ee8e5..49e03220f 100644 --- a/libtransmission/webseed.c +++ b/libtransmission/webseed.c @@ -108,39 +108,9 @@ makeURL( tr_webseed * w, evbuffer_add( out, url, url_len ); /* if url ends with a '/', add the torrent name */ - if( url[url_len - 1] == '/' ) - { - const char * str = file->name; - - /* this is like curl_escape() but doesn't munge the - * '/' directory separators in the path */ - while( str && *str ) - { - switch( *str ) - { - case ',': case '-': case '.': case '/': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - evbuffer_add( out, str, 1 ); - break; - default: - evbuffer_add_printf( out, "%%%02X", *str ); - break; - } - str++; - } - } - + if( url[url_len - 1] == '/' && file->name ) + tr_http_escape( out, file->name, strlen(file->name), 1 ); + ret = tr_strndup( EVBUFFER_DATA( out ), EVBUFFER_LENGTH( out ) ); evbuffer_free( out ); return ret;