1 /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
10 #include <arpa/inet.h>
23 #include "trackerlogic.h"
24 #include "ot_vector.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
);
41 free( peer_list
->peers
.data
);
46 void add_torrent_from_saved_state( ot_hash
const hash
, ot_time base
, size_t down_count
) {
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;
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
);
97 torrent
= vector_find_or_insert( torrents_list
, (void*)ws
->hash
, sizeof( ot_torrent
), OT_HASH_COMPARE_SIZE
, &exactmatch
);
99 mutex_bucket_unlock_by_hash( *ws
->hash
, 0 );
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 );
115 byte_zero( torrent
->peer_list6
, sizeof( ot_peerlist
) );
116 byte_zero( torrent
->peer_list4
, sizeof( ot_peerlist
) );
117 delta_torrentcount
= 1;
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
);
129 mutex_bucket_unlock_by_hash( *ws
->hash
, delta_torrentcount
);
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 */
143 #ifdef WANT_SYNC_LIVE
144 if( proto
== FLAG_MCA
)
145 OT_PEERFLAG( ws
->peer
) |= PEER_FLAG_FROM_SYNC
;
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
++;
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
);
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
) ) )
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
);
188 if( proto
== FLAG_MCA
) {
189 mutex_bucket_unlock_by_hash( *ws
->hash
, delta_torrentcount
);
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
);
219 memcpy( reply
, peers
, compare_size
);
220 reply
+= compare_size
;
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
;
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
;
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
);
270 memcpy(reply
, peer
, compare_size
);
271 reply
+= compare_size
;
277 static size_t return_peers_for_torrent_udp( struct ot_workstruct
* ws
, ot_torrent
*torrent
, size_t amount
, char *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
);
293 if( amount
== peer_list
->peer_count
)
294 r
+= return_peers_all( peer_list
, peer_size
, r
);
296 r
+= return_peers_selection( ws
, peer_list
, peer_size
, amount
, r
);
301 static size_t return_peers_for_torrent_tcp( struct ot_workstruct
* ws
, ot_torrent
*torrent
, size_t amount
, char *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
)
340 if( amount_v4
+ amount_v6
< amount
&& amount_v4
< torrent
->peer_list4
->peer_count
)
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 );
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
);
351 r
+= return_peers_selection( ws
, torrent
->peer_list4
, OT_PEER_SIZE4
, amount_v4
, r
);
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
);
359 r
+= return_peers_selection( ws
, torrent
->peer_list6
, OT_PEER_SIZE6
, amount_v6
, r
);
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
);
386 memset( reply
, 0, 12);
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;
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
);
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
) {
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
);
419 if( clean_single_torrent( torrent
) ) {
420 vector_remove_torrent( torrents_list
, torrent
);
421 delta_torrentcount
= -1;
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';
439 static ot_peerlist dummy_list
;
440 size_t remove_peer_from_torrent( PROTO_FLAG proto
, struct ot_workstruct
*ws
) {
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
;
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 */
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
);
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
) {
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
) )
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
);
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 );
544 void exerr( char * message
) {
545 fprintf( stderr
, "%s\n", message
);
549 void trackerlogic_init( ) {
550 g_tracker_id
= random();
553 g_stats_path
= "stats";
554 g_stats_path_len
= strlen( g_stats_path
);
556 /* Initialise background worker threads */
565 void trackerlogic_deinit( void ) {
566 int bucket
, delta_torrentcount
= 0;
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 */
587 accesslist_deinit( );
588 fullscrape_deinit( );
590 /* Release mutexes */
594 const char *g_version_trackerlogic_c
= "$Source$: $Revision$\n";