summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2024-04-03 22:25:30 +0200
committerDirk Engling <erdgeist@erdgeist.org>2024-04-03 22:25:30 +0200
commit2afc4893bf802700a1decfff57673cefc861c7e7 (patch)
tree9a0817371ac05062dbcf25107fcf5a6481feccc0
parenteb8834f7783cb85ae825976425800cd4af711263 (diff)
Prepare opentracker for dual stack capabilities
-rw-r--r--ot_clean.c63
-rw-r--r--ot_fullscrape.c24
-rw-r--r--ot_http.c18
-rw-r--r--ot_livesync.c12
-rw-r--r--ot_mutex.h2
-rw-r--r--ot_stats.c36
-rw-r--r--ot_udp.c26
-rw-r--r--ot_vector.c83
-rw-r--r--ot_vector.h10
-rw-r--r--trackerlogic.c174
-rw-r--r--trackerlogic.h54
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 @@
20#include "ot_accesslist.h" 20#include "ot_accesslist.h"
21 21
22/* Returns amount of removed peers */ 22/* Returns amount of removed peers */
23static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) { 23static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders ) {
24 ot_peer *last_peer = peers + peer_count, *insert_point; 24 ot_peer *last_peer = peers + peer_count * peer_size, *insert_point;
25 time_t timediff;
26 25
27 /* Two scan modes: unless there is one peer removed, just increase ot_peertime */ 26 /* Two scan modes: unless there is one peer removed, just increase ot_peertime */
28 while( peers < last_peer ) { 27 while( peers < last_peer ) {
29 if( ( timediff = timedout + OT_PEERTIME( peers ) ) >= OT_PEER_TIMEOUT ) 28 time_t timediff = timedout + OT_PEERTIME( peers, peer_size );
29 if( timediff >= OT_PEER_TIMEOUT )
30 break; 30 break;
31 OT_PEERTIME( peers++ ) = timediff; 31 OT_PEERTIME( peers, peer_size ) = timediff;
32 peers += peer_size;
32 } 33 }
33 34
34 /* If we at least remove one peer, we have to copy */ 35 /* If we at least remove one peer, we have to copy */
35 insert_point = peers; 36 for( insert_point = peers; peers < last_peer; peers += peer_size ) {
36 while( peers < last_peer ) 37 time_t timediff = timedout + OT_PEERTIME( peers, peer_size );
37 if( ( timediff = timedout + OT_PEERTIME( peers ) ) < OT_PEER_TIMEOUT ) { 38
38 OT_PEERTIME( peers ) = timediff; 39 if( timediff < OT_PEER_TIMEOUT ) {
39 memcpy( insert_point++, peers++, sizeof(ot_peer)); 40 OT_PEERTIME( peers, peer_size ) = timediff;
41 memcpy( insert_point, peers, peer_size);
42 insert_point += peer_size;
40 } else 43 } else
41 if( OT_PEERFLAG( peers++ ) & PEER_FLAG_SEEDING ) 44 if( OT_PEERFLAG_D( peers, peer_size ) & PEER_FLAG_SEEDING )
42 (*removed_seeders)++; 45 (*removed_seeders)++;
46 }
43 47
44 return peers - insert_point; 48 return peers - insert_point;
45} 49}
46 50
47/* Clean a single torrent 51int clean_single_peer_list( ot_peerlist *peer_list, size_t peer_size ) {
48 return 1 if torrent timed out 52 ot_vector *peer_vector = &peer_list->peers;
49*/
50int clean_single_torrent( ot_torrent *torrent ) {
51 ot_peerlist *peer_list = torrent->peer_list;
52 ot_vector *bucket_list = &peer_list->peers;
53 time_t timedout = (time_t)( g_now_minutes - peer_list->base ); 53 time_t timedout = (time_t)( g_now_minutes - peer_list->base );
54 int num_buckets = 1, removed_seeders = 0; 54 int num_buckets = 1, removed_seeders = 0;
55 55
@@ -69,24 +69,26 @@ int clean_single_torrent( ot_torrent *torrent ) {
69 } 69 }
70 70
71 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { 71 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
72 num_buckets = bucket_list->size; 72 num_buckets = peer_vector->size;
73 bucket_list = (ot_vector *)bucket_list->data; 73 peer_vector = (ot_vector *)peer_vector->data;
74 } 74 }
75 75
76 while( num_buckets-- ) { 76 while( num_buckets-- ) {
77 size_t removed_peers = clean_single_bucket( bucket_list->data, bucket_list->size, timedout, &removed_seeders ); 77 size_t removed_peers = clean_single_bucket( peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders );
78 peer_list->peer_count -= removed_peers; 78 peer_list->peer_count -= removed_peers;
79 bucket_list->size -= removed_peers; 79 peer_vector->size -= removed_peers;
80 if( bucket_list->size < removed_peers ) 80 if( removed_peers )
81 vector_fixup_peers( bucket_list ); 81 vector_fixup_peers( peer_vector, peer_size );
82 ++bucket_list; 82
83 /* Skip to next bucket, a vector containing peers */
84 ++peer_vector;
83 } 85 }
84 86
85 peer_list->seed_count -= removed_seeders; 87 peer_list->seed_count -= removed_seeders;
86 88
87 /* See, if we need to convert a torrent from simple vector to bucket list */ 89 /* See if we need to convert a torrent from simple vector to bucket list */
88 if( ( peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT ) || OT_PEERLIST_HASBUCKETS(peer_list) ) 90 if( ( peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT ) || OT_PEERLIST_HASBUCKETS(peer_list) )
89 vector_redistribute_buckets( peer_list ); 91 vector_redistribute_buckets( peer_list, peer_size );
90 92
91 if( peer_list->peer_count ) 93 if( peer_list->peer_count )
92 peer_list->base = g_now_minutes; 94 peer_list->base = g_now_minutes;
@@ -96,7 +98,14 @@ int clean_single_torrent( ot_torrent *torrent ) {
96 peer_list->base = g_now_minutes - OT_PEER_TIMEOUT; 98 peer_list->base = g_now_minutes - OT_PEER_TIMEOUT;
97 } 99 }
98 return 0; 100 return 0;
101}
99 102
103/* Clean a single torrent
104 return 1 if torrent timed out
105*/
106int clean_single_torrent( ot_torrent *torrent ) {
107 return clean_single_peer_list( torrent->peer_list6, OT_PEER_SIZE6) *
108 clean_single_peer_list( torrent->peer_list4, OT_PEER_SIZE4);
100} 109}
101 110
102/* Clean up all peers in current bucket, remove timedout pools and 111/* 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 ) {
82 mutex_workqueue_pushtask( sock, tasktype ); 82 mutex_workqueue_pushtask( sock, tasktype );
83} 83}
84 84
85static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_peerlist *peer_list, ot_hash *hash ) { 85static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_torrent *torrent, ot_hash *hash ) {
86 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
87 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
88 size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count;
89
86 switch( mode & TASK_TASK_MASK ) { 90 switch( mode & TASK_TASK_MASK ) {
87 case TASK_FULLSCRAPE: 91 case TASK_FULLSCRAPE:
88 default: 92 default:
@@ -90,30 +94,30 @@ static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_peerlist *peer
90 *r++='2'; *r++='0'; *r++=':'; 94 *r++='2'; *r++='0'; *r++=':';
91 memcpy( r, hash, sizeof(ot_hash) ); r += sizeof(ot_hash); 95 memcpy( r, hash, sizeof(ot_hash) ); r += sizeof(ot_hash);
92 /* push rest of the scrape string */ 96 /* push rest of the scrape string */
93 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 ); 97 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, down_count, peer_count-seed_count );
94 98
95 break; 99 break;
96 case TASK_FULLSCRAPE_TPB_ASCII: 100 case TASK_FULLSCRAPE_TPB_ASCII:
97 to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); 101 to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
98 r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count ); 102 r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count );
99 break; 103 break;
100 case TASK_FULLSCRAPE_TPB_ASCII_PLUS: 104 case TASK_FULLSCRAPE_TPB_ASCII_PLUS:
101 to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); 105 to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
102 r += sprintf( r, ":%zd:%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count, peer_list->down_count ); 106 r += sprintf( r, ":%zd:%zd:%zd\n", seed_count, peer_count-seed_count, down_count );
103 break; 107 break;
104 case TASK_FULLSCRAPE_TPB_BINARY: 108 case TASK_FULLSCRAPE_TPB_BINARY:
105 memcpy( r, *hash, sizeof(ot_hash) ); r += sizeof(ot_hash); 109 memcpy( r, *hash, sizeof(ot_hash) ); r += sizeof(ot_hash);
106 *(uint32_t*)(r+0) = htonl( (uint32_t) peer_list->seed_count ); 110 *(uint32_t*)(r+0) = htonl( (uint32_t) seed_count );
107 *(uint32_t*)(r+4) = htonl( (uint32_t)( peer_list->peer_count-peer_list->seed_count) ); 111 *(uint32_t*)(r+4) = htonl( (uint32_t)( peer_count-seed_count) );
108 r+=8; 112 r+=8;
109 break; 113 break;
110 case TASK_FULLSCRAPE_TPB_URLENCODED: 114 case TASK_FULLSCRAPE_TPB_URLENCODED:
111 r += fmt_urlencoded( r, (char *)*hash, 20 ); 115 r += fmt_urlencoded( r, (char *)*hash, 20 );
112 r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count ); 116 r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count );
113 break; 117 break;
114 case TASK_FULLSCRAPE_TRACKERSTATE: 118 case TASK_FULLSCRAPE_TRACKERSTATE:
115 to_hex( r, *hash ); r+= 2 * sizeof(ot_hash); 119 to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
116 r += sprintf( r, ":%zd:%zd\n", peer_list->base, peer_list->down_count ); 120 r += sprintf( r, ":%zd:%zd\n", torrent->peer_list6->base, down_count );
117 break; 121 break;
118 } 122 }
119 return r; 123 return r;
@@ -145,7 +149,7 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas
145 149
146 /* For each torrent in this bucket.. */ 150 /* For each torrent in this bucket.. */
147 for( i=0; i<torrents_list->size; ++i ) { 151 for( i=0; i<torrents_list->size; ++i ) {
148 r = fullscrape_write_one( mode, r, torrents[i].peer_list, &torrents[i].hash ); 152 r = fullscrape_write_one( mode, r, torrents+i, &torrents[i].hash );
149 153
150 if( r > re) { 154 if( r > re) {
151 /* Allocate a fresh output buffer at the end of our buffers list */ 155 /* 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
210 /* For each torrent in this bucket.. */ 214 /* For each torrent in this bucket.. */
211 for( i=0; i<torrents_list->size; ++i ) { 215 for( i=0; i<torrents_list->size; ++i ) {
212 char compress_buffer[OT_SCRAPE_MAXENTRYLEN]; 216 char compress_buffer[OT_SCRAPE_MAXENTRYLEN];
213 r = fullscrape_write_one( mode, compress_buffer, torrents[i].peer_list, &torrents[i].hash ); 217 r = fullscrape_write_one( mode, compress_buffer, torrents+i, &torrents[i].hash );
214 strm.next_in = (uint8_t*)compress_buffer; 218 strm.next_in = (uint8_t*)compress_buffer;
215 strm.avail_in = r - compress_buffer; 219 strm.avail_in = r - compress_buffer;
216 zres = deflate( &strm, Z_NO_FLUSH ); 220 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,
421 ot_ip6 proxied_ip; 421 ot_ip6 proxied_ip;
422 char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" ); 422 char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" );
423 if( fwd && scan_ip6( fwd, proxied_ip ) ) { 423 if( fwd && scan_ip6( fwd, proxied_ip ) ) {
424 /* If proxy reports an ipv6 address but we can only handle v4 (or vice versa), bail out */ 424 OT_SETIP( ws->peer, proxied_ip );
425#ifndef WANT_V6
426 if( !ip6_isv4mapped(proxied_ip) )
427#else
428 if( ip6_isv4mapped(proxied_ip) )
429#endif
430 HTTPERROR_400_PARAM;
431
432 OT_SETIP( &ws->peer, proxied_ip );
433 } else 425 } else
434 OT_SETIP( &ws->peer, cookie->ip ); 426 OT_SETIP( ws->peer, cookie->ip );
435 } else 427 } else
436#endif 428#endif
437 OT_SETIP( &ws->peer, cookie->ip ); 429 OT_SETIP( ws->peer, cookie->ip );
438 430
439 ws->peer_id = NULL; 431 ws->peer_id = NULL;
440 ws->hash = NULL; 432 ws->hash = NULL;
441 433
442 OT_SETPORT( &ws->peer, &port ); 434 OT_SETPORT( ws->peer, &port );
443 OT_PEERFLAG( &ws->peer ) = 0; 435 OT_PEERFLAG( ws->peer ) = 0;
444 numwant = 50; 436 numwant = 50;
445 scanon = 1; 437 scanon = 1;
446 438
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 ) {
127 127
128 /* Now basic sanity checks have been done on the live sync packet 128 /* Now basic sanity checks have been done on the live sync packet
129 We might add more testing and logging. */ 129 We might add more testing and logging. */
130 while( off + (ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ) <= ws->request_size ) { 130 while( off + (ssize_t)sizeof( ot_hash ) + OT_PEER_SIZE4 <= ws->request_size ) {
131 memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), sizeof( ot_peer ) ); 131 memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), OT_PEER_SIZE4 );
132 ws->hash = (ot_hash*)(ws->request + off); 132 ws->hash = (ot_hash*)(ws->request + off);
133 133
134 if( !g_opentracker_running ) return; 134 if( !g_opentracker_running ) return;
135 135
136 if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_STOPPED ) 136 if( OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED )
137 remove_peer_from_torrent( FLAG_MCA, ws ); 137 remove_peer_from_torrent( FLAG_MCA, ws );
138 else 138 else
139 add_peer_to_torrent_and_return_peers( FLAG_MCA, ws, /* amount = */ 0 ); 139 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 ) {
143 143
144 stats_issue_event(EVENT_SYNC, 0, 144 stats_issue_event(EVENT_SYNC, 0,
145 (ws->request_size - sizeof( g_tracker_id ) - sizeof( uint32_t ) ) / 145 (ws->request_size - sizeof( g_tracker_id ) - sizeof( uint32_t ) ) /
146 ((ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ))); 146 ((ssize_t)sizeof( ot_hash ) + OT_PEER_SIZE4));
147} 147}
148 148
149/* Tickle the live sync module from time to time, so no events get 149/* Tickle the live sync module from time to time, so no events get
@@ -164,9 +164,9 @@ void livesync_tell( struct ot_workstruct *ws ) {
164 pthread_mutex_lock(&g_outbuf_mutex); 164 pthread_mutex_lock(&g_outbuf_mutex);
165 165
166 memcpy( g_outbuf + g_outbuf_data, ws->hash, sizeof(ot_hash) ); 166 memcpy( g_outbuf + g_outbuf_data, ws->hash, sizeof(ot_hash) );
167 memcpy( g_outbuf + g_outbuf_data + sizeof(ot_hash), &ws->peer, sizeof(ot_peer) ); 167 memcpy( g_outbuf + g_outbuf_data + sizeof(ot_hash), &ws->peer, OT_PEER_SIZE4 );
168 168
169 g_outbuf_data += sizeof(ot_hash) + sizeof(ot_peer); 169 g_outbuf_data += sizeof(ot_hash) + OT_PEER_SIZE4;
170 170
171 if( g_outbuf_data >= LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS ) 171 if( g_outbuf_data >= LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS )
172 livesync_issue_peersync(); 172 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 {
43 TASK_STATS_EVERYTHING = 0x0106, 43 TASK_STATS_EVERYTHING = 0x0106,
44 TASK_STATS_FULLLOG = 0x0107, 44 TASK_STATS_FULLLOG = 0x0107,
45 TASK_STATS_WOODPECKERS = 0x0108, 45 TASK_STATS_WOODPECKERS = 0x0108,
46 46
47 TASK_FULLSCRAPE = 0x0200, /* Default mode */ 47 TASK_FULLSCRAPE = 0x0200, /* Default mode */
48 TASK_FULLSCRAPE_TPB_BINARY = 0x0201, 48 TASK_FULLSCRAPE_TPB_BINARY = 0x0201,
49 TASK_FULLSCRAPE_TPB_ASCII = 0x0202, 49 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;
73#define __LDR(P,D) ((__BYTE((P),(D))>>__SHFT((D)))&__MSK) 73#define __LDR(P,D) ((__BYTE((P),(D))>>__SHFT((D)))&__MSK)
74#define __STR(P,D,V) __BYTE((P),(D))=(__BYTE((P),(D))&~(__MSK<<__SHFT((D))))|((V)<<__SHFT((D))) 74#define __STR(P,D,V) __BYTE((P),(D))=(__BYTE((P),(D))&~(__MSK<<__SHFT((D))))|((V)<<__SHFT((D)))
75 75
76#ifdef WANT_V6 76//#ifdef WANT_V6
77#define STATS_NETWORK_NODE_MAXDEPTH (68-STATS_NETWORK_NODE_BITWIDTH) 77//#define STATS_NETWORK_NODE_MAXDEPTH (68-STATS_NETWORK_NODE_BITWIDTH)
78#define STATS_NETWORK_NODE_LIMIT (48-STATS_NETWORK_NODE_BITWIDTH) 78//#define STATS_NETWORK_NODE_LIMIT (48-STATS_NETWORK_NODE_BITWIDTH)
79#else 79//#else
80#define STATS_NETWORK_NODE_MAXDEPTH (28-STATS_NETWORK_NODE_BITWIDTH) 80#define STATS_NETWORK_NODE_MAXDEPTH (28-STATS_NETWORK_NODE_BITWIDTH)
81#define STATS_NETWORK_NODE_LIMIT (24-STATS_NETWORK_NODE_BITWIDTH) 81#define STATS_NETWORK_NODE_LIMIT (24-STATS_NETWORK_NODE_BITWIDTH)
82#endif 82//#endif
83 83
84typedef union stats_network_node stats_network_node; 84typedef union stats_network_node stats_network_node;
85union stats_network_node { 85union stats_network_node {
@@ -219,12 +219,12 @@ static size_t stats_slash24s_txt( char *reply, size_t amount ) {
219 stats_network_node *slash24s_network_counters_root = NULL; 219 stats_network_node *slash24s_network_counters_root = NULL;
220 char *r=reply; 220 char *r=reply;
221 int bucket; 221 int bucket;
222 size_t i; 222 size_t i, peer_size = OT_PEER_SIZE4;
223 223
224 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 224 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
225 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 225 ot_vector *torrents_list = mutex_bucket_lock( bucket );
226 for( i=0; i<torrents_list->size; ++i ) { 226 for( i=0; i<torrents_list->size; ++i ) {
227 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list; 227 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list4;
228 ot_vector *bucket_list = &peer_list->peers; 228 ot_vector *bucket_list = &peer_list->peers;
229 int num_buckets = 1; 229 int num_buckets = 1;
230 230
@@ -236,9 +236,11 @@ static size_t stats_slash24s_txt( char *reply, size_t amount ) {
236 while( num_buckets-- ) { 236 while( num_buckets-- ) {
237 ot_peer *peers = (ot_peer*)bucket_list->data; 237 ot_peer *peers = (ot_peer*)bucket_list->data;
238 size_t numpeers = bucket_list->size; 238 size_t numpeers = bucket_list->size;
239 while( numpeers-- ) 239 while( numpeers-- ) {
240 if( stat_increase_network_count( &slash24s_network_counters_root, 0, (uintptr_t)(peers++) ) ) 240 if( stat_increase_network_count( &slash24s_network_counters_root, 0, (uintptr_t)(peers) ) )
241 goto bailout_unlock; 241 goto bailout_unlock;
242 peers += peer_size;
243 }
242 ++bucket_list; 244 ++bucket_list;
243 } 245 }
244 } 246 }
@@ -285,8 +287,8 @@ typedef struct {
285static int torrent_statter( ot_torrent *torrent, uintptr_t data ) { 287static int torrent_statter( ot_torrent *torrent, uintptr_t data ) {
286 torrent_stats *stats = (torrent_stats*)data; 288 torrent_stats *stats = (torrent_stats*)data;
287 stats->torrent_count++; 289 stats->torrent_count++;
288 stats->peer_count += torrent->peer_list->peer_count; 290 stats->peer_count += torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
289 stats->seed_count += torrent->peer_list->seed_count; 291 stats->seed_count += torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
290 return 0; 292 return 0;
291} 293}
292 294
@@ -312,21 +314,23 @@ size_t stats_top_txt( char * reply, int amount ) {
312 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 314 ot_vector *torrents_list = mutex_bucket_lock( bucket );
313 for( j=0; j<torrents_list->size; ++j ) { 315 for( j=0; j<torrents_list->size; ++j ) {
314 ot_torrent *torrent = (ot_torrent*)(torrents_list->data) + j; 316 ot_torrent *torrent = (ot_torrent*)(torrents_list->data) + j;
317 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
318 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
315 idx = amount - 1; 319 idx = amount - 1;
316 while( (idx >= 0) && ( torrent->peer_list->peer_count > top100c[idx].val ) ) 320 while( (idx >= 0) && ( peer_count > top100c[idx].val ) )
317 --idx; 321 --idx;
318 if ( idx++ != amount - 1 ) { 322 if ( idx++ != amount - 1 ) {
319 memmove( top100c + idx + 1, top100c + idx, ( amount - 1 - idx ) * sizeof( ot_record ) ); 323 memmove( top100c + idx + 1, top100c + idx, ( amount - 1 - idx ) * sizeof( ot_record ) );
320 memcpy( &top100c[idx].hash, &torrent->hash, sizeof(ot_hash)); 324 memcpy( &top100c[idx].hash, &torrent->hash, sizeof(ot_hash));
321 top100c[idx].val = torrent->peer_list->peer_count; 325 top100c[idx].val = peer_count;
322 } 326 }
323 idx = amount - 1; 327 idx = amount - 1;
324 while( (idx >= 0) && ( torrent->peer_list->seed_count > top100s[idx].val ) ) 328 while( (idx >= 0) && ( seed_count > top100s[idx].val ) )
325 --idx; 329 --idx;
326 if ( idx++ != amount - 1 ) { 330 if ( idx++ != amount - 1 ) {
327 memmove( top100s + idx + 1, top100s + idx, ( amount - 1 - idx ) * sizeof( ot_record ) ); 331 memmove( top100s + idx + 1, top100s + idx, ( amount - 1 - idx ) * sizeof( ot_record ) );
328 memcpy( &top100s[idx].hash, &torrent->hash, sizeof(ot_hash)); 332 memcpy( &top100s[idx].hash, &torrent->hash, sizeof(ot_hash));
329 top100s[idx].val = torrent->peer_list->seed_count; 333 top100s[idx].val = seed_count;
330 } 334 }
331 } 335 }
332 mutex_bucket_unlock( bucket, 0 ); 336 mutex_bucket_unlock( bucket, 0 );
@@ -718,7 +722,7 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event
718 break; 722 break;
719 case EVENT_SYNC: 723 case EVENT_SYNC:
720 ot_overall_sync_count+=event_data; 724 ot_overall_sync_count+=event_data;
721 break; 725 break;
722 case EVENT_BUCKET_LOCKED: 726 case EVENT_BUCKET_LOCKED:
723 ot_overall_stall_count++; 727 ot_overall_stall_count++;
724 break; 728 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 @@
13/* Libowfat */ 13/* Libowfat */
14#include "socket.h" 14#include "socket.h"
15#include "io.h" 15#include "io.h"
16#include "ip6.h"
16 17
17/* Opentracker */ 18/* Opentracker */
18#include "trackerlogic.h" 19#include "trackerlogic.h"
@@ -73,7 +74,7 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
73 ot_ip6 remoteip; 74 ot_ip6 remoteip;
74 uint32_t *inpacket = (uint32_t*)ws->inbuf; 75 uint32_t *inpacket = (uint32_t*)ws->inbuf;
75 uint32_t *outpacket = (uint32_t*)ws->outbuf; 76 uint32_t *outpacket = (uint32_t*)ws->outbuf;
76 uint32_t numwant, left, event, scopeid; 77 uint32_t left, event, scopeid;
77 uint32_t connid[2]; 78 uint32_t connid[2];
78 uint32_t action; 79 uint32_t action;
79 uint16_t port, remoteport; 80 uint16_t port, remoteport;
@@ -141,34 +142,35 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
141 /* We do only want to know, if it is zero */ 142 /* We do only want to know, if it is zero */
142 left = inpacket[64/4] | inpacket[68/4]; 143 left = inpacket[64/4] | inpacket[68/4];
143 144
144 /* Limit amount of peers to OT_MAX_PEERS_UDP */
145 numwant = ntohl( inpacket[92/4] );
146 if (numwant > OT_MAX_PEERS_UDP) numwant = OT_MAX_PEERS_UDP;
147
148 event = ntohl( inpacket[80/4] ); 145 event = ntohl( inpacket[80/4] );
149 port = *(uint16_t*)( ((char*)inpacket) + 96 ); 146 port = *(uint16_t*)( ((char*)inpacket) + 96 );
150 ws->hash = (ot_hash*)( ((char*)inpacket) + 16 ); 147 ws->hash = (ot_hash*)( ((char*)inpacket) + 16 );
151 148
152 OT_SETIP( &ws->peer, remoteip ); 149 OT_SETIP( ws->peer, remoteip );
153 OT_SETPORT( &ws->peer, &port ); 150 OT_SETPORT( ws->peer, &port );
154 OT_PEERFLAG( &ws->peer ) = 0; 151 OT_PEERFLAG( ws->peer ) = 0;
155 152
156 switch( event ) { 153 switch( event ) {
157 case 1: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; break; 154 case 1: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED; break;
158 case 3: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; break; 155 case 3: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED; break;
159 default: break; 156 default: break;
160 } 157 }
161 158
162 if( !left ) 159 if( !left )
163 OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_SEEDING; 160 OT_PEERFLAG( ws->peer ) |= PEER_FLAG_SEEDING;
164 161
165 outpacket[0] = htonl( 1 ); /* announce action */ 162 outpacket[0] = htonl( 1 ); /* announce action */
166 outpacket[1] = inpacket[12/4]; 163 outpacket[1] = inpacket[12/4];
167 164
168 if( OT_PEERFLAG( &ws->peer ) & PEER_FLAG_STOPPED ) { /* Peer is gone. */ 165 if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_STOPPED ) { /* Peer is gone. */
169 ws->reply = ws->outbuf; 166 ws->reply = ws->outbuf;
170 ws->reply_size = remove_peer_from_torrent( FLAG_UDP, ws ); 167 ws->reply_size = remove_peer_from_torrent( FLAG_UDP, ws );
171 } else { 168 } else {
169 /* Limit amount of peers to OT_MAX_PEERS_UDP */
170 uint32_t numwant = ntohl( inpacket[92/4] );
171 size_t max_peers = ip6_isv4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6;
172 if (numwant > max_peers) numwant = max_peers;
173
172 ws->reply = ws->outbuf + 8; 174 ws->reply = ws->outbuf + 8;
173 ws->reply_size = 8 + add_peer_to_torrent_and_return_peers( FLAG_UDP, ws, numwant ); 175 ws->reply_size = 8 + add_peer_to_torrent_and_return_peers( FLAG_UDP, ws, numwant );
174 } 176 }
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 @@
17#include "uint32.h" 17#include "uint32.h"
18#include "uint16.h" 18#include "uint16.h"
19 19
20static int vector_compare_peer(const void *peer1, const void *peer2 ) { 20static int vector_compare_peer6(const void *peer1, const void *peer2 ) {
21 return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE ); 21 return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE6 );
22}
23static int vector_compare_peer4(const void *peer1, const void *peer2 ) {
24 return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE4 );
22} 25}
23 26
24/* This function gives us a binary search that returns a pointer, even if 27/* 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
47 return (void*)base; 50 return (void*)base;
48} 51}
49 52
50static uint8_t vector_hash_peer( ot_peer *peer, int bucket_count ) { 53static uint8_t vector_hash_peer( ot_peer const *peer, size_t compare_size, int bucket_count ) {
51 unsigned int hash = 5381, i = OT_PEER_COMPARE_SIZE; 54 unsigned int hash = 5381;
52 uint8_t *p = (uint8_t*)peer; 55 uint8_t *p = (uint8_t*)peer;
53 while( i-- ) hash += (hash<<5) + *(p++); 56 while( compare_size-- ) hash += (hash<<5) + *(p++);
54 return hash % bucket_count; 57 return hash % bucket_count;
55} 58}
56 59
@@ -82,27 +85,37 @@ void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, s
82 return match; 85 return match;
83} 86}
84 87
85ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ) { 88ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch ) {
86 ot_peer *match; 89 ot_peer *match, *end;
90 const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
91 size_t match_to_end;
87 92
88 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ 93 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
89 if( vector->space < vector->size ) 94 if( vector->space < vector->size )
90 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size ); 95 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size );
91 match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, exactmatch ); 96 match = binary_search( peer, vector->data, vector->size, peer_size, compare_size, exactmatch );
92 97
93 if( *exactmatch ) return match; 98 if( *exactmatch ) return match;
94 99
100 /* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */
101 end = (ot_peer*)vector->data + vector->size * peer_size;
102 match_to_end = end - match;
103
95 if( vector->size + 1 > vector->space ) { 104 if( vector->size + 1 > vector->space ) {
105 ptrdiff_t offset = match - (ot_peer*)vector->data;
96 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; 106 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
97 ot_peer *new_data = realloc( vector->data, new_space * sizeof(ot_peer) ); 107 ot_peer *new_data = realloc( vector->data, new_space * peer_size );
108
98 if( !new_data ) return NULL; 109 if( !new_data ) return NULL;
99 /* Adjust pointer if it moved by realloc */ 110 /* Adjust pointer if it moved by realloc */
100 match = new_data + (match - (ot_peer*)vector->data); 111 match = new_data + offset;
101 112
102 vector->data = new_data; 113 vector->data = new_data;
103 vector->space = new_space; 114 vector->space = new_space;
104 } 115 }
105 memmove( match + 1, match, sizeof(ot_peer) * ( ((ot_peer*)vector->data) + vector->size - match ) ); 116
117 /* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */
118 memmove( match + peer_size, match, match_to_end);
106 119
107 vector->size++; 120 vector->size++;
108 return match; 121 return match;
@@ -113,26 +126,27 @@ ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exac
113 1 if a non-seeding peer was removed 126 1 if a non-seeding peer was removed
114 2 if a seeding peer was removed 127 2 if a seeding peer was removed
115*/ 128*/
116int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { 129int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size) {
117 int exactmatch; 130 int exactmatch, was_seeder;
118 ot_peer *match, *end; 131 ot_peer *match, *end;
132 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
119 133
120 if( !vector->size ) return 0; 134 if( !vector->size ) return 0;
121 135
122 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ 136 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
123 if( vector->space < vector->size ) 137 if( vector->space < vector->size )
124 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size ); 138 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size );
125 139
126 end = ((ot_peer*)vector->data) + vector->size; 140 end = ((ot_peer*)vector->data) + peer_size * vector->size;
127 match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch ); 141 match = (ot_peer*)binary_search( peer, vector->data, vector->size, peer_size, compare_size, &exactmatch );
128 if( !exactmatch ) return 0; 142 if( !exactmatch ) return 0;
129 143
130 exactmatch = ( OT_PEERFLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; 144 was_seeder = ( OT_PEERFLAG_D( match, peer_size ) & PEER_FLAG_SEEDING ) ? 2 : 1;
131 memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); 145 memmove( match, match + peer_size, end - match - peer_size );
132 146
133 vector->size--; 147 vector->size--;
134 vector_fixup_peers( vector ); 148 vector_fixup_peers( vector, peer_size );
135 return exactmatch; 149 return was_seeder;
136} 150}
137 151
138void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { 152void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
@@ -142,7 +156,8 @@ void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
142 156
143 /* If this is being called after a unsuccessful malloc() for peer_list 157 /* If this is being called after a unsuccessful malloc() for peer_list
144 in add_peer_to_torrent, match->peer_list actually might be NULL */ 158 in add_peer_to_torrent, match->peer_list actually might be NULL */
145 if( match->peer_list) free_peerlist( match->peer_list ); 159 if( match->peer_list6) free_peerlist( match->peer_list6 );
160 if( match->peer_list4) free_peerlist( match->peer_list4 );
146 161
147 memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) ); 162 memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) );
148 if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) { 163 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 ) {
158 return; 173 return;
159} 174}
160 175
161void vector_redistribute_buckets( ot_peerlist * peer_list ) { 176void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size ) {
162 int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1; 177 int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1;
163 ot_vector * bucket_list_new, * bucket_list_old = &peer_list->peers; 178 ot_vector * bucket_list_new, * bucket_list_old = &peer_list->peers;
179 int (*sort_func)(const void *, const void *) =
180 peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
164 181
165 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { 182 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
166 num_buckets_old = peer_list->peers.size; 183 num_buckets_old = peer_list->peers.size;
@@ -198,33 +215,33 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) {
198 /* preallocate vectors to hold all peers */ 215 /* preallocate vectors to hold all peers */
199 for( bucket=0; bucket<num_buckets_new; ++bucket ) { 216 for( bucket=0; bucket<num_buckets_new; ++bucket ) {
200 bucket_list_new[bucket].space = bucket_size_new; 217 bucket_list_new[bucket].space = bucket_size_new;
201 bucket_list_new[bucket].data = malloc( bucket_size_new * sizeof(ot_peer) ); 218 bucket_list_new[bucket].data = malloc( bucket_size_new * peer_size );
202 if( !bucket_list_new[bucket].data ) 219 if( !bucket_list_new[bucket].data )
203 return vector_clean_list( bucket_list_new, num_buckets_new ); 220 return vector_clean_list( bucket_list_new, num_buckets_new );
204 } 221 }
205 222
206 /* Now sort them into the correct bucket */ 223 /* Now sort them into the correct bucket */
207 for( bucket=0; bucket<num_buckets_old; ++bucket ) { 224 for( bucket=0; bucket<num_buckets_old; ++bucket ) {
208 ot_peer * peers_old = bucket_list_old[bucket].data, * peers_new; 225 ot_peer * peers_old = bucket_list_old[bucket].data;
209 int peer_count_old = bucket_list_old[bucket].size; 226 int peer_count_old = bucket_list_old[bucket].size;
210 while( peer_count_old-- ) { 227 while( peer_count_old-- ) {
211 ot_vector * bucket_dest = bucket_list_new; 228 ot_vector * bucket_dest = bucket_list_new;
212 if( num_buckets_new > 1 ) 229 if( num_buckets_new > 1 )
213 bucket_dest += vector_hash_peer(peers_old, num_buckets_new); 230 bucket_dest += vector_hash_peer(peers_old, OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size), num_buckets_new);
214 if( bucket_dest->size + 1 > bucket_dest->space ) { 231 if( bucket_dest->size + 1 > bucket_dest->space ) {
215 void * tmp = realloc( bucket_dest->data, sizeof(ot_peer) * OT_VECTOR_GROW_RATIO * bucket_dest->space ); 232 void * tmp = realloc( bucket_dest->data, peer_size * OT_VECTOR_GROW_RATIO * bucket_dest->space );
216 if( !tmp ) return vector_clean_list( bucket_list_new, num_buckets_new ); 233 if( !tmp ) return vector_clean_list( bucket_list_new, num_buckets_new );
217 bucket_dest->data = tmp; 234 bucket_dest->data = tmp;
218 bucket_dest->space *= OT_VECTOR_GROW_RATIO; 235 bucket_dest->space *= OT_VECTOR_GROW_RATIO;
219 } 236 }
220 peers_new = (ot_peer*)bucket_dest->data; 237 memcpy((ot_peer*)bucket_dest->data + peer_size * bucket_dest->size++, peers_old, peer_size);
221 memcpy(peers_new + bucket_dest->size++, peers_old++, sizeof(ot_peer)); 238 peers_old += peer_size;
222 } 239 }
223 } 240 }
224 241
225 /* Now sort each bucket to later allow bsearch */ 242 /* Now sort each bucket to later allow bsearch */
226 for( bucket=0; bucket<num_buckets_new; ++bucket ) 243 for( bucket=0; bucket<num_buckets_new; ++bucket )
227 qsort( bucket_list_new[bucket].data, bucket_list_new[bucket].size, sizeof( ot_peer ), vector_compare_peer ); 244 qsort( bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func );
228 245
229 /* Everything worked fine. Now link new bucket_list to peer_list */ 246 /* Everything worked fine. Now link new bucket_list to peer_list */
230 if( OT_PEERLIST_HASBUCKETS( peer_list) ) 247 if( OT_PEERLIST_HASBUCKETS( peer_list) )
@@ -244,7 +261,7 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) {
244 } 261 }
245} 262}
246 263
247void vector_fixup_peers( ot_vector * vector ) { 264void vector_fixup_peers( ot_vector * vector, size_t peer_size ) {
248 int need_fix = 0; 265 int need_fix = 0;
249 266
250 if( !vector->size ) { 267 if( !vector->size ) {
@@ -260,7 +277,7 @@ void vector_fixup_peers( ot_vector * vector ) {
260 need_fix++; 277 need_fix++;
261 } 278 }
262 if( need_fix ) 279 if( need_fix )
263 vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); 280 vector->data = realloc( vector->data, vector->space * peer_size );
264} 281}
265 282
266const char *g_version_vector_c = "$Source$: $Revision$\n"; 283const 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 {
24void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, 24void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size,
25 size_t compare_size, int *exactmatch ); 25 size_t compare_size, int *exactmatch );
26void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ); 26void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch );
27ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ); 27ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch );
28 28
29int vector_remove_peer( ot_vector *vector, ot_peer *peer ); 29int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size);
30void vector_remove_torrent( ot_vector *vector, ot_torrent *match ); 30void vector_remove_torrent( ot_vector *vector, ot_torrent *match );
31void vector_redistribute_buckets( ot_peerlist * peer_list ); 31
32void vector_fixup_peers( ot_vector * vector ); 32/* For ot_clean.c */
33void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size );
34void vector_fixup_peers( ot_vector * vector, size_t peer_size );
33 35
34#endif 36#endif
diff --git a/trackerlogic.c b/trackerlogic.c
index 47e0085..9d564c1 100644
--- a/trackerlogic.c
+++ b/trackerlogic.c
@@ -16,6 +16,7 @@
16#include "byte.h" 16#include "byte.h"
17#include "io.h" 17#include "io.h"
18#include "iob.h" 18#include "iob.h"
19#include "ip6.h"
19#include "array.h" 20#include "array.h"
20 21
21/* Opentracker */ 22/* Opentracker */
@@ -57,25 +58,33 @@ void add_torrent_from_saved_state( ot_hash hash, ot_time base, size_t down_count
57 return mutex_bucket_unlock_by_hash( hash, 0 ); 58 return mutex_bucket_unlock_by_hash( hash, 0 );
58 59
59 /* Create a new torrent entry, then */ 60 /* Create a new torrent entry, then */
61 byte_zero( torrent, sizeof( ot_torrent ) );
60 memcpy( torrent->hash, hash, sizeof(ot_hash) ); 62 memcpy( torrent->hash, hash, sizeof(ot_hash) );
61 63
62 if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { 64 if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) ||
65 !( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) {
63 vector_remove_torrent( torrents_list, torrent ); 66 vector_remove_torrent( torrents_list, torrent );
64 return mutex_bucket_unlock_by_hash( hash, 0 ); 67 return mutex_bucket_unlock_by_hash( hash, 0 );
65 } 68 }
66 69
67 byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); 70 byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) );
68 torrent->peer_list->base = base; 71 byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) );
69 torrent->peer_list->down_count = down_count; 72 torrent->peer_list6->base = base;
73 torrent->peer_list4->base = base;
74 torrent->peer_list6->down_count = down_count;
75 torrent->peer_list4->down_count = down_count;
70 76
71 return mutex_bucket_unlock_by_hash( hash, 1 ); 77 return mutex_bucket_unlock_by_hash( hash, 1 );
72} 78}
73 79
74size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) { 80size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) {
75 int exactmatch, delta_torrentcount = 0; 81 int exactmatch, delta_torrentcount = 0;
76 ot_torrent *torrent; 82 ot_torrent *torrent;
77 ot_peer *peer_dest; 83 ot_peer *peer_dest;
78 ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); 84 ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
85 ot_peerlist *peer_list;
86 size_t peer_size; /* initialized in next line */
87 ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size);
79 88
80 if( !accesslist_hashisvalid( *ws->hash ) ) { 89 if( !accesslist_hashisvalid( *ws->hash ) ) {
81 mutex_bucket_unlock_by_hash( *ws->hash, 0 ); 90 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
95 104
96 if( !exactmatch ) { 105 if( !exactmatch ) {
97 /* Create a new torrent entry, then */ 106 /* Create a new torrent entry, then */
107 byte_zero( torrent, sizeof(ot_torrent));
98 memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) ); 108 memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) );
99 109
100 if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { 110 if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) ||
111 !( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) {
101 vector_remove_torrent( torrents_list, torrent ); 112 vector_remove_torrent( torrents_list, torrent );
102 mutex_bucket_unlock_by_hash( *ws->hash, 0 ); 113 mutex_bucket_unlock_by_hash( *ws->hash, 0 );
103 return 0; 114 return 0;
104 } 115 }
105 116
106 byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); 117 byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) );
118 byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) );
107 delta_torrentcount = 1; 119 delta_torrentcount = 1;
108 } else 120 } else
109 clean_single_torrent( torrent ); 121 clean_single_torrent( torrent );
110 122
111 torrent->peer_list->base = g_now_minutes; 123 torrent->peer_list6->base = g_now_minutes;
124 torrent->peer_list4->base = g_now_minutes;
125
126 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
112 127
113 /* Check for peer in torrent */ 128 /* Check for peer in torrent */
114 peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), &ws->peer, &exactmatch ); 129 peer_dest = vector_find_or_insert_peer( &(peer_list->peers), peer_src, peer_size, &exactmatch );
115 if( !peer_dest ) { 130 if( !peer_dest ) {
116 mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); 131 mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
117 return 0; 132 return 0;
118 } 133 }
119 134
120 /* Tell peer that it's fresh */ 135 /* Tell peer that it's fresh */
121 OT_PEERTIME( &ws->peer ) = 0; 136 OT_PEERTIME( ws->peer, OT_PEER_SIZE6 ) = 0;
122 137
123 /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ 138 /* Sanitize flags: Whoever claims to have completed download, must be a seeder */
124 if( ( OT_PEERFLAG( &ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) 139 if( ( OT_PEERFLAG( ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
125 OT_PEERFLAG( &ws->peer ) ^= PEER_FLAG_COMPLETED; 140 OT_PEERFLAG( ws->peer ) ^= PEER_FLAG_COMPLETED;
126 141
127 /* If we hadn't had a match create peer there */ 142 /* If we hadn't had a match create peer there */
128 if( !exactmatch ) { 143 if( !exactmatch ) {
129 144
130#ifdef WANT_SYNC_LIVE 145#ifdef WANT_SYNC_LIVE
131 if( proto == FLAG_MCA ) 146 if( proto == FLAG_MCA )
132 OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_FROM_SYNC; 147 OT_PEERFLAG( ws->peer ) |= PEER_FLAG_FROM_SYNC;
133 else 148 else
134 livesync_tell( ws ); 149 livesync_tell( ws );
135#endif 150#endif
136 151
137 torrent->peer_list->peer_count++; 152 peer_list->peer_count++;
138 if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) { 153 if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_COMPLETED ) {
139 torrent->peer_list->down_count++; 154 peer_list->down_count++;
140 stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws ); 155 stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
141 } 156 }
142 if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) 157 if( OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING )
143 torrent->peer_list->seed_count++; 158 peer_list->seed_count++;
144 159
145 } else { 160 } else {
146 stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest ) ); 161 stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest, peer_size ) );
147#ifdef WANT_SPOT_WOODPECKER 162#ifdef WANT_SPOT_WOODPECKER
148 if( ( OT_PEERTIME(peer_dest) > 0 ) && ( OT_PEERTIME(peer_dest) < 20 ) ) 163 if( ( OT_PEERTIME(peer_dest, peer_size) > 0 ) && ( OT_PEERTIME(peer_dest, peer_size) < 20 ) )
149 stats_issue_event( EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer ); 164 stats_issue_event( EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer );
150#endif 165#endif
151#ifdef WANT_SYNC_LIVE 166#ifdef WANT_SYNC_LIVE
152 /* Won't live sync peers that come back too fast. Only exception: 167 /* Won't live sync peers that come back too fast. Only exception:
153 fresh "completed" reports */ 168 fresh "completed" reports */
154 if( proto != FLAG_MCA ) { 169 if( proto != FLAG_MCA ) {
155 if( OT_PEERTIME( peer_dest ) > OT_CLIENT_SYNC_RENEW_BOUNDARY || 170 if( OT_PEERTIME( peer_dest, peer_size ) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
156 ( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) ) 171 ( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) )
157 livesync_tell( ws ); 172 livesync_tell( ws );
158 } 173 }
159#endif 174#endif
160 175
161 if( (OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) ) 176 if( (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) )
162 torrent->peer_list->seed_count--; 177 peer_list->seed_count--;
163 if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) ) 178 if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) )
164 torrent->peer_list->seed_count++; 179 peer_list->seed_count++;
165 if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) { 180 if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) {
166 torrent->peer_list->down_count++; 181 peer_list->down_count++;
167 stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws ); 182 stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
168 } 183 }
169 if( OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) 184 if( OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED )
170 OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; 185 OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED;
171 } 186 }
172 187
173 memcpy( peer_dest, &ws->peer, sizeof(ot_peer) ); 188 memcpy( peer_dest, peer_src, peer_size );
174#ifdef WANT_SYNC 189#ifdef WANT_SYNC
175 if( proto == FLAG_MCA ) { 190 if( proto == FLAG_MCA ) {
176 mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); 191 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
183 return ws->reply_size; 198 return ws->reply_size;
184} 199}
185 200
186static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) { 201static size_t return_peers_all( ot_peerlist *peer_list, size_t peer_size, char *reply ) {
187 unsigned int bucket, num_buckets = 1; 202 unsigned int bucket, num_buckets = 1;
188 ot_vector * bucket_list = &peer_list->peers; 203 ot_vector * bucket_list = &peer_list->peers;
189 size_t result = OT_PEER_COMPARE_SIZE * peer_list->peer_count; 204 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
205 size_t result = compare_size * peer_list->peer_count;
190 char * r_end = reply + result; 206 char * r_end = reply + result;
191 207
192 if( OT_PEERLIST_HASBUCKETS(peer_list) ) { 208 if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
@@ -195,28 +211,30 @@ static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) {
195 } 211 }
196 212
197 for( bucket = 0; bucket<num_buckets; ++bucket ) { 213 for( bucket = 0; bucket<num_buckets; ++bucket ) {
198 ot_peer * peers = (ot_peer*)bucket_list[bucket].data; 214 ot_peer *peers = bucket_list[bucket].data;
199 size_t peer_count = bucket_list[bucket].size; 215 size_t peer_count = bucket_list[bucket].size;
200 while( peer_count-- ) { 216 while( peer_count-- ) {
201 if( OT_PEERFLAG(peers) & PEER_FLAG_SEEDING ) { 217 if( OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING ) {
202 r_end-=OT_PEER_COMPARE_SIZE; 218 r_end -= peer_size;
203 memcpy(r_end,peers++,OT_PEER_COMPARE_SIZE); 219 memcpy( r_end, peers, compare_size);
204 } else { 220 } else {
205 memcpy(reply,peers++,OT_PEER_COMPARE_SIZE); 221 memcpy( reply, peers, compare_size );
206 reply+=OT_PEER_COMPARE_SIZE; 222 reply += compare_size;
207 } 223 }
224 peers += peer_size;
208 } 225 }
209 } 226 }
210 return result; 227 return result;
211} 228}
212 229
213static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *peer_list, size_t amount, char *reply ) { 230static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply ) {
214 unsigned int bucket_offset, bucket_index = 0, num_buckets = 1; 231 unsigned int bucket_offset, bucket_index = 0, num_buckets = 1;
215 ot_vector * bucket_list = &peer_list->peers; 232 ot_vector * bucket_list = &peer_list->peers;
216 unsigned int shifted_pc = peer_list->peer_count; 233 unsigned int shifted_pc = peer_list->peer_count;
217 unsigned int shifted_step = 0; 234 unsigned int shifted_step = 0;
218 unsigned int shift = 0; 235 unsigned int shift = 0;
219 size_t result = OT_PEER_COMPARE_SIZE * amount; 236 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
237 size_t result = compare_size * amount;
220 char * r_end = reply + result; 238 char * r_end = reply + result;
221 239
222 if( OT_PEERLIST_HASBUCKETS(peer_list) ) { 240 if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
@@ -235,7 +253,7 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
235 bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count; 253 bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count;
236 254
237 while( amount-- ) { 255 while( amount-- ) {
238 ot_peer * peer; 256 ot_peer *peer;
239 257
240 /* This is the aliased, non shifted range, next value may fall into */ 258 /* This is the aliased, non shifted range, next value may fall into */
241 unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) - 259 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
246 bucket_offset -= bucket_list[bucket_index].size; 264 bucket_offset -= bucket_list[bucket_index].size;
247 bucket_index = ( bucket_index + 1 ) % num_buckets; 265 bucket_index = ( bucket_index + 1 ) % num_buckets;
248 } 266 }
249 peer = ((ot_peer*)bucket_list[bucket_index].data) + bucket_offset; 267 peer = bucket_list[bucket_index].data + peer_size * bucket_offset;
250 if( OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) { 268 if( OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING ) {
251 r_end-=OT_PEER_COMPARE_SIZE; 269 r_end -= compare_size;
252 memcpy(r_end,peer,OT_PEER_COMPARE_SIZE); 270 memcpy(r_end, peer, compare_size);
253 } else { 271 } else {
254 memcpy(reply,peer,OT_PEER_COMPARE_SIZE); 272 memcpy(reply, peer, compare_size);
255 reply+=OT_PEER_COMPARE_SIZE; 273 reply += compare_size;
256 } 274 }
257 } 275 }
258 return result; 276 return result;
@@ -267,15 +285,17 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
267 * Does not yet check not to return self 285 * Does not yet check not to return self
268*/ 286*/
269size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) { 287size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) {
270 ot_peerlist *peer_list = torrent->peer_list; 288 size_t peer_size = peer_size_from_peer6(&ws->peer);
289 ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
271 char *r = reply; 290 char *r = reply;
291 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
272 292
273 if( amount > peer_list->peer_count ) 293 if( amount > peer_list->peer_count )
274 amount = peer_list->peer_count; 294 amount = peer_list->peer_count;
275 295
276 if( proto == FLAG_TCP ) { 296 if( proto == FLAG_TCP ) {
277 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; 297 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
278 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 ); 298 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 );
279 } else { 299 } else {
280 *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); 300 *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
281 *(uint32_t*)(r+4) = htonl( peer_list->peer_count - peer_list->seed_count ); 301 *(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,
285 305
286 if( amount ) { 306 if( amount ) {
287 if( amount == peer_list->peer_count ) 307 if( amount == peer_list->peer_count )
288 r += return_peers_all( peer_list, r ); 308 r += return_peers_all( peer_list, peer_size, r );
289 else 309 else
290 r += return_peers_selection( ws, peer_list, amount, r ); 310 r += return_peers_selection( ws, peer_list, peer_size, amount, r );
291 } 311 }
292 312
293 if( proto == FLAG_TCP ) 313 if( proto == FLAG_TCP )
@@ -312,9 +332,10 @@ size_t return_udp_scrape_for_torrent( ot_hash hash, char *reply ) {
312 memset( reply, 0, 12); 332 memset( reply, 0, 12);
313 delta_torrentcount = -1; 333 delta_torrentcount = -1;
314 } else { 334 } else {
315 r[0] = htonl( torrent->peer_list->seed_count ); 335 r[0] = htonl( torrent->peer_list6->seed_count + torrent->peer_list4->seed_count );
316 r[1] = htonl( torrent->peer_list->down_count ); 336 r[1] = htonl( torrent->peer_list6->down_count + torrent->peer_list4->down_count );
317 r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); 337 r[2] = htonl( torrent->peer_list6->peer_count + torrent->peer_list4->peer_count -
338 torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
318 } 339 }
319 } 340 }
320 mutex_bucket_unlock_by_hash( hash, delta_torrentcount ); 341 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
342 *r++='2';*r++='0';*r++=':'; 363 *r++='2';*r++='0';*r++=':';
343 memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash); 364 memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash);
344 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", 365 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee",
345 torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ); 366 torrent->peer_list6->seed_count + torrent->peer_list4->seed_count,
367 torrent->peer_list6->down_count + torrent->peer_list4->down_count,
368 torrent->peer_list6->peer_count + torrent->peer_list4->peer_count -
369 torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
346 } 370 }
347 } 371 }
348 mutex_bucket_unlock_by_hash( *hash, delta_torrentcount ); 372 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 ) {
358 ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); 382 ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
359 ot_torrent *torrent = binary_search( ws->hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); 383 ot_torrent *torrent = binary_search( ws->hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
360 ot_peerlist *peer_list = &dummy_list; 384 ot_peerlist *peer_list = &dummy_list;
385 size_t peer_size; /* initialized in next line */
386 ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size);
361 387
362#ifdef WANT_SYNC_LIVE 388#ifdef WANT_SYNC_LIVE
363 if( proto != FLAG_MCA ) { 389 if( proto != FLAG_MCA ) {
364 OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; 390 OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED;
365 livesync_tell( ws ); 391 livesync_tell( ws );
366 } 392 }
367#endif 393#endif
368 394
369 if( exactmatch ) { 395 if( exactmatch ) {
370 peer_list = torrent->peer_list; 396 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
371 switch( vector_remove_peer( &peer_list->peers, &ws->peer ) ) { 397 switch( vector_remove_peer( &peer_list->peers, peer_src, peer_size ) ) {
372 case 2: peer_list->seed_count--; /* Intentional fallthrough */ 398 case 2: peer_list->seed_count--; /* Intentional fallthrough */
373 case 1: peer_list->peer_count--; /* Intentional fallthrough */ 399 case 1: peer_list->peer_count--; /* Intentional fallthrough */
374 default: break; 400 default: break;
@@ -377,7 +403,7 @@ size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) {
377 403
378 if( proto == FLAG_TCP ) { 404 if( proto == FLAG_TCP ) {
379 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; 405 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
380 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 ); 406 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 );
381 } 407 }
382 408
383 /* Handle UDP reply */ 409 /* Handle UDP reply */
@@ -409,6 +435,23 @@ void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data
409 } 435 }
410} 436}
411 437
438ot_peer *peer_from_peer6( ot_peer6 *peer, size_t *peer_size ) {
439 ot_ip6 *ip = (ot_ip6*)peer;
440 if( !ip6_isv4mapped(ip) ) {
441 *peer_size = OT_PEER_SIZE6;
442 return (ot_peer*)peer;
443 }
444 *peer_size = OT_PEER_SIZE4;
445 return (ot_peer*)(((uint8_t*)peer) + 12);
446}
447
448size_t peer_size_from_peer6(ot_peer6 *peer) {
449 ot_ip6 *ip = (ot_ip6*)peer;
450 if( !ip6_isv4mapped(ip))
451 return OT_PEER_SIZE6;
452 return OT_PEER_SIZE4;
453}
454
412void exerr( char * message ) { 455void exerr( char * message ) {
413 fprintf( stderr, "%s\n", message ); 456 fprintf( stderr, "%s\n", message );
414 exit( 111 ); 457 exit( 111 );
@@ -440,7 +483,8 @@ void trackerlogic_deinit( void ) {
440 if( torrents_list->size ) { 483 if( torrents_list->size ) {
441 for( j=0; j<torrents_list->size; ++j ) { 484 for( j=0; j<torrents_list->size; ++j ) {
442 ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j; 485 ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j;
443 free_peerlist( torrent->peer_list ); 486 free_peerlist( torrent->peer_list6 );
487 free_peerlist( torrent->peer_list4 );
444 delta_torrentcount -= 1; 488 delta_torrentcount -= 1;
445 } 489 }
446 free( torrents_list->data ); 490 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;
24typedef char ot_ip6[16]; 24typedef char ot_ip6[16];
25typedef struct { ot_ip6 address; int bits; } 25typedef struct { ot_ip6 address; int bits; }
26 ot_net; 26 ot_net;
27#ifdef WANT_V6
28#define OT_IP_SIZE 16
29#define PEERS_BENCODED "6:peers6"
30/* List of peers should fit in a single UDP packet (around 1200 bytes) */ 27/* List of peers should fit in a single UDP packet (around 1200 bytes) */
31#define OT_MAX_PEERS_UDP 66 28#define OT_MAX_PEERS_UDP6 66
32#else 29#define OT_MAX_PEERS_UDP4 200
33#define OT_IP_SIZE 4 30
34#define PEERS_BENCODED "5:peers" 31#define OT_IP_SIZE6 16
35#define OT_MAX_PEERS_UDP 200 32#define OT_IP_SIZE4 4
36#endif
37#define OT_PORT_SIZE 2 33#define OT_PORT_SIZE 2
38#define OT_FLAG_SIZE 1 34#define OT_FLAG_SIZE 1
39#define OT_TIME_SIZE 1 35#define OT_TIME_SIZE 1
@@ -61,6 +57,7 @@ typedef struct { ot_ip6 address; int bits; }
61#define OT_ADMINIP_MAX 64 57#define OT_ADMINIP_MAX 64
62#define OT_MAX_THREADS 64 58#define OT_MAX_THREADS 64
63 59
60/* Number of minutes after announce before peer is removed */
64#define OT_PEER_TIMEOUT 45 61#define OT_PEER_TIMEOUT 45
65 62
66/* We maintain a list of 1024 pointers to sorted list of ot_torrent structs 63/* We maintain a list of 1024 pointers to sorted list of ot_torrent structs
@@ -78,23 +75,35 @@ extern volatile int g_opentracker_running;
78extern uint32_t g_tracker_id; 75extern uint32_t g_tracker_id;
79typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG; 76typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG;
80 77
81#define OT_PEER_COMPARE_SIZE ((OT_IP_SIZE)+(OT_PORT_SIZE)) 78#define OT_PEER_COMPARE_SIZE6 ((OT_IP_SIZE6)+(OT_PORT_SIZE))
82#define OT_PEER_SIZE ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE)) 79#define OT_PEER_COMPARE_SIZE4 ((OT_IP_SIZE4)+(OT_PORT_SIZE))
83typedef uint8_t ot_peer[OT_PEER_SIZE]; 80#define OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(PEER_SIZE) ((PEER_SIZE)-(OT_TIME_SIZE)-(OT_FLAG_SIZE))
81
82#define OT_PEER_SIZE6 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE6))
83#define OT_PEER_SIZE4 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE4))
84
85typedef uint8_t ot_peer[1];
86typedef uint8_t ot_peer6[OT_PEER_SIZE6];
87typedef uint8_t ot_peer4[OT_PEER_SIZE4];
84static const uint8_t PEER_FLAG_SEEDING = 0x80; 88static const uint8_t PEER_FLAG_SEEDING = 0x80;
85static const uint8_t PEER_FLAG_COMPLETED = 0x40; 89static const uint8_t PEER_FLAG_COMPLETED = 0x40;
86static const uint8_t PEER_FLAG_STOPPED = 0x20; 90static const uint8_t PEER_FLAG_STOPPED = 0x20;
87static const uint8_t PEER_FLAG_FROM_SYNC = 0x10; 91static const uint8_t PEER_FLAG_FROM_SYNC = 0x10;
88static const uint8_t PEER_FLAG_LEECHING = 0x00; 92static const uint8_t PEER_FLAG_LEECHING = 0x00;
89 93
90#ifdef WANT_V6 94/* Takes an ot_peer6 and returns the proper pointer to the peer and sets peer_size */
91#define OT_SETIP(peer,ip) memcpy((peer),(ip),(OT_IP_SIZE)) 95ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size);
92#else 96size_t peer_size_from_peer6(ot_peer6 *peer);
93#define OT_SETIP(peer,ip) memcpy((peer),(((uint8_t*)ip)+12),(OT_IP_SIZE)) 97
94#endif 98/* New style */
95#define OT_SETPORT(peer,port) memcpy(((uint8_t*)(peer))+(OT_IP_SIZE),(port),2) 99#define OT_SETIP(peer,ip) memcpy((peer),(ip),OT_IP_SIZE6)
96#define OT_PEERFLAG(peer) (((uint8_t*)(peer))[(OT_IP_SIZE)+2]) 100#define OT_SETPORT(peer,port) memcpy(((uint8_t*)(peer))+(OT_IP_SIZE6),(port),2)
97#define OT_PEERTIME(peer) (((uint8_t*)(peer))[(OT_IP_SIZE)+3]) 101#define OT_PEERFLAG(peer) (((uint8_t*)(peer))[(OT_IP_SIZE6)+2])
102#define OT_PEERFLAG_D(peer,peersize) (((uint8_t*)(peer))[(peersize)-2])
103#define OT_PEERTIME(peer,peersize) (((uint8_t*)(peer))[(peersize)-1])
104
105#define PEERS_BENCODED6 "6:peers6"
106#define PEERS_BENCODED4 "5:peers"
98 107
99#define OT_HASH_COMPARE_SIZE (sizeof(ot_hash)) 108#define OT_HASH_COMPARE_SIZE (sizeof(ot_hash))
100 109
@@ -102,7 +111,8 @@ struct ot_peerlist;
102typedef struct ot_peerlist ot_peerlist; 111typedef struct ot_peerlist ot_peerlist;
103typedef struct { 112typedef struct {
104 ot_hash hash; 113 ot_hash hash;
105 ot_peerlist *peer_list; 114 ot_peerlist *peer_list6;
115 ot_peerlist *peer_list4;
106} ot_torrent; 116} ot_torrent;
107 117
108#include "ot_vector.h" 118#include "ot_vector.h"
@@ -131,7 +141,7 @@ struct ot_workstruct {
131#endif 141#endif
132 142
133 /* The peer currently in the working */ 143 /* The peer currently in the working */
134 ot_peer peer; 144 ot_peer6 peer; /* Can fit v6 and v4 peers */
135 145
136 /* Pointers into the request buffer */ 146 /* Pointers into the request buffer */
137 ot_hash *hash; 147 ot_hash *hash;