From 2afc4893bf802700a1decfff57673cefc861c7e7 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Wed, 3 Apr 2024 22:25:30 +0200 Subject: Prepare opentracker for dual stack capabilities --- ot_clean.c | 63 +++++++++++--------- ot_fullscrape.c | 24 ++++---- ot_http.c | 18 ++---- ot_livesync.c | 12 ++-- ot_mutex.h | 2 +- ot_stats.c | 36 ++++++------ ot_udp.c | 26 +++++---- ot_vector.c | 83 ++++++++++++++++----------- ot_vector.h | 10 ++-- trackerlogic.c | 174 +++++++++++++++++++++++++++++++++++--------------------- trackerlogic.h | 54 +++++++++++------- 11 files changed, 293 insertions(+), 209 deletions(-) diff --git a/ot_clean.c b/ot_clean.c index 139bedb..3b494f4 100644 --- a/ot_clean.c +++ b/ot_clean.c @@ -20,36 +20,36 @@ #include "ot_accesslist.h" /* Returns amount of removed peers */ -static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) { - ot_peer *last_peer = peers + peer_count, *insert_point; - time_t timediff; +static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders ) { + ot_peer *last_peer = peers + peer_count * peer_size, *insert_point; /* Two scan modes: unless there is one peer removed, just increase ot_peertime */ while( peers < last_peer ) { - if( ( timediff = timedout + OT_PEERTIME( peers ) ) >= OT_PEER_TIMEOUT ) + time_t timediff = timedout + OT_PEERTIME( peers, peer_size ); + if( timediff >= OT_PEER_TIMEOUT ) break; - OT_PEERTIME( peers++ ) = timediff; + OT_PEERTIME( peers, peer_size ) = timediff; + peers += peer_size; } - /* If we at least remove one peer, we have to copy */ - insert_point = peers; - while( peers < last_peer ) - if( ( timediff = timedout + OT_PEERTIME( peers ) ) < OT_PEER_TIMEOUT ) { - OT_PEERTIME( peers ) = timediff; - memcpy( insert_point++, peers++, sizeof(ot_peer)); + /* If we at least remove one peer, we have to copy */ + for( insert_point = peers; peers < last_peer; peers += peer_size ) { + time_t timediff = timedout + OT_PEERTIME( peers, peer_size ); + + if( timediff < OT_PEER_TIMEOUT ) { + OT_PEERTIME( peers, peer_size ) = timediff; + memcpy( insert_point, peers, peer_size); + insert_point += peer_size; } else - if( OT_PEERFLAG( peers++ ) & PEER_FLAG_SEEDING ) + if( OT_PEERFLAG_D( peers, peer_size ) & PEER_FLAG_SEEDING ) (*removed_seeders)++; + } return peers - insert_point; } -/* Clean a single torrent - return 1 if torrent timed out -*/ -int clean_single_torrent( ot_torrent *torrent ) { - ot_peerlist *peer_list = torrent->peer_list; - ot_vector *bucket_list = &peer_list->peers; +int clean_single_peer_list( ot_peerlist *peer_list, size_t peer_size ) { + ot_vector *peer_vector = &peer_list->peers; time_t timedout = (time_t)( g_now_minutes - peer_list->base ); int num_buckets = 1, removed_seeders = 0; @@ -69,24 +69,26 @@ int clean_single_torrent( ot_torrent *torrent ) { } if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { - num_buckets = bucket_list->size; - bucket_list = (ot_vector *)bucket_list->data; + num_buckets = peer_vector->size; + peer_vector = (ot_vector *)peer_vector->data; } while( num_buckets-- ) { - size_t removed_peers = clean_single_bucket( bucket_list->data, bucket_list->size, timedout, &removed_seeders ); + size_t removed_peers = clean_single_bucket( peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders ); peer_list->peer_count -= removed_peers; - bucket_list->size -= removed_peers; - if( bucket_list->size < removed_peers ) - vector_fixup_peers( bucket_list ); - ++bucket_list; + peer_vector->size -= removed_peers; + if( removed_peers ) + vector_fixup_peers( peer_vector, peer_size ); + + /* Skip to next bucket, a vector containing peers */ + ++peer_vector; } peer_list->seed_count -= removed_seeders; - /* See, if we need to convert a torrent from simple vector to bucket list */ + /* See if we need to convert a torrent from simple vector to bucket list */ if( ( peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT ) || OT_PEERLIST_HASBUCKETS(peer_list) ) - vector_redistribute_buckets( peer_list ); + vector_redistribute_buckets( peer_list, peer_size ); if( peer_list->peer_count ) peer_list->base = g_now_minutes; @@ -96,7 +98,14 @@ int clean_single_torrent( ot_torrent *torrent ) { peer_list->base = g_now_minutes - OT_PEER_TIMEOUT; } return 0; +} +/* Clean a single torrent + return 1 if torrent timed out +*/ +int clean_single_torrent( ot_torrent *torrent ) { + return clean_single_peer_list( torrent->peer_list6, OT_PEER_SIZE6) * + clean_single_peer_list( torrent->peer_list4, OT_PEER_SIZE4); } /* Clean up all peers in current bucket, remove timedout pools and diff --git a/ot_fullscrape.c b/ot_fullscrape.c index 5d115dc..d7d3518 100644 --- a/ot_fullscrape.c +++ b/ot_fullscrape.c @@ -82,7 +82,11 @@ void fullscrape_deliver( int64 sock, ot_tasktype tasktype ) { mutex_workqueue_pushtask( sock, tasktype ); } -static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_peerlist *peer_list, ot_hash *hash ) { +static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_torrent *torrent, ot_hash *hash ) { + size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; + size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; + size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count; + switch( mode & TASK_TASK_MASK ) { case TASK_FULLSCRAPE: default: @@ -90,30 +94,30 @@ static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_peerlist *peer *r++='2'; *r++='0'; *r++=':'; memcpy( r, hash, sizeof(ot_hash) ); r += sizeof(ot_hash); /* push rest of the scrape string */ - r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count ); + r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, down_count, peer_count-seed_count ); break; case TASK_FULLSCRAPE_TPB_ASCII: to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); - r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count ); + r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count ); break; case TASK_FULLSCRAPE_TPB_ASCII_PLUS: to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); - r += sprintf( r, ":%zd:%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count, peer_list->down_count ); + r += sprintf( r, ":%zd:%zd:%zd\n", seed_count, peer_count-seed_count, down_count ); break; case TASK_FULLSCRAPE_TPB_BINARY: memcpy( r, *hash, sizeof(ot_hash) ); r += sizeof(ot_hash); - *(uint32_t*)(r+0) = htonl( (uint32_t) peer_list->seed_count ); - *(uint32_t*)(r+4) = htonl( (uint32_t)( peer_list->peer_count-peer_list->seed_count) ); + *(uint32_t*)(r+0) = htonl( (uint32_t) seed_count ); + *(uint32_t*)(r+4) = htonl( (uint32_t)( peer_count-seed_count) ); r+=8; break; case TASK_FULLSCRAPE_TPB_URLENCODED: r += fmt_urlencoded( r, (char *)*hash, 20 ); - r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count ); + r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count ); break; case TASK_FULLSCRAPE_TRACKERSTATE: to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); - r += sprintf( r, ":%zd:%zd\n", peer_list->base, peer_list->down_count ); + r += sprintf( r, ":%zd:%zd\n", torrent->peer_list6->base, down_count ); break; } return r; @@ -145,7 +149,7 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas /* For each torrent in this bucket.. */ for( i=0; isize; ++i ) { - r = fullscrape_write_one( mode, r, torrents[i].peer_list, &torrents[i].hash ); + r = fullscrape_write_one( mode, r, torrents+i, &torrents[i].hash ); if( r > re) { /* Allocate a fresh output buffer at the end of our buffers list */ @@ -210,7 +214,7 @@ static void fullscrape_make_gzip( int *iovec_entries, struct iovec **iovector, o /* For each torrent in this bucket.. */ for( i=0; isize; ++i ) { char compress_buffer[OT_SCRAPE_MAXENTRYLEN]; - r = fullscrape_write_one( mode, compress_buffer, torrents[i].peer_list, &torrents[i].hash ); + r = fullscrape_write_one( mode, compress_buffer, torrents+i, &torrents[i].hash ); strm.next_in = (uint8_t*)compress_buffer; strm.avail_in = r - compress_buffer; zres = deflate( &strm, Z_NO_FLUSH ); diff --git a/ot_http.c b/ot_http.c index 88b4261..374d6d8 100644 --- a/ot_http.c +++ b/ot_http.c @@ -421,26 +421,18 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws, ot_ip6 proxied_ip; char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" ); if( fwd && scan_ip6( fwd, proxied_ip ) ) { - /* If proxy reports an ipv6 address but we can only handle v4 (or vice versa), bail out */ -#ifndef WANT_V6 - if( !ip6_isv4mapped(proxied_ip) ) -#else - if( ip6_isv4mapped(proxied_ip) ) -#endif - HTTPERROR_400_PARAM; - - OT_SETIP( &ws->peer, proxied_ip ); + OT_SETIP( ws->peer, proxied_ip ); } else - OT_SETIP( &ws->peer, cookie->ip ); + OT_SETIP( ws->peer, cookie->ip ); } else #endif - OT_SETIP( &ws->peer, cookie->ip ); + OT_SETIP( ws->peer, cookie->ip ); ws->peer_id = NULL; ws->hash = NULL; - OT_SETPORT( &ws->peer, &port ); - OT_PEERFLAG( &ws->peer ) = 0; + OT_SETPORT( ws->peer, &port ); + OT_PEERFLAG( ws->peer ) = 0; numwant = 50; scanon = 1; diff --git a/ot_livesync.c b/ot_livesync.c index 75a5f9f..b87fa6d 100644 --- a/ot_livesync.c +++ b/ot_livesync.c @@ -127,13 +127,13 @@ static void livesync_handle_peersync( struct ot_workstruct *ws ) { /* Now basic sanity checks have been done on the live sync packet We might add more testing and logging. */ - while( off + (ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ) <= ws->request_size ) { - memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), sizeof( ot_peer ) ); + while( off + (ssize_t)sizeof( ot_hash ) + OT_PEER_SIZE4 <= ws->request_size ) { + memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), OT_PEER_SIZE4 ); ws->hash = (ot_hash*)(ws->request + off); if( !g_opentracker_running ) return; - if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_STOPPED ) + if( OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED ) remove_peer_from_torrent( FLAG_MCA, ws ); else add_peer_to_torrent_and_return_peers( FLAG_MCA, ws, /* amount = */ 0 ); @@ -143,7 +143,7 @@ static void livesync_handle_peersync( struct ot_workstruct *ws ) { stats_issue_event(EVENT_SYNC, 0, (ws->request_size - sizeof( g_tracker_id ) - sizeof( uint32_t ) ) / - ((ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ))); + ((ssize_t)sizeof( ot_hash ) + OT_PEER_SIZE4)); } /* Tickle the live sync module from time to time, so no events get @@ -164,9 +164,9 @@ void livesync_tell( struct ot_workstruct *ws ) { pthread_mutex_lock(&g_outbuf_mutex); memcpy( g_outbuf + g_outbuf_data, ws->hash, sizeof(ot_hash) ); - memcpy( g_outbuf + g_outbuf_data + sizeof(ot_hash), &ws->peer, sizeof(ot_peer) ); + memcpy( g_outbuf + g_outbuf_data + sizeof(ot_hash), &ws->peer, OT_PEER_SIZE4 ); - g_outbuf_data += sizeof(ot_hash) + sizeof(ot_peer); + g_outbuf_data += sizeof(ot_hash) + OT_PEER_SIZE4; if( g_outbuf_data >= LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS ) livesync_issue_peersync(); diff --git a/ot_mutex.h b/ot_mutex.h index 93c1ecf..8d64cf6 100644 --- a/ot_mutex.h +++ b/ot_mutex.h @@ -43,7 +43,7 @@ typedef enum { TASK_STATS_EVERYTHING = 0x0106, TASK_STATS_FULLLOG = 0x0107, TASK_STATS_WOODPECKERS = 0x0108, - + TASK_FULLSCRAPE = 0x0200, /* Default mode */ TASK_FULLSCRAPE_TPB_BINARY = 0x0201, TASK_FULLSCRAPE_TPB_ASCII = 0x0202, diff --git a/ot_stats.c b/ot_stats.c index 7d2749f..b3cc48a 100644 --- a/ot_stats.c +++ b/ot_stats.c @@ -73,13 +73,13 @@ static time_t ot_start_time; #define __LDR(P,D) ((__BYTE((P),(D))>>__SHFT((D)))&__MSK) #define __STR(P,D,V) __BYTE((P),(D))=(__BYTE((P),(D))&~(__MSK<<__SHFT((D))))|((V)<<__SHFT((D))) -#ifdef WANT_V6 -#define STATS_NETWORK_NODE_MAXDEPTH (68-STATS_NETWORK_NODE_BITWIDTH) -#define STATS_NETWORK_NODE_LIMIT (48-STATS_NETWORK_NODE_BITWIDTH) -#else +//#ifdef WANT_V6 +//#define STATS_NETWORK_NODE_MAXDEPTH (68-STATS_NETWORK_NODE_BITWIDTH) +//#define STATS_NETWORK_NODE_LIMIT (48-STATS_NETWORK_NODE_BITWIDTH) +//#else #define STATS_NETWORK_NODE_MAXDEPTH (28-STATS_NETWORK_NODE_BITWIDTH) #define STATS_NETWORK_NODE_LIMIT (24-STATS_NETWORK_NODE_BITWIDTH) -#endif +//#endif typedef union stats_network_node stats_network_node; union stats_network_node { @@ -219,12 +219,12 @@ static size_t stats_slash24s_txt( char *reply, size_t amount ) { stats_network_node *slash24s_network_counters_root = NULL; char *r=reply; int bucket; - size_t i; + size_t i, peer_size = OT_PEER_SIZE4; for( bucket=0; bucketsize; ++i ) { - ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list; + ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list4; ot_vector *bucket_list = &peer_list->peers; int num_buckets = 1; @@ -236,9 +236,11 @@ static size_t stats_slash24s_txt( char *reply, size_t amount ) { while( num_buckets-- ) { ot_peer *peers = (ot_peer*)bucket_list->data; size_t numpeers = bucket_list->size; - while( numpeers-- ) - if( stat_increase_network_count( &slash24s_network_counters_root, 0, (uintptr_t)(peers++) ) ) + while( numpeers-- ) { + if( stat_increase_network_count( &slash24s_network_counters_root, 0, (uintptr_t)(peers) ) ) goto bailout_unlock; + peers += peer_size; + } ++bucket_list; } } @@ -285,8 +287,8 @@ typedef struct { static int torrent_statter( ot_torrent *torrent, uintptr_t data ) { torrent_stats *stats = (torrent_stats*)data; stats->torrent_count++; - stats->peer_count += torrent->peer_list->peer_count; - stats->seed_count += torrent->peer_list->seed_count; + stats->peer_count += torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; + stats->seed_count += torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; return 0; } @@ -312,21 +314,23 @@ size_t stats_top_txt( char * reply, int amount ) { ot_vector *torrents_list = mutex_bucket_lock( bucket ); for( j=0; jsize; ++j ) { ot_torrent *torrent = (ot_torrent*)(torrents_list->data) + j; + size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; + size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; idx = amount - 1; - while( (idx >= 0) && ( torrent->peer_list->peer_count > top100c[idx].val ) ) + while( (idx >= 0) && ( peer_count > top100c[idx].val ) ) --idx; if ( idx++ != amount - 1 ) { memmove( top100c + idx + 1, top100c + idx, ( amount - 1 - idx ) * sizeof( ot_record ) ); memcpy( &top100c[idx].hash, &torrent->hash, sizeof(ot_hash)); - top100c[idx].val = torrent->peer_list->peer_count; + top100c[idx].val = peer_count; } idx = amount - 1; - while( (idx >= 0) && ( torrent->peer_list->seed_count > top100s[idx].val ) ) + while( (idx >= 0) && ( seed_count > top100s[idx].val ) ) --idx; if ( idx++ != amount - 1 ) { memmove( top100s + idx + 1, top100s + idx, ( amount - 1 - idx ) * sizeof( ot_record ) ); memcpy( &top100s[idx].hash, &torrent->hash, sizeof(ot_hash)); - top100s[idx].val = torrent->peer_list->seed_count; + top100s[idx].val = seed_count; } } mutex_bucket_unlock( bucket, 0 ); @@ -718,7 +722,7 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event break; case EVENT_SYNC: ot_overall_sync_count+=event_data; - break; + break; case EVENT_BUCKET_LOCKED: ot_overall_stall_count++; break; diff --git a/ot_udp.c b/ot_udp.c index 8309660..c32a7e2 100644 --- a/ot_udp.c +++ b/ot_udp.c @@ -13,6 +13,7 @@ /* Libowfat */ #include "socket.h" #include "io.h" +#include "ip6.h" /* Opentracker */ #include "trackerlogic.h" @@ -73,7 +74,7 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) { ot_ip6 remoteip; uint32_t *inpacket = (uint32_t*)ws->inbuf; uint32_t *outpacket = (uint32_t*)ws->outbuf; - uint32_t numwant, left, event, scopeid; + uint32_t left, event, scopeid; uint32_t connid[2]; uint32_t action; uint16_t port, remoteport; @@ -141,34 +142,35 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) { /* We do only want to know, if it is zero */ left = inpacket[64/4] | inpacket[68/4]; - /* Limit amount of peers to OT_MAX_PEERS_UDP */ - numwant = ntohl( inpacket[92/4] ); - if (numwant > OT_MAX_PEERS_UDP) numwant = OT_MAX_PEERS_UDP; - event = ntohl( inpacket[80/4] ); port = *(uint16_t*)( ((char*)inpacket) + 96 ); ws->hash = (ot_hash*)( ((char*)inpacket) + 16 ); - OT_SETIP( &ws->peer, remoteip ); - OT_SETPORT( &ws->peer, &port ); - OT_PEERFLAG( &ws->peer ) = 0; + OT_SETIP( ws->peer, remoteip ); + OT_SETPORT( ws->peer, &port ); + OT_PEERFLAG( ws->peer ) = 0; switch( event ) { - case 1: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; break; - case 3: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; break; + case 1: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED; break; + case 3: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED; break; default: break; } if( !left ) - OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_SEEDING; + OT_PEERFLAG( ws->peer ) |= PEER_FLAG_SEEDING; outpacket[0] = htonl( 1 ); /* announce action */ outpacket[1] = inpacket[12/4]; - if( OT_PEERFLAG( &ws->peer ) & PEER_FLAG_STOPPED ) { /* Peer is gone. */ + if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_STOPPED ) { /* Peer is gone. */ ws->reply = ws->outbuf; ws->reply_size = remove_peer_from_torrent( FLAG_UDP, ws ); } else { + /* Limit amount of peers to OT_MAX_PEERS_UDP */ + uint32_t numwant = ntohl( inpacket[92/4] ); + size_t max_peers = ip6_isv4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6; + if (numwant > max_peers) numwant = max_peers; + ws->reply = ws->outbuf + 8; ws->reply_size = 8 + add_peer_to_torrent_and_return_peers( FLAG_UDP, ws, numwant ); } diff --git a/ot_vector.c b/ot_vector.c index 2a632b2..c38f05d 100644 --- a/ot_vector.c +++ b/ot_vector.c @@ -17,8 +17,11 @@ #include "uint32.h" #include "uint16.h" -static int vector_compare_peer(const void *peer1, const void *peer2 ) { - return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE ); +static int vector_compare_peer6(const void *peer1, const void *peer2 ) { + return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE6 ); +} +static int vector_compare_peer4(const void *peer1, const void *peer2 ) { + return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE4 ); } /* This function gives us a binary search that returns a pointer, even if @@ -47,10 +50,10 @@ void *binary_search( const void * const key, const void * base, const size_t mem return (void*)base; } -static uint8_t vector_hash_peer( ot_peer *peer, int bucket_count ) { - unsigned int hash = 5381, i = OT_PEER_COMPARE_SIZE; +static uint8_t vector_hash_peer( ot_peer const *peer, size_t compare_size, int bucket_count ) { + unsigned int hash = 5381; uint8_t *p = (uint8_t*)peer; - while( i-- ) hash += (hash<<5) + *(p++); + while( compare_size-- ) hash += (hash<<5) + *(p++); return hash % bucket_count; } @@ -82,27 +85,37 @@ void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, s return match; } -ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ) { - ot_peer *match; +ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch ) { + ot_peer *match, *end; + const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); + size_t match_to_end; /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ if( vector->space < vector->size ) - vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size ); - match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, exactmatch ); + vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size ); + match = binary_search( peer, vector->data, vector->size, peer_size, compare_size, exactmatch ); if( *exactmatch ) return match; + /* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */ + end = (ot_peer*)vector->data + vector->size * peer_size; + match_to_end = end - match; + if( vector->size + 1 > vector->space ) { + ptrdiff_t offset = match - (ot_peer*)vector->data; size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; - ot_peer *new_data = realloc( vector->data, new_space * sizeof(ot_peer) ); + ot_peer *new_data = realloc( vector->data, new_space * peer_size ); + if( !new_data ) return NULL; /* Adjust pointer if it moved by realloc */ - match = new_data + (match - (ot_peer*)vector->data); + match = new_data + offset; vector->data = new_data; vector->space = new_space; } - memmove( match + 1, match, sizeof(ot_peer) * ( ((ot_peer*)vector->data) + vector->size - match ) ); + + /* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */ + memmove( match + peer_size, match, match_to_end); vector->size++; return match; @@ -113,26 +126,27 @@ ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exac 1 if a non-seeding peer was removed 2 if a seeding peer was removed */ -int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { - int exactmatch; - ot_peer *match, *end; +int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size) { + int exactmatch, was_seeder; + ot_peer *match, *end; + size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); if( !vector->size ) return 0; /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ if( vector->space < vector->size ) - vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size ); + vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size ); - end = ((ot_peer*)vector->data) + vector->size; - match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch ); + end = ((ot_peer*)vector->data) + peer_size * vector->size; + match = (ot_peer*)binary_search( peer, vector->data, vector->size, peer_size, compare_size, &exactmatch ); if( !exactmatch ) return 0; - exactmatch = ( OT_PEERFLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; - memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); + was_seeder = ( OT_PEERFLAG_D( match, peer_size ) & PEER_FLAG_SEEDING ) ? 2 : 1; + memmove( match, match + peer_size, end - match - peer_size ); vector->size--; - vector_fixup_peers( vector ); - return exactmatch; + vector_fixup_peers( vector, peer_size ); + return was_seeder; } void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { @@ -142,7 +156,8 @@ void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { /* If this is being called after a unsuccessful malloc() for peer_list in add_peer_to_torrent, match->peer_list actually might be NULL */ - if( match->peer_list) free_peerlist( match->peer_list ); + if( match->peer_list6) free_peerlist( match->peer_list6 ); + if( match->peer_list4) free_peerlist( match->peer_list4 ); memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) ); if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) { @@ -158,9 +173,11 @@ void vector_clean_list( ot_vector * vector, int num_buckets ) { return; } -void vector_redistribute_buckets( ot_peerlist * peer_list ) { +void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size ) { int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1; ot_vector * bucket_list_new, * bucket_list_old = &peer_list->peers; + int (*sort_func)(const void *, const void *) = + peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4; if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { num_buckets_old = peer_list->peers.size; @@ -198,33 +215,33 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) { /* preallocate vectors to hold all peers */ for( bucket=0; bucket 1 ) - bucket_dest += vector_hash_peer(peers_old, num_buckets_new); + bucket_dest += vector_hash_peer(peers_old, OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size), num_buckets_new); if( bucket_dest->size + 1 > bucket_dest->space ) { - void * tmp = realloc( bucket_dest->data, sizeof(ot_peer) * OT_VECTOR_GROW_RATIO * bucket_dest->space ); + void * tmp = realloc( bucket_dest->data, peer_size * OT_VECTOR_GROW_RATIO * bucket_dest->space ); if( !tmp ) return vector_clean_list( bucket_list_new, num_buckets_new ); bucket_dest->data = tmp; bucket_dest->space *= OT_VECTOR_GROW_RATIO; } - peers_new = (ot_peer*)bucket_dest->data; - memcpy(peers_new + bucket_dest->size++, peers_old++, sizeof(ot_peer)); + memcpy((ot_peer*)bucket_dest->data + peer_size * bucket_dest->size++, peers_old, peer_size); + peers_old += peer_size; } } /* Now sort each bucket to later allow bsearch */ for( bucket=0; bucketsize ) { @@ -260,7 +277,7 @@ void vector_fixup_peers( ot_vector * vector ) { need_fix++; } if( need_fix ) - vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); + vector->data = realloc( vector->data, vector->space * peer_size ); } const char *g_version_vector_c = "$Source$: $Revision$\n"; diff --git a/ot_vector.h b/ot_vector.h index f7f87aa..f60c291 100644 --- a/ot_vector.h +++ b/ot_vector.h @@ -24,11 +24,13 @@ typedef struct { void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, size_t compare_size, int *exactmatch ); void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ); -ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ); +ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch ); -int vector_remove_peer( ot_vector *vector, ot_peer *peer ); +int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size); void vector_remove_torrent( ot_vector *vector, ot_torrent *match ); -void vector_redistribute_buckets( ot_peerlist * peer_list ); -void vector_fixup_peers( ot_vector * vector ); + +/* For ot_clean.c */ +void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size ); +void vector_fixup_peers( ot_vector * vector, size_t peer_size ); #endif diff --git a/trackerlogic.c b/trackerlogic.c index 47e0085..9d564c1 100644 --- a/trackerlogic.c +++ b/trackerlogic.c @@ -16,6 +16,7 @@ #include "byte.h" #include "io.h" #include "iob.h" +#include "ip6.h" #include "array.h" /* Opentracker */ @@ -57,25 +58,33 @@ void add_torrent_from_saved_state( ot_hash hash, ot_time base, size_t down_count return mutex_bucket_unlock_by_hash( hash, 0 ); /* Create a new torrent entry, then */ + byte_zero( torrent, sizeof( ot_torrent ) ); memcpy( torrent->hash, hash, sizeof(ot_hash) ); - if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { + if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) || + !( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) { vector_remove_torrent( torrents_list, torrent ); return mutex_bucket_unlock_by_hash( hash, 0 ); } - byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); - torrent->peer_list->base = base; - torrent->peer_list->down_count = down_count; + byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) ); + byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) ); + torrent->peer_list6->base = base; + torrent->peer_list4->base = base; + torrent->peer_list6->down_count = down_count; + torrent->peer_list4->down_count = down_count; return mutex_bucket_unlock_by_hash( hash, 1 ); } size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) { - int exactmatch, delta_torrentcount = 0; - ot_torrent *torrent; - ot_peer *peer_dest; - ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); + int exactmatch, delta_torrentcount = 0; + ot_torrent *torrent; + ot_peer *peer_dest; + ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); + ot_peerlist *peer_list; + size_t peer_size; /* initialized in next line */ + ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size); if( !accesslist_hashisvalid( *ws->hash ) ) { mutex_bucket_unlock_by_hash( *ws->hash, 0 ); @@ -95,82 +104,88 @@ size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstr if( !exactmatch ) { /* Create a new torrent entry, then */ + byte_zero( torrent, sizeof(ot_torrent)); memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) ); - if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { + if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) || + !( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) { vector_remove_torrent( torrents_list, torrent ); mutex_bucket_unlock_by_hash( *ws->hash, 0 ); return 0; } - byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); + byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) ); + byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) ); delta_torrentcount = 1; } else clean_single_torrent( torrent ); - torrent->peer_list->base = g_now_minutes; + torrent->peer_list6->base = g_now_minutes; + torrent->peer_list4->base = g_now_minutes; + + peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; /* Check for peer in torrent */ - peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), &ws->peer, &exactmatch ); + peer_dest = vector_find_or_insert_peer( &(peer_list->peers), peer_src, peer_size, &exactmatch ); if( !peer_dest ) { mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); return 0; } /* Tell peer that it's fresh */ - OT_PEERTIME( &ws->peer ) = 0; + OT_PEERTIME( ws->peer, OT_PEER_SIZE6 ) = 0; /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ - if( ( OT_PEERFLAG( &ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) - OT_PEERFLAG( &ws->peer ) ^= PEER_FLAG_COMPLETED; + if( ( OT_PEERFLAG( ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) + OT_PEERFLAG( ws->peer ) ^= PEER_FLAG_COMPLETED; /* If we hadn't had a match create peer there */ if( !exactmatch ) { #ifdef WANT_SYNC_LIVE if( proto == FLAG_MCA ) - OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_FROM_SYNC; + OT_PEERFLAG( ws->peer ) |= PEER_FLAG_FROM_SYNC; else livesync_tell( ws ); #endif - torrent->peer_list->peer_count++; - if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) { - torrent->peer_list->down_count++; + peer_list->peer_count++; + if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_COMPLETED ) { + peer_list->down_count++; stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws ); } - if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) - torrent->peer_list->seed_count++; + if( OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) + peer_list->seed_count++; } else { - stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest ) ); + stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest, peer_size ) ); #ifdef WANT_SPOT_WOODPECKER - if( ( OT_PEERTIME(peer_dest) > 0 ) && ( OT_PEERTIME(peer_dest) < 20 ) ) + if( ( OT_PEERTIME(peer_dest, peer_size) > 0 ) && ( OT_PEERTIME(peer_dest, peer_size) < 20 ) ) stats_issue_event( EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer ); #endif #ifdef WANT_SYNC_LIVE /* Won't live sync peers that come back too fast. Only exception: fresh "completed" reports */ if( proto != FLAG_MCA ) { - if( OT_PEERTIME( peer_dest ) > OT_CLIENT_SYNC_RENEW_BOUNDARY || - ( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) ) + if( OT_PEERTIME( peer_dest, peer_size ) > OT_CLIENT_SYNC_RENEW_BOUNDARY || + ( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) ) livesync_tell( ws ); } #endif - if( (OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) ) - torrent->peer_list->seed_count--; - if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) ) - torrent->peer_list->seed_count++; - if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) { - torrent->peer_list->down_count++; + if( (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) ) + peer_list->seed_count--; + if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) ) + peer_list->seed_count++; + if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) { + peer_list->down_count++; stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws ); } - if( OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) - OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; + if( OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) + OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED; } - memcpy( peer_dest, &ws->peer, sizeof(ot_peer) ); + memcpy( peer_dest, peer_src, peer_size ); #ifdef WANT_SYNC if( proto == FLAG_MCA ) { mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); @@ -183,10 +198,11 @@ size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstr return ws->reply_size; } -static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) { +static size_t return_peers_all( ot_peerlist *peer_list, size_t peer_size, char *reply ) { unsigned int bucket, num_buckets = 1; ot_vector * bucket_list = &peer_list->peers; - size_t result = OT_PEER_COMPARE_SIZE * peer_list->peer_count; + size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); + size_t result = compare_size * peer_list->peer_count; char * r_end = reply + result; if( OT_PEERLIST_HASBUCKETS(peer_list) ) { @@ -195,28 +211,30 @@ static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) { } for( bucket = 0; bucketpeers; unsigned int shifted_pc = peer_list->peer_count; unsigned int shifted_step = 0; unsigned int shift = 0; - size_t result = OT_PEER_COMPARE_SIZE * amount; + size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); + size_t result = compare_size * amount; char * r_end = reply + result; if( OT_PEERLIST_HASBUCKETS(peer_list) ) { @@ -235,7 +253,7 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count; while( amount-- ) { - ot_peer * peer; + ot_peer *peer; /* This is the aliased, non shifted range, next value may fall into */ unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) - @@ -246,13 +264,13 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee bucket_offset -= bucket_list[bucket_index].size; bucket_index = ( bucket_index + 1 ) % num_buckets; } - peer = ((ot_peer*)bucket_list[bucket_index].data) + bucket_offset; - if( OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) { - r_end-=OT_PEER_COMPARE_SIZE; - memcpy(r_end,peer,OT_PEER_COMPARE_SIZE); + peer = bucket_list[bucket_index].data + peer_size * bucket_offset; + if( OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING ) { + r_end -= compare_size; + memcpy(r_end, peer, compare_size); } else { - memcpy(reply,peer,OT_PEER_COMPARE_SIZE); - reply+=OT_PEER_COMPARE_SIZE; + memcpy(reply, peer, compare_size); + reply += compare_size; } } return result; @@ -267,15 +285,17 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee * Does not yet check not to return self */ size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) { - ot_peerlist *peer_list = torrent->peer_list; + size_t peer_size = peer_size_from_peer6(&ws->peer); + ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; char *r = reply; + size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); if( amount > peer_list->peer_count ) amount = peer_list->peer_count; if( proto == FLAG_TCP ) { int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; - r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie" PEERS_BENCODED "%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, OT_PEER_COMPARE_SIZE*amount ); + r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4, compare_size * amount ); } else { *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); *(uint32_t*)(r+4) = htonl( peer_list->peer_count - peer_list->seed_count ); @@ -285,9 +305,9 @@ size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, if( amount ) { if( amount == peer_list->peer_count ) - r += return_peers_all( peer_list, r ); + r += return_peers_all( peer_list, peer_size, r ); else - r += return_peers_selection( ws, peer_list, amount, r ); + r += return_peers_selection( ws, peer_list, peer_size, amount, r ); } if( proto == FLAG_TCP ) @@ -312,9 +332,10 @@ size_t return_udp_scrape_for_torrent( ot_hash hash, char *reply ) { memset( reply, 0, 12); delta_torrentcount = -1; } else { - r[0] = htonl( torrent->peer_list->seed_count ); - r[1] = htonl( torrent->peer_list->down_count ); - r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); + r[0] = htonl( torrent->peer_list6->seed_count + torrent->peer_list4->seed_count ); + r[1] = htonl( torrent->peer_list6->down_count + torrent->peer_list4->down_count ); + r[2] = htonl( torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - + torrent->peer_list6->seed_count - torrent->peer_list4->seed_count); } } mutex_bucket_unlock_by_hash( hash, delta_torrentcount ); @@ -342,7 +363,10 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl *r++='2';*r++='0';*r++=':'; memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash); r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", - torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ); + torrent->peer_list6->seed_count + torrent->peer_list4->seed_count, + torrent->peer_list6->down_count + torrent->peer_list4->down_count, + torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - + torrent->peer_list6->seed_count - torrent->peer_list4->seed_count); } } mutex_bucket_unlock_by_hash( *hash, delta_torrentcount ); @@ -358,17 +382,19 @@ size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) { ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); ot_torrent *torrent = binary_search( ws->hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); ot_peerlist *peer_list = &dummy_list; + size_t peer_size; /* initialized in next line */ + ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size); #ifdef WANT_SYNC_LIVE if( proto != FLAG_MCA ) { - OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; + OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED; livesync_tell( ws ); } #endif if( exactmatch ) { - peer_list = torrent->peer_list; - switch( vector_remove_peer( &peer_list->peers, &ws->peer ) ) { + peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; + switch( vector_remove_peer( &peer_list->peers, peer_src, peer_size ) ) { case 2: peer_list->seed_count--; /* Intentional fallthrough */ case 1: peer_list->peer_count--; /* Intentional fallthrough */ default: break; @@ -377,7 +403,7 @@ size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) { if( proto == FLAG_TCP ) { int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; - ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie" PEERS_BENCODED "0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2 ); + ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4 ); } /* Handle UDP reply */ @@ -409,6 +435,23 @@ void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data } } +ot_peer *peer_from_peer6( ot_peer6 *peer, size_t *peer_size ) { + ot_ip6 *ip = (ot_ip6*)peer; + if( !ip6_isv4mapped(ip) ) { + *peer_size = OT_PEER_SIZE6; + return (ot_peer*)peer; + } + *peer_size = OT_PEER_SIZE4; + return (ot_peer*)(((uint8_t*)peer) + 12); +} + +size_t peer_size_from_peer6(ot_peer6 *peer) { + ot_ip6 *ip = (ot_ip6*)peer; + if( !ip6_isv4mapped(ip)) + return OT_PEER_SIZE6; + return OT_PEER_SIZE4; +} + void exerr( char * message ) { fprintf( stderr, "%s\n", message ); exit( 111 ); @@ -440,7 +483,8 @@ void trackerlogic_deinit( void ) { if( torrents_list->size ) { for( j=0; jsize; ++j ) { ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j; - free_peerlist( torrent->peer_list ); + free_peerlist( torrent->peer_list6 ); + free_peerlist( torrent->peer_list4 ); delta_torrentcount -= 1; } free( torrents_list->data ); diff --git a/trackerlogic.h b/trackerlogic.h index f43b4f1..24ef097 100644 --- a/trackerlogic.h +++ b/trackerlogic.h @@ -24,16 +24,12 @@ typedef time_t ot_time; typedef char ot_ip6[16]; typedef struct { ot_ip6 address; int bits; } ot_net; -#ifdef WANT_V6 -#define OT_IP_SIZE 16 -#define PEERS_BENCODED "6:peers6" /* List of peers should fit in a single UDP packet (around 1200 bytes) */ -#define OT_MAX_PEERS_UDP 66 -#else -#define OT_IP_SIZE 4 -#define PEERS_BENCODED "5:peers" -#define OT_MAX_PEERS_UDP 200 -#endif +#define OT_MAX_PEERS_UDP6 66 +#define OT_MAX_PEERS_UDP4 200 + +#define OT_IP_SIZE6 16 +#define OT_IP_SIZE4 4 #define OT_PORT_SIZE 2 #define OT_FLAG_SIZE 1 #define OT_TIME_SIZE 1 @@ -61,6 +57,7 @@ typedef struct { ot_ip6 address; int bits; } #define OT_ADMINIP_MAX 64 #define OT_MAX_THREADS 64 +/* Number of minutes after announce before peer is removed */ #define OT_PEER_TIMEOUT 45 /* We maintain a list of 1024 pointers to sorted list of ot_torrent structs @@ -78,23 +75,35 @@ extern volatile int g_opentracker_running; extern uint32_t g_tracker_id; typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG; -#define OT_PEER_COMPARE_SIZE ((OT_IP_SIZE)+(OT_PORT_SIZE)) -#define OT_PEER_SIZE ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE)) -typedef uint8_t ot_peer[OT_PEER_SIZE]; +#define OT_PEER_COMPARE_SIZE6 ((OT_IP_SIZE6)+(OT_PORT_SIZE)) +#define OT_PEER_COMPARE_SIZE4 ((OT_IP_SIZE4)+(OT_PORT_SIZE)) +#define OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(PEER_SIZE) ((PEER_SIZE)-(OT_TIME_SIZE)-(OT_FLAG_SIZE)) + +#define OT_PEER_SIZE6 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE6)) +#define OT_PEER_SIZE4 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE4)) + +typedef uint8_t ot_peer[1]; +typedef uint8_t ot_peer6[OT_PEER_SIZE6]; +typedef uint8_t ot_peer4[OT_PEER_SIZE4]; static const uint8_t PEER_FLAG_SEEDING = 0x80; static const uint8_t PEER_FLAG_COMPLETED = 0x40; static const uint8_t PEER_FLAG_STOPPED = 0x20; static const uint8_t PEER_FLAG_FROM_SYNC = 0x10; static const uint8_t PEER_FLAG_LEECHING = 0x00; -#ifdef WANT_V6 -#define OT_SETIP(peer,ip) memcpy((peer),(ip),(OT_IP_SIZE)) -#else -#define OT_SETIP(peer,ip) memcpy((peer),(((uint8_t*)ip)+12),(OT_IP_SIZE)) -#endif -#define OT_SETPORT(peer,port) memcpy(((uint8_t*)(peer))+(OT_IP_SIZE),(port),2) -#define OT_PEERFLAG(peer) (((uint8_t*)(peer))[(OT_IP_SIZE)+2]) -#define OT_PEERTIME(peer) (((uint8_t*)(peer))[(OT_IP_SIZE)+3]) +/* Takes an ot_peer6 and returns the proper pointer to the peer and sets peer_size */ +ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size); +size_t peer_size_from_peer6(ot_peer6 *peer); + +/* New style */ +#define OT_SETIP(peer,ip) memcpy((peer),(ip),OT_IP_SIZE6) +#define OT_SETPORT(peer,port) memcpy(((uint8_t*)(peer))+(OT_IP_SIZE6),(port),2) +#define OT_PEERFLAG(peer) (((uint8_t*)(peer))[(OT_IP_SIZE6)+2]) +#define OT_PEERFLAG_D(peer,peersize) (((uint8_t*)(peer))[(peersize)-2]) +#define OT_PEERTIME(peer,peersize) (((uint8_t*)(peer))[(peersize)-1]) + +#define PEERS_BENCODED6 "6:peers6" +#define PEERS_BENCODED4 "5:peers" #define OT_HASH_COMPARE_SIZE (sizeof(ot_hash)) @@ -102,7 +111,8 @@ struct ot_peerlist; typedef struct ot_peerlist ot_peerlist; typedef struct { ot_hash hash; - ot_peerlist *peer_list; + ot_peerlist *peer_list6; + ot_peerlist *peer_list4; } ot_torrent; #include "ot_vector.h" @@ -131,7 +141,7 @@ struct ot_workstruct { #endif /* The peer currently in the working */ - ot_peer peer; + ot_peer6 peer; /* Can fit v6 and v4 peers */ /* Pointers into the request buffer */ ot_hash *hash; -- cgit v1.2.3