Make chunked transfers use gzip also
[opentracker.git] / trackerlogic.c
blobe2ac5b3af64e1c6ce8cbff13d8aeb0e4e243d571
1 /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
4 $id$ */
6 /* System */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <arpa/inet.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <stdint.h>
15 /* Libowfat */
16 #include "byte.h"
17 #include "io.h"
18 #include "iob.h"
19 #include "ip6.h"
20 #include "array.h"
22 /* Opentracker */
23 #include "trackerlogic.h"
24 #include "ot_vector.h"
25 #include "ot_mutex.h"
26 #include "ot_stats.h"
27 #include "ot_clean.h"
28 #include "ot_http.h"
29 #include "ot_accesslist.h"
30 #include "ot_fullscrape.h"
31 #include "ot_livesync.h"
33 /* Forward declaration */
34 size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto );
36 void free_peerlist( ot_peerlist *peer_list ) {
37 if( peer_list->peers.data ) {
38 if( OT_PEERLIST_HASBUCKETS( peer_list ) )
39 vector_clean_list( (ot_vector*)peer_list->peers.data, peer_list->peers.size );
40 else
41 free( peer_list->peers.data );
43 free( peer_list );
46 void add_torrent_from_saved_state( ot_hash const hash, ot_time base, size_t down_count ) {
47 int exactmatch;
48 ot_torrent *torrent;
49 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
51 if( !accesslist_hashisvalid( hash ) )
52 return mutex_bucket_unlock_by_hash( hash, 0 );
54 torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
55 if( !torrent || exactmatch )
56 return mutex_bucket_unlock_by_hash( hash, 0 );
58 /* Create a new torrent entry, then */
59 byte_zero( torrent, sizeof( ot_torrent ) );
60 memcpy( torrent->hash, hash, sizeof(ot_hash) );
62 if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) ||
63 !( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) {
64 vector_remove_torrent( torrents_list, torrent );
65 return mutex_bucket_unlock_by_hash( hash, 0 );
68 byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) );
69 byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) );
70 torrent->peer_list6->base = base;
71 torrent->peer_list4->base = base;
72 torrent->peer_list6->down_count = down_count;
73 torrent->peer_list4->down_count = down_count;
75 return mutex_bucket_unlock_by_hash( hash, 1 );
78 size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) {
79 int exactmatch, delta_torrentcount = 0;
80 ot_torrent *torrent;
81 ot_peer *peer_dest;
82 ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
83 ot_peerlist *peer_list;
84 size_t peer_size; /* initialized in next line */
85 ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
87 if( !accesslist_hashisvalid( *ws->hash ) ) {
88 mutex_bucket_unlock_by_hash( *ws->hash, 0 );
89 if( proto == FLAG_TCP ) {
90 const char invalid_hash[] = "d14:failure reason63:Requested download is not authorized for use with this tracker.e";
91 memcpy( ws->reply, invalid_hash, strlen( invalid_hash ) );
92 return strlen( invalid_hash );
94 return 0;
97 torrent = vector_find_or_insert( torrents_list, (void*)ws->hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
98 if( !torrent ) {
99 mutex_bucket_unlock_by_hash( *ws->hash, 0 );
100 return 0;
103 if( !exactmatch ) {
104 /* Create a new torrent entry, then */
105 byte_zero( torrent, sizeof(ot_torrent));
106 memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) );
108 if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) ||
109 !( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) {
110 vector_remove_torrent( torrents_list, torrent );
111 mutex_bucket_unlock_by_hash( *ws->hash, 0 );
112 return 0;
115 byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) );
116 byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) );
117 delta_torrentcount = 1;
118 } else
119 clean_single_torrent( torrent );
121 torrent->peer_list6->base = g_now_minutes;
122 torrent->peer_list4->base = g_now_minutes;
124 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
126 /* Check for peer in torrent */
127 peer_dest = vector_find_or_insert_peer( &(peer_list->peers), peer_src, peer_size, &exactmatch );
128 if( !peer_dest ) {
129 mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
130 return 0;
133 /* Tell peer that it's fresh */
134 OT_PEERTIME( ws->peer, OT_PEER_SIZE6 ) = 0;
136 /* Sanitize flags: Whoever claims to have completed download, must be a seeder */
137 if( ( OT_PEERFLAG( ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
138 OT_PEERFLAG( ws->peer ) ^= PEER_FLAG_COMPLETED;
140 /* If we hadn't had a match create peer there */
141 if( !exactmatch ) {
143 #ifdef WANT_SYNC_LIVE
144 if( proto == FLAG_MCA )
145 OT_PEERFLAG( ws->peer ) |= PEER_FLAG_FROM_SYNC;
146 else
147 livesync_tell( ws );
148 #endif
150 peer_list->peer_count++;
151 if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_COMPLETED ) {
152 peer_list->down_count++;
153 stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
155 if( OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING )
156 peer_list->seed_count++;
158 } else {
159 stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest, peer_size ) );
160 #ifdef WANT_SPOT_WOODPECKER
161 if( ( OT_PEERTIME(peer_dest, peer_size) > 0 ) && ( OT_PEERTIME(peer_dest, peer_size) < 20 ) )
162 stats_issue_event( EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer );
163 #endif
164 #ifdef WANT_SYNC_LIVE
165 /* Won't live sync peers that come back too fast. Only exception:
166 fresh "completed" reports */
167 if( proto != FLAG_MCA ) {
168 if( OT_PEERTIME( peer_dest, peer_size ) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
169 ( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) )
170 livesync_tell( ws );
172 #endif
174 if( (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) )
175 peer_list->seed_count--;
176 if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) )
177 peer_list->seed_count++;
178 if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) {
179 peer_list->down_count++;
180 stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
182 if( OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED )
183 OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED;
186 memcpy( peer_dest, peer_src, peer_size );
187 #ifdef WANT_SYNC
188 if( proto == FLAG_MCA ) {
189 mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
190 return 0;
192 #endif
194 ws->reply_size = return_peers_for_torrent( ws, torrent, amount, ws->reply, proto );
195 mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
196 return ws->reply_size;
199 static size_t return_peers_all( ot_peerlist *peer_list, size_t peer_size, char *reply ) {
200 unsigned int bucket, num_buckets = 1;
201 ot_vector * bucket_list = &peer_list->peers;
202 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
203 size_t result = compare_size * peer_list->peer_count;
204 char * r_end = reply + result;
206 if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
207 num_buckets = bucket_list->size;
208 bucket_list = (ot_vector *)bucket_list->data;
211 for( bucket = 0; bucket<num_buckets; ++bucket ) {
212 ot_peer *peers = bucket_list[bucket].data;
213 size_t peer_count = bucket_list[bucket].size;
214 while( peer_count-- ) {
215 if( OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING ) {
216 r_end -= compare_size;
217 memcpy( r_end, peers, compare_size);
218 } else {
219 memcpy( reply, peers, compare_size );
220 reply += compare_size;
222 peers += peer_size;
225 return result;
228 static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply ) {
229 unsigned int bucket_offset, bucket_index = 0, num_buckets = 1;
230 ot_vector * bucket_list = &peer_list->peers;
231 unsigned int shifted_pc = peer_list->peer_count;
232 unsigned int shifted_step = 0;
233 unsigned int shift = 0;
234 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
235 size_t result = compare_size * amount;
236 char * r_end = reply + result;
238 if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
239 num_buckets = bucket_list->size;
240 bucket_list = (ot_vector *)bucket_list->data;
243 /* Make fixpoint arithmetic as exact as possible */
244 #define MAXPRECBIT (1<<(8*sizeof(int)-3))
245 while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; }
246 shifted_step = shifted_pc/amount;
247 #undef MAXPRECBIT
249 /* Initialize somewhere in the middle of peers so that
250 fixpoint's aliasing doesn't alway miss the same peers */
251 bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count;
253 while( amount-- ) {
254 ot_peer *peer;
256 /* This is the aliased, non shifted range, next value may fall into */
257 unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) -
258 ( ( amount * shifted_step ) >> shift );
259 bucket_offset += 1 + nrand48(ws->rand48_state) % diff;
261 while( bucket_offset >= bucket_list[bucket_index].size ) {
262 bucket_offset -= bucket_list[bucket_index].size;
263 bucket_index = ( bucket_index + 1 ) % num_buckets;
265 peer = bucket_list[bucket_index].data + peer_size * bucket_offset;
266 if( OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING ) {
267 r_end -= compare_size;
268 memcpy(r_end, peer, compare_size);
269 } else {
270 memcpy(reply, peer, compare_size);
271 reply += compare_size;
274 return result;
277 static size_t return_peers_for_torrent_udp( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply ) {
278 char *r = reply;
279 size_t peer_size = peer_size_from_peer6(&ws->peer);
280 ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
281 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
282 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
284 if( amount > peer_list->peer_count )
285 amount = peer_list->peer_count;
287 *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
288 *(uint32_t*)(r+4) = htonl( peer_count - seed_count );
289 *(uint32_t*)(r+8) = htonl( seed_count );
290 r += 12;
292 if( amount ) {
293 if( amount == peer_list->peer_count )
294 r += return_peers_all( peer_list, peer_size, r );
295 else
296 r += return_peers_selection( ws, peer_list, peer_size, amount, r );
298 return r - reply;
301 static size_t return_peers_for_torrent_tcp( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply ) {
302 char *r = reply;
303 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
304 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
305 size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count;
306 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - seed_count;
308 /* Simple case: amount of peers in both lists is less than requested, here we return all results */
309 size_t amount_v4 = torrent->peer_list4->peer_count;
310 size_t amount_v6 = torrent->peer_list6->peer_count;
312 /* Complex case: both lists have more than enough entries and we need to split between v4 and v6 clients */
313 if( amount_v4 + amount_v6 > amount ) {
314 size_t amount_left, percent_v6 = 0, percent_v4 = 0, left_v6, left_v4;
315 const size_t SCALE = 1024;
317 /* If possible, fill at least a quarter of peer from each family */
318 if( amount / 4 <= amount_v4 )
319 amount_v4 = amount / 4;
320 if( amount / 4 <= amount_v6 )
321 amount_v6 = amount / 4;
323 /* Fill the rest according to which family's pool provides more peers */
324 amount_left = amount - (amount_v4 + amount_v6);
326 left_v4 = torrent->peer_list4->peer_count - amount_v4;
327 left_v6 = torrent->peer_list6->peer_count - amount_v6;
329 if( left_v4 + left_v6 ) {
330 percent_v4 = (SCALE * left_v4) / (left_v4 + left_v6);
331 percent_v6 = (SCALE * left_v6) / (left_v4 + left_v6);
334 amount_v4 += (amount_left * percent_v4) / SCALE;
335 amount_v6 += (amount_left * percent_v6) / SCALE;
337 /* Integer division rounding can leave out a peer */
338 if( amount_v4 + amount_v6 < amount && amount_v6 < torrent->peer_list6->peer_count )
339 ++amount_v6;
340 if( amount_v4 + amount_v6 < amount && amount_v4 < torrent->peer_list4->peer_count )
341 ++amount_v4;
344 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie", seed_count, down_count, peer_count, erval, erval/2 );
346 if( amount_v4 ) {
347 r += sprintf( r, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4);
348 if( amount_v4 == torrent->peer_list4->peer_count )
349 r += return_peers_all( torrent->peer_list4, OT_PEER_SIZE4, r );
350 else
351 r += return_peers_selection( ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r );
354 if( amount_v6 ) {
355 r += sprintf( r, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6);
356 if( amount_v6 == torrent->peer_list6->peer_count )
357 r += return_peers_all( torrent->peer_list6, OT_PEER_SIZE6, r );
358 else
359 r += return_peers_selection( ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r );
362 *r++ = 'e';
364 return r - reply;
367 /* Compiles a list of random peers for a torrent
368 * Reply must have enough space to hold:
369 * 92 + 6 * amount bytes for TCP/IPv4
370 * 92 + 18 * amount bytes for TCP/IPv6
371 * 12 + 6 * amount bytes for UDP/IPv4
372 * 12 + 18 * amount bytes for UDP/IPv6
373 * Does not yet check not to return self
375 size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) {
376 return proto == FLAG_TCP ? return_peers_for_torrent_tcp(ws, torrent, amount, reply) : return_peers_for_torrent_udp(ws, torrent, amount, reply);
379 /* Fetches scrape info for a specific torrent */
380 size_t return_udp_scrape_for_torrent( ot_hash const hash, char *reply ) {
381 int exactmatch, delta_torrentcount = 0;
382 ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash );
383 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
385 if( !exactmatch ) {
386 memset( reply, 0, 12);
387 } else {
388 uint32_t *r = (uint32_t*) reply;
390 if( clean_single_torrent( torrent ) ) {
391 vector_remove_torrent( torrents_list, torrent );
392 memset( reply, 0, 12);
393 delta_torrentcount = -1;
394 } else {
395 r[0] = htonl( torrent->peer_list6->seed_count + torrent->peer_list4->seed_count );
396 r[1] = htonl( torrent->peer_list6->down_count + torrent->peer_list4->down_count );
397 r[2] = htonl( torrent->peer_list6->peer_count + torrent->peer_list4->peer_count -
398 torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
401 mutex_bucket_unlock_by_hash( hash, delta_torrentcount );
402 return 12;
405 /* Fetches scrape info for a specific torrent */
406 size_t return_tcp_scrape_for_torrent( ot_hash const *hash_list, int amount, char *reply ) {
407 char *r = reply;
408 int exactmatch, i;
410 r += sprintf( r, "d5:filesd" );
412 for( i=0; i<amount; ++i ) {
413 int delta_torrentcount = 0;
414 ot_hash const *hash = hash_list + i;
415 ot_vector *torrents_list = mutex_bucket_lock_by_hash( *hash );
416 ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
418 if( exactmatch ) {
419 if( clean_single_torrent( torrent ) ) {
420 vector_remove_torrent( torrents_list, torrent );
421 delta_torrentcount = -1;
422 } else {
423 *r++='2';*r++='0';*r++=':';
424 memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash);
425 r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee",
426 torrent->peer_list6->seed_count + torrent->peer_list4->seed_count,
427 torrent->peer_list6->down_count + torrent->peer_list4->down_count,
428 torrent->peer_list6->peer_count + torrent->peer_list4->peer_count -
429 torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
432 mutex_bucket_unlock_by_hash( *hash, delta_torrentcount );
435 *r++ = 'e'; *r++ = 'e';
436 return r - reply;
439 static ot_peerlist dummy_list;
440 size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) {
441 int exactmatch;
442 ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
443 ot_torrent *torrent = binary_search( ws->hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
444 ot_peerlist *peer_list = &dummy_list;
445 size_t peer_size; /* initialized in next line */
446 ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
447 size_t peer_count = 0, seed_count = 0;
449 #ifdef WANT_SYNC_LIVE
450 if( proto != FLAG_MCA ) {
451 OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED;
452 livesync_tell( ws );
454 #endif
456 if( exactmatch ) {
457 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
458 switch( vector_remove_peer( &peer_list->peers, peer_src, peer_size ) ) {
459 case 2: peer_list->seed_count--; /* Intentional fallthrough */
460 case 1: peer_list->peer_count--; /* Intentional fallthrough */
461 default: break;
464 peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
465 seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
469 if( proto == FLAG_TCP ) {
470 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
471 ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s0:e", seed_count, peer_count - seed_count, erval, erval / 2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4 );
474 /* Handle UDP reply */
475 if( proto == FLAG_UDP ) {
476 ((uint32_t*)ws->reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
477 ((uint32_t*)ws->reply)[3] = htonl( peer_count - seed_count );
478 ((uint32_t*)ws->reply)[4] = htonl( seed_count);
479 ws->reply_size = 20;
482 mutex_bucket_unlock_by_hash( *ws->hash, 0 );
483 return ws->reply_size;
486 void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data ) {
487 int bucket;
488 size_t j;
490 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
491 ot_vector *torrents_list = mutex_bucket_lock( bucket );
492 ot_torrent *torrents = (ot_torrent*)(torrents_list->data);
494 for( j=0; j<torrents_list->size; ++j )
495 if( for_each( torrents + j, data ) )
496 break;
498 mutex_bucket_unlock( bucket, 0 );
499 if( !g_opentracker_running ) return;
503 ot_peer *peer_from_peer6( ot_peer6 *peer, size_t *peer_size ) {
504 ot_ip6 *ip = (ot_ip6*)peer;
505 if( !ip6_isv4mapped(ip) ) {
506 *peer_size = OT_PEER_SIZE6;
507 return (ot_peer*)peer;
509 *peer_size = OT_PEER_SIZE4;
510 return (ot_peer*)(((uint8_t*)peer) + 12);
513 size_t peer_size_from_peer6(ot_peer6 *peer) {
514 ot_ip6 *ip = (ot_ip6*)peer;
515 if( !ip6_isv4mapped(ip))
516 return OT_PEER_SIZE6;
517 return OT_PEER_SIZE4;
520 #ifdef _DEBUG_RANDOMTORRENTS
521 void trackerlogic_add_random_torrents(size_t amount) {
522 struct ot_workstruct ws;
523 memset( &ws, 0, sizeof(ws) );
525 ws.inbuf=malloc(G_INBUF_SIZE);
526 ws.outbuf=malloc(G_OUTBUF_SIZE);
527 ws.reply=ws.outbuf;
528 ws.hash=ws.inbuf;
530 while( amount-- ) {
531 arc4random_buf(ws.hash, sizeof(ot_hash));
532 arc4random_buf(&ws.peer, sizeof(ws.peer));
534 OT_PEERFLAG(ws.peer) &= PEER_FLAG_SEEDING | PEER_FLAG_COMPLETED | PEER_FLAG_STOPPED;
536 add_peer_to_torrent_and_return_peers( FLAG_TCP, &ws, 1 );
539 free(ws.inbuf);
540 free(ws.outbuf);
542 #endif
544 void exerr( char * message ) {
545 fprintf( stderr, "%s\n", message );
546 exit( 111 );
549 void trackerlogic_init( ) {
550 g_tracker_id = random();
552 if( !g_stats_path )
553 g_stats_path = "stats";
554 g_stats_path_len = strlen( g_stats_path );
556 /* Initialise background worker threads */
557 mutex_init( );
558 clean_init( );
559 fullscrape_init( );
560 accesslist_init( );
561 livesync_init( );
562 stats_init( );
565 void trackerlogic_deinit( void ) {
566 int bucket, delta_torrentcount = 0;
567 size_t j;
569 /* Free all torrents... */
570 for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
571 ot_vector *torrents_list = mutex_bucket_lock( bucket );
572 if( torrents_list->size ) {
573 for( j=0; j<torrents_list->size; ++j ) {
574 ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j;
575 free_peerlist( torrent->peer_list6 );
576 free_peerlist( torrent->peer_list4 );
577 delta_torrentcount -= 1;
579 free( torrents_list->data );
581 mutex_bucket_unlock( bucket, delta_torrentcount );
584 /* Deinitialise background worker threads */
585 stats_deinit( );
586 livesync_deinit( );
587 accesslist_deinit( );
588 fullscrape_deinit( );
589 clean_deinit( );
590 /* Release mutexes */
591 mutex_deinit( );
594 const char *g_version_trackerlogic_c = "$Source$: $Revision$\n";