1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-25 01:03:01 +00:00

(trunk libT) #117 "UDP tracker support (BEP #15)" -- added request timeout

UDP announce and scrapes now have a 120 second TTL.
This commit is contained in:
Jordan Lee 2011-03-13 06:38:54 +00:00
parent 7a24257d00
commit 2cca699f06
4 changed files with 116 additions and 76 deletions

View file

@ -238,4 +238,6 @@ void tr_tracker_udp_announce( tr_session * session,
tr_announce_response_func response_func, tr_announce_response_func response_func,
void * user_data ); void * user_data );
void tr_tracker_udp_upkeep( tr_session * session );
#endif /* _TR_ANNOUNCER_COMMON_H_ */ #endif /* _TR_ANNOUNCER_COMMON_H_ */

View file

@ -120,6 +120,11 @@ typedef enum
} }
tau_action_t; tau_action_t;
enum
{
TAU_REQUEST_TTL = 120
};
/**** /****
***** *****
***** SCRAPE ***** SCRAPE
@ -157,7 +162,7 @@ tau_scrape_request_new( const tr_scrape_request * in,
memcpy( req->response.rows[i].info_hash, memcpy( req->response.rows[i].info_hash,
in->info_hash[i], SHA_DIGEST_LENGTH ); in->info_hash[i], SHA_DIGEST_LENGTH );
/* build the scrape payload */ /* build the payload */
buf = evbuffer_new( ); buf = evbuffer_new( );
evbuffer_add_hton_32( buf, TAU_ACTION_SCRAPE ); evbuffer_add_hton_32( buf, TAU_ACTION_SCRAPE );
evbuffer_add_hton_32( buf, req->transaction_id ); evbuffer_add_hton_32( buf, req->transaction_id );
@ -223,7 +228,6 @@ on_scrape_response( tr_session * session,
row->seeders = evbuffer_read_ntoh_32( buf ); row->seeders = evbuffer_read_ntoh_32( buf );
row->downloads = evbuffer_read_ntoh_32( buf ); row->downloads = evbuffer_read_ntoh_32( buf );
row->leechers = evbuffer_read_ntoh_32( buf ); row->leechers = evbuffer_read_ntoh_32( buf );
} }
tau_scrape_request_finished( session, request ); tau_scrape_request_finished( session, request );
@ -259,10 +263,10 @@ struct tau_announce_request
typedef enum typedef enum
{ {
/* used in the "event" field of an announce request */ /* used in the "event" field of an announce request */
UDP_TRACKER_EVENT_NONE = 0, TAU_ANNOUNCE_EVENT_NONE = 0,
UDP_TRACKER_EVENT_COMPLETED = 1, TAU_ANNOUNCE_EVENT_COMPLETED = 1,
UDP_TRACKER_EVENT_STARTED = 2, TAU_ANNOUNCE_EVENT_STARTED = 2,
UDP_TRACKER_EVENT_STOPPED = 3 TAU_ANNOUNCE_EVENT_STOPPED = 3
} }
tau_announce_event; tau_announce_event;
@ -271,10 +275,10 @@ get_tau_announce_event( tr_announce_event e )
{ {
switch( e ) switch( e )
{ {
case TR_ANNOUNCE_EVENT_COMPLETED: return UDP_TRACKER_EVENT_COMPLETED; case TR_ANNOUNCE_EVENT_COMPLETED: return TAU_ANNOUNCE_EVENT_COMPLETED;
case TR_ANNOUNCE_EVENT_STARTED: return UDP_TRACKER_EVENT_STARTED; case TR_ANNOUNCE_EVENT_STARTED: return TAU_ANNOUNCE_EVENT_STARTED;
case TR_ANNOUNCE_EVENT_STOPPED: return UDP_TRACKER_EVENT_STOPPED; case TR_ANNOUNCE_EVENT_STOPPED: return TAU_ANNOUNCE_EVENT_STOPPED;
default: return UDP_TRACKER_EVENT_NONE; default: return TAU_ANNOUNCE_EVENT_NONE;
} }
} }
@ -285,16 +289,16 @@ tau_announce_request_new( const tr_announce_request * in,
{ {
struct evbuffer * buf; struct evbuffer * buf;
struct tau_announce_request * req = tr_new0( struct tau_announce_request, 1 ); struct tau_announce_request * r = tr_new0( struct tau_announce_request, 1 );
req->transaction_id = tau_transaction_new( ); r->transaction_id = tau_transaction_new( );
req->callback = callback; r->callback = callback;
req->user_data = user_data; r->user_data = user_data;
memcpy( req->response.info_hash, in->info_hash, SHA_DIGEST_LENGTH ); memcpy( r->response.info_hash, in->info_hash, SHA_DIGEST_LENGTH );
/* build the announce payload */ /* build the announce payload */
buf = evbuffer_new( ); buf = evbuffer_new( );
evbuffer_add_hton_32( buf, TAU_ACTION_ANNOUNCE ); evbuffer_add_hton_32( buf, TAU_ACTION_ANNOUNCE );
evbuffer_add_hton_32( buf, req->transaction_id ); evbuffer_add_hton_32( buf, r->transaction_id );
evbuffer_add ( buf, in->info_hash, SHA_DIGEST_LENGTH ); evbuffer_add ( buf, in->info_hash, SHA_DIGEST_LENGTH );
evbuffer_add ( buf, in->peer_id, PEER_ID_LEN ); evbuffer_add ( buf, in->peer_id, PEER_ID_LEN );
evbuffer_add_hton_64( buf, in->down ); evbuffer_add_hton_64( buf, in->down );
@ -305,11 +309,11 @@ tau_announce_request_new( const tr_announce_request * in,
evbuffer_add_hton_32( buf, in->key ); evbuffer_add_hton_32( buf, in->key );
evbuffer_add_hton_32( buf, in->numwant ); evbuffer_add_hton_32( buf, in->numwant );
evbuffer_add_hton_16( buf, in->port ); evbuffer_add_hton_16( buf, in->port );
req->payload_len = evbuffer_get_length( buf ); r->payload_len = evbuffer_get_length( buf );
req->payload = tr_memdup( evbuffer_pullup( buf, -1 ), req->payload_len ); r->payload = tr_memdup( evbuffer_pullup( buf, -1 ), r->payload_len );
evbuffer_free( buf ); evbuffer_free( buf );
return req; return r;
} }
static void static void
@ -494,8 +498,7 @@ tau_tracker_upkeep( struct tau_tracker * tracker )
int n; int n;
tr_ptrArray * reqs; tr_ptrArray * reqs;
const time_t now = tr_time( ); const time_t now = tr_time( );
const tr_bool is_connected = tracker->connection_expiration_time > now;
/* FIXME: look for timed-out requests */
/* if the address info is too old, expire it */ /* if the address info is too old, expire it */
if( tracker->addr && ( tracker->addr_expiration_time <= now ) ) { if( tracker->addr && ( tracker->addr_expiration_time <= now ) ) {
@ -504,66 +507,78 @@ tau_tracker_upkeep( struct tau_tracker * tracker )
tracker->addr = NULL; tracker->addr = NULL;
} }
/* if no requests, there's nothing to do */ /* are there any requests pending? */
if( tr_ptrArrayEmpty( &tracker->announces ) && tr_ptrArrayEmpty( &tracker->scrapes ) ) if( tr_ptrArrayEmpty( &tracker->announces ) &&
tr_ptrArrayEmpty( &tracker->scrapes ) )
return; return;
/* can't do anything without an address */ /* if we don't have an address yet, try & get one now. */
if( !tracker->addr ) { if( !tracker->addr && !tracker->is_asking_dns )
if( !tracker->is_asking_dns ) { {
struct evutil_addrinfo hints; struct evutil_addrinfo hints;
memset( &hints, 0, sizeof( hints ) ); memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_flags = EVUTIL_AI_CANONNAME; hints.ai_flags = EVUTIL_AI_CANONNAME;
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP; hints.ai_protocol = IPPROTO_UDP;
tracker->is_asking_dns = TRUE; tracker->is_asking_dns = TRUE;
dbgmsg( tracker->host, "Trying a new DNS lookup" ); dbgmsg( tracker->host, "Trying a new DNS lookup" );
evdns_getaddrinfo( tracker->session->evdns_base, evdns_getaddrinfo( tracker->session->evdns_base,
tracker->host, NULL, &hints, tau_tracker_on_dns, tracker ); tracker->host, NULL, &hints,
} tau_tracker_on_dns, tracker );
return; return;
} }
/* also need a valid connection ID... */ /* also need a valid connection ID... */
if( tracker->connection_expiration_time < now ) { if( !is_connected && !tracker->is_connecting )
if( !tracker->is_connecting ) { {
struct evbuffer * buf = evbuffer_new( ); struct evbuffer * buf = evbuffer_new( );
tracker->is_connecting = TRUE; tracker->is_connecting = TRUE;
tracker->connection_transaction_id = tau_transaction_new( ); tracker->connection_transaction_id = tau_transaction_new( );
dbgmsg( tracker->key, "Trying to connect. Transaction ID is %u", dbgmsg( tracker->key, "Trying to connect. Transaction ID is %u",
tracker->connection_transaction_id ); tracker->connection_transaction_id );
evbuffer_add_hton_64( buf, 0x41727101980LL ); evbuffer_add_hton_64( buf, 0x41727101980LL );
evbuffer_add_hton_32( buf, TAU_ACTION_CONNECT ); evbuffer_add_hton_32( buf, TAU_ACTION_CONNECT );
evbuffer_add_hton_32( buf, tracker->connection_transaction_id ); evbuffer_add_hton_32( buf, tracker->connection_transaction_id );
tau_sendto( tracker->session, tracker->addr, tracker->port, tau_sendto( tracker->session, tracker->addr, tracker->port,
evbuffer_pullup( buf, -1 ), evbuffer_pullup( buf, -1 ),
evbuffer_get_length( buf ) ); evbuffer_get_length( buf ) );
evbuffer_free( buf ); evbuffer_free( buf );
}
return; return;
} }
/* send the announce requests */ /* send the announce requests */
reqs = &tracker->announces; reqs = &tracker->announces;
for( i=0, n=tr_ptrArraySize(reqs); i<n; ++i ) { for( i=0, n=tr_ptrArraySize(reqs); i<n; ++i )
{
struct tau_announce_request * req = tr_ptrArrayNth( reqs, i ); struct tau_announce_request * req = tr_ptrArrayNth( reqs, i );
if( req->sent_at == 0 ) { if( is_connected && !req->sent_at ) {
dbgmsg( tracker->key, "Sending an announce request" ); dbgmsg( tracker->key, "Sending an announce request" );
req->sent_at = now; req->sent_at = now;
tau_tracker_send_request( tracker, req->payload, req->payload_len ); tau_tracker_send_request( tracker, req->payload, req->payload_len );
} }
else if( req->sent_at && ( req->sent_at + TAU_REQUEST_TTL < now ) ) {
tau_announce_request_fail( tracker->session, req, FALSE, TRUE, NULL );
tau_announce_request_free( req );
tr_ptrArrayRemove( reqs, i-- );
}
} }
/* send the scrape requests */ /* send the scrape requests */
reqs = &tracker->scrapes; reqs = &tracker->scrapes;
for( i=0, n=tr_ptrArraySize(reqs); i<n; ++i ) { for( i=0, n=tr_ptrArraySize(reqs); i<n; ++i )
{
struct tau_scrape_request * req = tr_ptrArrayNth( reqs, i ); struct tau_scrape_request * req = tr_ptrArrayNth( reqs, i );
if( req->sent_at == 0 ) { if( is_connected && !req->sent_at ) {
dbgmsg( tracker->key, "Sending a scrape request" ); dbgmsg( tracker->key, "Sending a scrape request" );
req->sent_at = now; req->sent_at = now;
tau_tracker_send_request( tracker, req->payload, req->payload_len ); tau_tracker_send_request( tracker, req->payload, req->payload_len );
} }
else if( req->sent_at && ( req->sent_at + TAU_REQUEST_TTL < now ) ) {
tau_scrape_request_fail( tracker->session, req, FALSE, TRUE, NULL );
tau_scrape_request_free( req );
tr_ptrArrayRemove( reqs, i-- );
}
} }
} }
@ -673,6 +688,16 @@ tau_session_get_tracker( struct tr_announcer_udp * tau, const char * url )
***** *****
****/ ****/
void
tr_tracker_udp_upkeep( tr_session * session )
{
struct tr_announcer_udp * tau = session->announcer_udp;
if( tau != NULL )
tr_ptrArrayForeach( &tau->trackers,
(PtrArrayForeachFunc)tau_tracker_upkeep );
}
tr_bool tr_bool
tau_handle_message( tr_session * session, tau_handle_message( tr_session * session,
const uint8_t * msg, const uint8_t * msg,
@ -711,7 +736,8 @@ tau_handle_message( tr_session * session,
struct tau_tracker * tracker = tr_ptrArrayNth( &tau->trackers, i ); struct tau_tracker * tracker = tr_ptrArrayNth( &tau->trackers, i );
/* is it a connection response? */ /* is it a connection response? */
if( tracker->is_connecting && ( transaction_id == tracker->connection_transaction_id ) ) if( tracker->is_connecting
&& ( transaction_id == tracker->connection_transaction_id ) )
{ {
dbgmsg( tracker->key, "%"PRIu32" matches my connection request!", transaction_id ); dbgmsg( tracker->key, "%"PRIu32" matches my connection request!", transaction_id );
on_tracker_connection_response( tracker, action_id, buf ); on_tracker_connection_response( tracker, action_id, buf );
@ -761,7 +787,9 @@ tr_tracker_udp_announce( tr_session * session,
{ {
struct tr_announcer_udp * tau = announcer_udp_get( session ); struct tr_announcer_udp * tau = announcer_udp_get( session );
struct tau_tracker * tracker = tau_session_get_tracker( tau, request->url ); struct tau_tracker * tracker = tau_session_get_tracker( tau, request->url );
struct tau_announce_request * r = tau_announce_request_new( request, response_func, user_data ); struct tau_announce_request * r = tau_announce_request_new( request,
response_func,
user_data );
tr_ptrArrayAppend( &tracker->announces, r ); tr_ptrArrayAppend( &tracker->announces, r );
tau_tracker_upkeep( tracker ); tau_tracker_upkeep( tracker );
} }
@ -774,7 +802,9 @@ tr_tracker_udp_scrape( tr_session * session,
{ {
struct tr_announcer_udp * tau = announcer_udp_get( session ); struct tr_announcer_udp * tau = announcer_udp_get( session );
struct tau_tracker * tracker = tau_session_get_tracker( tau, request->url ); struct tau_tracker * tracker = tau_session_get_tracker( tau, request->url );
struct tau_scrape_request * r = tau_scrape_request_new( request, response_func, user_data ); struct tau_scrape_request * r = tau_scrape_request_new( request,
response_func,
user_data );
tr_ptrArrayAppend( &tracker->scrapes, r ); tr_ptrArrayAppend( &tracker->scrapes, r );
tau_tracker_upkeep( tracker ); tau_tracker_upkeep( tracker );
} }

View file

@ -64,7 +64,10 @@ enum
UPKEEP_INTERVAL_SECS = 1, UPKEEP_INTERVAL_SECS = 1,
/* this is an upper limit for the frequency of LDS announces */ /* this is an upper limit for the frequency of LDS announces */
LPD_HOUSEKEEPING_INTERVAL_SECS = 5 LPD_HOUSEKEEPING_INTERVAL_SECS = 5,
/* this is how often to call the UDP tracker upkeep */
TAU_UPKEEP_INTERVAL_SECS = 5
}; };
/*** /***
@ -128,7 +131,8 @@ typedef struct tr_announcer
struct event * upkeepTimer; struct event * upkeepTimer;
int slotsAvailable; int slotsAvailable;
int key; int key;
time_t lpdHouseKeepingAt; time_t lpdUpkeepAt;
time_t tauUpkeepAt;
} }
tr_announcer; tr_announcer;
@ -139,7 +143,7 @@ tr_announcerHasBacklog( const struct tr_announcer * announcer )
} }
static inline time_t static inline time_t
calcRescheduleWithJitter( const int minPeriod ) valPlusJitter( const int minPeriod )
{ {
const double jitter = 0.1; const double jitter = 0.1;
@ -158,8 +162,7 @@ tr_announcerInit( tr_session * session )
{ {
tr_announcer * a; tr_announcer * a;
const time_t lpdAt = const time_t lpdAt = valPlusJitter( LPD_HOUSEKEEPING_INTERVAL_SECS / 3 );
calcRescheduleWithJitter( LPD_HOUSEKEEPING_INTERVAL_SECS / 3 );
assert( tr_isSession( session ) ); assert( tr_isSession( session ) );
@ -168,7 +171,7 @@ tr_announcerInit( tr_session * session )
a->key = tr_cryptoRandInt( INT_MAX ); a->key = tr_cryptoRandInt( INT_MAX );
a->session = session; a->session = session;
a->slotsAvailable = MAX_CONCURRENT_TASKS; a->slotsAvailable = MAX_CONCURRENT_TASKS;
a->lpdHouseKeepingAt = lpdAt; a->lpdUpkeepAt = lpdAt;
a->upkeepTimer = evtimer_new( session->event_base, onUpkeepTimer, a ); a->upkeepTimer = evtimer_new( session->event_base, onUpkeepTimer, a );
tr_timerAdd( a->upkeepTimer, UPKEEP_INTERVAL_SECS, 0 ); tr_timerAdd( a->upkeepTimer, UPKEEP_INTERVAL_SECS, 0 );
@ -1414,21 +1417,12 @@ fprintf( stderr, "[%s] announce.c has %d requests ready to send (announce: %d, s
} }
} }
} }
/* Local Peer Discovery */
if( announcer->lpdHouseKeepingAt <= now )
{
tr_lpdAnnounceMore( now, LPD_HOUSEKEEPING_INTERVAL_SECS );
/* reschedule more LDS announces for ( the future + jitter ) */
announcer->lpdHouseKeepingAt =
calcRescheduleWithJitter( LPD_HOUSEKEEPING_INTERVAL_SECS );
}
} }
static void static void
onUpkeepTimer( int foo UNUSED, short bar UNUSED, void * vannouncer ) onUpkeepTimer( int foo UNUSED, short bar UNUSED, void * vannouncer )
{ {
const time_t now = tr_time( );
tr_announcer * announcer = vannouncer; tr_announcer * announcer = vannouncer;
tr_sessionLock( announcer->session ); tr_sessionLock( announcer->session );
@ -1438,6 +1432,19 @@ onUpkeepTimer( int foo UNUSED, short bar UNUSED, void * vannouncer )
/* maybe send out some announcements to trackers */ /* maybe send out some announcements to trackers */
announceMore( announcer ); announceMore( announcer );
/* LPD upkeep */
if( announcer->lpdUpkeepAt <= now ) {
const int seconds = LPD_HOUSEKEEPING_INTERVAL_SECS;
announcer->lpdUpkeepAt = valPlusJitter( seconds );
tr_lpdAnnounceMore( now, seconds );
}
/* TAU upkeep */
if( announcer->tauUpkeepAt <= now ) {
announcer->tauUpkeepAt = now + TAU_UPKEEP_INTERVAL_SECS;
tr_tracker_udp_upkeep( announcer->session );
}
/* set up the next timer */ /* set up the next timer */
tr_timerAdd( announcer->upkeepTimer, UPKEEP_INTERVAL_SECS, 0 ); tr_timerAdd( announcer->upkeepTimer, UPKEEP_INTERVAL_SECS, 0 );

View file

@ -32,6 +32,7 @@ void tr_udpInit( tr_session * );
void tr_udpUninit( tr_session * ); void tr_udpUninit( tr_session * );
void tr_udpSetSocketBuffers(tr_session *); void tr_udpSetSocketBuffers(tr_session *);
tr_bool tau_handle_message( tr_session * session, const uint8_t * msg, size_t msglen ); tr_bool tau_handle_message( tr_session * session,
const uint8_t * msg, size_t msglen );
#endif /* #ifndef TR_UDP_H */ #endif /* #ifndef TR_UDP_H */