mirror of
git://erdgeist.org/opentracker
synced 2025-01-11 15:30:07 +00:00
Added outbound part of sync Proposed format: d4:syncd20:<info_hash>8*N:(xxxxyy)*Nee, therefore had to refactor torrent cleanup now that it will hit all torrents once every OT_POOL_TIMEOUT units.
This commit is contained in:
parent
1d2d3c9d95
commit
b38104b986
@ -200,31 +200,9 @@ static void httpresponse( const int64 s, char *data ) {
|
||||
switch( scan_urlencoded_query( &c, data = c, SCAN_PATH ) ) {
|
||||
case 4: /* sync ? */
|
||||
if( byte_diff( data, 4, "sync") ) HTTPERROR_404;
|
||||
scanon = 1;
|
||||
|
||||
while( scanon ) {
|
||||
switch( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_PARAM ) ) {
|
||||
case -2: scanon = 0; break; /* TERMINATOR */
|
||||
case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */
|
||||
case 9:
|
||||
if(byte_diff(data,9,"info_hash")) {
|
||||
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
||||
continue;
|
||||
}
|
||||
/* ignore this, when we have less than 20 bytes */
|
||||
if( scan_urlencoded_query( &c, data = c, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM;
|
||||
hash = (ot_hash*)data; /* Fall through intended */
|
||||
break;
|
||||
default:
|
||||
scan_urlencoded_query( &c, NULL, SCAN_SEARCHPATH_VALUE );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !hash ) HTTPERROR_400_PARAM;
|
||||
if( !( reply_size = return_sync_for_torrent( hash, &reply ) ) ) HTTPERROR_500;
|
||||
|
||||
if( !( reply_size = return_changeset_for_tracker( &reply ) ) ) HTTPERROR_500;
|
||||
return sendmallocdata( s, reply, reply_size );
|
||||
|
||||
case 5: /* stats ? */
|
||||
if( byte_diff(data,5,"stats")) HTTPERROR_404;
|
||||
scanon = 1;
|
||||
@ -523,11 +501,13 @@ static void handle_read( const int64 clientsocket ) {
|
||||
array_catb( &h->request, static_inbuf, l );
|
||||
|
||||
if( array_failed( &h->request ) )
|
||||
httperror( clientsocket, "500 Server Error", "Request too long.");
|
||||
else if( array_bytes( &h->request ) > 8192 )
|
||||
httperror( clientsocket, "500 request too long", "You sent too much headers");
|
||||
else if( memchr( array_start( &h->request ), '\n', array_length( &h->request, 1 ) ) )
|
||||
httpresponse( clientsocket, array_start( &h->request ) );
|
||||
return httperror( clientsocket, "500 Server Error", "Request too long.");
|
||||
|
||||
if( array_bytes( &h->request ) > 8192 )
|
||||
return httperror( clientsocket, "500 request too long", "You sent too much headers");
|
||||
|
||||
if( memchr( array_start( &h->request ), '\n', array_length( &h->request, 1 ) ) )
|
||||
return httpresponse( clientsocket, array_start( &h->request ) );
|
||||
}
|
||||
|
||||
static void handle_write( const int64 clientsocket ) {
|
||||
@ -701,6 +681,9 @@ static void server_mainloop( ) {
|
||||
taia_now( &next_timeout_check );
|
||||
taia_addsec( &next_timeout_check, &next_timeout_check, OT_CLIENT_TIMEOUT_CHECKINTERVAL);
|
||||
}
|
||||
|
||||
/* See if we need to move our pools */
|
||||
clean_all_torrents();
|
||||
}
|
||||
}
|
||||
|
||||
|
213
trackerlogic.c
213
trackerlogic.c
@ -25,6 +25,10 @@
|
||||
|
||||
/* GLOBAL VARIABLES */
|
||||
static ot_vector all_torrents[256];
|
||||
static ot_vector changeset;
|
||||
size_t changeset_size = 0;
|
||||
time_t last_clean_time = 0;
|
||||
|
||||
#ifdef WANT_CLOSED_TRACKER
|
||||
int g_closedtracker = 1;
|
||||
static ot_torrent* const OT_TORRENT_NOT_ON_WHITELIST = (ot_torrent*)1;
|
||||
@ -158,33 +162,6 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function deallocates all timedouted pools and shifts all other pools
|
||||
it Returns 1 if torrent itself has not seen an announce for more than OT_TORRENT_TIMEOUT time units
|
||||
0 if torrent is not yet timed out
|
||||
Note: We expect NOW as a parameter since calling time() may be expensive
|
||||
*/
|
||||
static int clean_peerlist( time_t time_now, ot_peerlist *peer_list ) {
|
||||
int i, timedout = (int)( time_now - peer_list->base );
|
||||
|
||||
if( !timedout ) return 0;
|
||||
if( timedout > OT_POOLS_COUNT ) timedout = OT_POOLS_COUNT;
|
||||
|
||||
for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i )
|
||||
free( peer_list->peers[i].data);
|
||||
|
||||
memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * (OT_POOLS_COUNT-timedout) );
|
||||
byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout );
|
||||
|
||||
memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout) );
|
||||
byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout );
|
||||
|
||||
if( timedout == OT_POOLS_COUNT )
|
||||
return time_now - peer_list->base > OT_TORRENT_TIMEOUT;
|
||||
|
||||
peer_list->base = time_now;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
|
||||
int exactmatch;
|
||||
ot_torrent *torrent;
|
||||
@ -219,8 +196,7 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer ) {
|
||||
|
||||
byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
|
||||
torrent->peer_list->base = NOW;
|
||||
} else
|
||||
clean_peerlist( NOW, torrent->peer_list );
|
||||
}
|
||||
|
||||
/* Sanitize flags: Whoever claims to have completed download, must be a seeder */
|
||||
if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
|
||||
@ -294,7 +270,9 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply
|
||||
peer_count += torrent->peer_list->peers[index].size;
|
||||
seed_count += torrent->peer_list->seed_count[index];
|
||||
}
|
||||
if( peer_count < amount ) amount = peer_count;
|
||||
|
||||
if( peer_count < amount )
|
||||
amount = peer_count;
|
||||
|
||||
if( is_tcp )
|
||||
r += sprintf( r, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers%zd:", seed_count, peer_count-seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount );
|
||||
@ -348,10 +326,8 @@ size_t return_fullscrape_for_tracker( char **reply ) {
|
||||
int i, k;
|
||||
char *r;
|
||||
|
||||
for( i=0; i<256; ++i ) {
|
||||
ot_vector *torrents_list = &all_torrents[i];
|
||||
torrent_count += torrents_list->size;
|
||||
}
|
||||
for( i=0; i<256; ++i )
|
||||
torrent_count += all_torrents[i].size;
|
||||
|
||||
if( !( r = *reply = malloc( 128*torrent_count ) ) ) return 0;
|
||||
|
||||
@ -380,7 +356,6 @@ size_t return_memstat_for_tracker( char **reply ) {
|
||||
size_t torrent_count = 0, j;
|
||||
int i, k;
|
||||
char *r;
|
||||
time_t time_now = NOW;
|
||||
|
||||
for( i=0; i<256; ++i ) {
|
||||
ot_vector *torrents_list = &all_torrents[i];
|
||||
@ -398,7 +373,6 @@ size_t return_memstat_for_tracker( char **reply ) {
|
||||
ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
|
||||
ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash;
|
||||
r += sprintf( r, "\n%s:\n", to_hex( (ot_byte*)hash ) );
|
||||
clean_peerlist( time_now, peer_list );
|
||||
for( k=0; k<OT_POOLS_COUNT; ++k )
|
||||
r += sprintf( r, "\t%04X %04X\n", ((unsigned int)peer_list->peers[k].size), (unsigned int)peer_list->peers[k].space );
|
||||
}
|
||||
@ -418,7 +392,6 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) {
|
||||
memset( reply, 0, 12);
|
||||
} else {
|
||||
unsigned long *r = (unsigned long*) reply;
|
||||
clean_peerlist( NOW, torrent->peer_list );
|
||||
|
||||
for( i=0; i<OT_POOLS_COUNT; ++i ) {
|
||||
peers += torrent->peer_list->peers[i].size;
|
||||
@ -440,7 +413,6 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply ) {
|
||||
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
||||
|
||||
if( !exactmatch ) return sprintf( r, "d5:filesdee" );
|
||||
clean_peerlist( NOW, torrent->peer_list );
|
||||
|
||||
for( i=0; i<OT_POOLS_COUNT; ++i ) {
|
||||
peers += torrent->peer_list->peers[i].size;
|
||||
@ -453,36 +425,145 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply ) {
|
||||
return r - reply;
|
||||
}
|
||||
|
||||
size_t return_sync_for_torrent( ot_hash *hash, char **reply ) {
|
||||
int exactmatch;
|
||||
size_t peers = 0;
|
||||
char *r;
|
||||
ot_vector *torrents_list = &all_torrents[*hash[0]];
|
||||
ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
|
||||
/* Throw away old changeset */
|
||||
static void release_changeset( void ) {
|
||||
ot_byte **changeset_ptrs = (ot_byte**)(changeset.data);
|
||||
int i;
|
||||
|
||||
if( exactmatch ) {
|
||||
clean_peerlist( NOW, torrent->peer_list );
|
||||
peers = torrent->peer_list->peers[0].size;
|
||||
for( i = 0; i < changeset.size; ++i )
|
||||
free( changeset_ptrs[i] );
|
||||
|
||||
free( changeset_ptrs );
|
||||
byte_zero( &changeset, sizeof( changeset ) );
|
||||
|
||||
changeset_size = 0;
|
||||
}
|
||||
|
||||
static void add_pool_to_changeset( ot_hash *hash, ot_peer *peers, size_t peer_count ) {
|
||||
ot_byte *pool_copy = (ot_byte *)malloc( sizeof( size_t ) + sizeof( ot_hash ) + sizeof( ot_peer ) * peer_count + 13 );
|
||||
size_t r = 0;
|
||||
|
||||
if( !pool_copy )
|
||||
return;
|
||||
|
||||
memmove( pool_copy + sizeof( size_t ), "20:", 3 );
|
||||
memmove( pool_copy + sizeof( size_t ) + 3, hash, sizeof( ot_hash ) );
|
||||
r = sizeof( size_t ) + 3 + sizeof( ot_hash );
|
||||
r += sprintf( (char*)pool_copy + r, "%zd:", sizeof( ot_peer ) * peer_count );
|
||||
memmove( pool_copy + r, peers, sizeof( ot_peer ) * peer_count );
|
||||
r += sizeof( ot_peer ) * peer_count;
|
||||
|
||||
/* Without the length field */
|
||||
*(size_t*)pool_copy = r - sizeof( size_t );
|
||||
|
||||
if( changeset.size + 1 >= changeset.space ) {
|
||||
size_t new_space = changeset.space ? OT_VECTOR_GROW_RATIO * changeset.space : OT_VECTOR_MIN_MEMBERS;
|
||||
ot_byte *new_data = realloc( changeset.data, new_space * sizeof( ot_byte *) );
|
||||
|
||||
if( !new_data )
|
||||
return free( pool_copy );
|
||||
|
||||
changeset.data = new_data;
|
||||
changeset.space = new_space;
|
||||
}
|
||||
|
||||
if( !( r = *reply = malloc( 10 + peers * sizeof( ot_peer ) ) ) ) return 0;
|
||||
((ot_byte**)changeset.data)[changeset.size++] = pool_copy;
|
||||
|
||||
memmove( r, "d4:sync", 7 );
|
||||
r += 7;
|
||||
r += sprintf( r, "%zd:", peers * sizeof( ot_peer ) );
|
||||
if( peers ) {
|
||||
memmove( r, torrent->peer_list->peers[0].data, peers * sizeof( ot_peer ) );
|
||||
r += peers * sizeof( ot_peer );
|
||||
/* Without the length field */
|
||||
changeset_size += r - sizeof( size_t );
|
||||
}
|
||||
|
||||
/* Proposed output format
|
||||
d4:syncd20:<info_hash>8*N:(xxxxyy)*Nee
|
||||
*/
|
||||
size_t return_changeset_for_tracker( char **reply ) {
|
||||
size_t i, r = 8;
|
||||
|
||||
clean_all_torrents();
|
||||
|
||||
*reply = malloc( 8 + changeset_size + 2 );
|
||||
if( !*reply )
|
||||
return 0;
|
||||
|
||||
memmove( *reply, "d4:syncd", 8 );
|
||||
for( i = 0; i < changeset.size; ++i ) {
|
||||
ot_byte *data = ((ot_byte**)changeset.data)[i];
|
||||
memmove( *reply + r, data + sizeof( size_t ), *(size_t*)data );
|
||||
r += *(size_t*)data;
|
||||
}
|
||||
|
||||
(*reply)[r++] = 'e';
|
||||
(*reply)[r++] = 'e';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Clean up all torrents, remove timedout pools and
|
||||
torrents, also prepare new changeset */
|
||||
void clean_all_torrents( void ) {
|
||||
int i, j, k;
|
||||
time_t time_now = NOW;
|
||||
size_t peers_count;
|
||||
|
||||
if( time_now <= last_clean_time )
|
||||
return;
|
||||
last_clean_time = time_now;
|
||||
|
||||
release_changeset();
|
||||
|
||||
for( i=0; i<256; ++i ) {
|
||||
ot_vector *torrents_list = &all_torrents[i];
|
||||
for( j=0; j<torrents_list->size; ++j ) {
|
||||
ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
|
||||
ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash;
|
||||
|
||||
time_t timedout = (int)( time_now - peer_list->base );
|
||||
|
||||
/* Torrent has idled out */
|
||||
if( timedout > OT_TORRENT_TIMEOUT ) {
|
||||
vector_remove_torrent( torrents_list, hash );
|
||||
--j;
|
||||
}
|
||||
|
||||
/* If nothing to be cleaned here, handle next torrent */
|
||||
if( timedout > OT_POOLS_COUNT )
|
||||
continue;
|
||||
|
||||
/* Release vectors that have timed out */
|
||||
for( k = OT_POOLS_COUNT - timedout; k < OT_POOLS_COUNT; ++k )
|
||||
free( peer_list->peers[k].data);
|
||||
|
||||
/* Shift vectors back by the amount of pools that were shifted out */
|
||||
memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) );
|
||||
byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout );
|
||||
|
||||
/* Shift back seed counts as well */
|
||||
memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) );
|
||||
byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout );
|
||||
|
||||
/* Save the block modified within last OT_POOLS_TIMEOUT */
|
||||
if( peer_list->peers[1].size )
|
||||
add_pool_to_changeset( hash, peer_list->peers[1].data, peer_list->peers[1].size );
|
||||
|
||||
peers_count = 0;
|
||||
for( k = 0; k < OT_POOLS_COUNT; ++k )
|
||||
peers_count += peer_list->peers[k].size;
|
||||
|
||||
if( peers_count ) {
|
||||
peer_list->base = time_now;
|
||||
} else {
|
||||
/* When we got here, the last time that torrent
|
||||
has been touched is OT_POOLS_COUNT units before */
|
||||
peer_list->base = time_now - OT_POOLS_COUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
*r++ = 'e';
|
||||
return r - *reply;
|
||||
}
|
||||
|
||||
typedef struct { int val; ot_torrent * torrent; } ot_record;
|
||||
|
||||
/* Fetches stats from tracker */
|
||||
size_t return_stats_for_tracker( char *reply, int mode ) {
|
||||
time_t time_now = NOW;
|
||||
size_t torrent_count = 0, peer_count = 0, seed_count = 0, j;
|
||||
ot_record top5s[5], top5c[5];
|
||||
char *r = reply;
|
||||
@ -498,12 +579,6 @@ size_t return_stats_for_tracker( char *reply, int mode ) {
|
||||
ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
|
||||
size_t local_peers = 0, local_seeds = 0;
|
||||
|
||||
if( clean_peerlist( time_now, peer_list ) ) {
|
||||
ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash;
|
||||
vector_remove_torrent( torrents_list, hash );
|
||||
--j;
|
||||
continue;
|
||||
}
|
||||
for( k=0; k<OT_POOLS_COUNT; ++k ) {
|
||||
local_peers += peer_list->peers[k].size;
|
||||
local_seeds += peer_list->seed_count[k];
|
||||
@ -549,12 +624,6 @@ void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer ) {
|
||||
|
||||
if( !exactmatch ) return;
|
||||
|
||||
/* Maybe this does the job */
|
||||
if( clean_peerlist( NOW, torrent->peer_list ) ) {
|
||||
vector_remove_torrent( torrents_list, hash );
|
||||
return;
|
||||
}
|
||||
|
||||
for( i=0; i<OT_POOLS_COUNT; ++i )
|
||||
switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, i == 0 ) ) {
|
||||
case 0: continue;
|
||||
@ -572,7 +641,9 @@ int init_logic( const char * const serverdir ) {
|
||||
srandom( time(NULL) );
|
||||
|
||||
/* Initialize control structures */
|
||||
byte_zero( all_torrents, sizeof (all_torrents) );
|
||||
byte_zero( all_torrents, sizeof( all_torrents ) );
|
||||
byte_zero( &changeset, sizeof( changeset ) );
|
||||
changeset_size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -591,4 +662,6 @@ void deinit_logic( void ) {
|
||||
}
|
||||
}
|
||||
byte_zero( all_torrents, sizeof (all_torrents));
|
||||
byte_zero( &changeset, sizeof( changeset ) );
|
||||
changeset_size = 0;
|
||||
}
|
||||
|
@ -98,9 +98,10 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply
|
||||
size_t return_fullscrape_for_tracker( char **reply );
|
||||
size_t return_tcp_scrape_for_torrent( ot_hash *hash, char *reply );
|
||||
size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply );
|
||||
size_t return_sync_for_torrent( ot_hash *hash, char **reply );
|
||||
size_t return_stats_for_tracker( char *reply, int mode );
|
||||
size_t return_memstat_for_tracker( char **reply );
|
||||
size_t return_changeset_for_tracker( char **reply );
|
||||
void clean_all_torrents( void );
|
||||
void remove_peer_from_torrent( ot_hash *hash, ot_peer *peer );
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user