Disable forced gzip by default
[opentracker.git] / trackerlogic.c
blob04df54469d7187921ebbfa816efde2b81db3e569
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 <arpa/inet.h>
8 #include <errno.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
15 /* Libowfat */
16 #include "array.h"
17 #include "byte.h"
18 #include "io.h"
19 #include "iob.h"
20 #include "ip6.h"
22 /* Opentracker */
23 #include "ot_accesslist.h"
24 #include "ot_clean.h"
25 #include "ot_fullscrape.h"
26 #include "ot_http.h"
27 #include "ot_livesync.h"
28 #include "ot_mutex.h"
29 #include "ot_stats.h"
30 #include "ot_vector.h"
31 #include "trackerlogic.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))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) {
63 vector_remove_torrent(torrents_list, torrent);
64 return mutex_bucket_unlock_by_hash(hash, 0);
67 byte_zero(torrent->peer_list6, sizeof(ot_peerlist));
68 byte_zero(torrent->peer_list4, sizeof(ot_peerlist));
69 torrent->peer_list6->base = base;
70 torrent->peer_list4->base = base;
71 torrent->peer_list6->down_count = down_count;
72 torrent->peer_list4->down_count = down_count;
74 return mutex_bucket_unlock_by_hash(hash, 1);
77 size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount) {
78 int exactmatch, delta_torrentcount = 0;
79 ot_torrent *torrent;
80 ot_peer *peer_dest;
81 ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash);
82 ot_peerlist *peer_list;
83 size_t peer_size; /* initialized in next line */
84 ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
86 if (!accesslist_hashisvalid(*ws->hash)) {
87 mutex_bucket_unlock_by_hash(*ws->hash, 0);
88 if (proto == FLAG_TCP) {
89 const char invalid_hash[] = "d14:failure reason63:Requested download is not authorized for use with this tracker.e";
90 memcpy(ws->reply, invalid_hash, strlen(invalid_hash));
91 return strlen(invalid_hash);
93 return 0;
96 torrent = vector_find_or_insert(torrents_list, (void *)ws->hash, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
97 if (!torrent) {
98 mutex_bucket_unlock_by_hash(*ws->hash, 0);
99 return 0;
102 if (!exactmatch) {
103 /* Create a new torrent entry, then */
104 byte_zero(torrent, sizeof(ot_torrent));
105 memcpy(torrent->hash, *ws->hash, sizeof(ot_hash));
107 if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) {
108 vector_remove_torrent(torrents_list, torrent);
109 mutex_bucket_unlock_by_hash(*ws->hash, 0);
110 return 0;
113 byte_zero(torrent->peer_list6, sizeof(ot_peerlist));
114 byte_zero(torrent->peer_list4, sizeof(ot_peerlist));
115 delta_torrentcount = 1;
116 } else
117 clean_single_torrent(torrent);
119 torrent->peer_list6->base = g_now_minutes;
120 torrent->peer_list4->base = g_now_minutes;
122 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
124 /* Check for peer in torrent */
125 peer_dest = vector_find_or_insert_peer(&(peer_list->peers), peer_src, peer_size, &exactmatch);
126 if (!peer_dest) {
127 mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
128 return 0;
131 /* Tell peer that it's fresh */
132 OT_PEERTIME(ws->peer, OT_PEER_SIZE6) = 0;
134 /* Sanitize flags: Whoever claims to have completed download, must be a seeder */
135 if ((OT_PEERFLAG(ws->peer) & (PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING)) == PEER_FLAG_COMPLETED)
136 OT_PEERFLAG(ws->peer) ^= PEER_FLAG_COMPLETED;
138 /* If we hadn't had a match create peer there */
139 if (!exactmatch) {
141 #ifdef WANT_SYNC_LIVE
142 if (proto == FLAG_MCA)
143 OT_PEERFLAG(ws->peer) |= PEER_FLAG_FROM_SYNC;
144 else
145 livesync_tell(ws);
146 #endif
148 peer_list->peer_count++;
149 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED) {
150 peer_list->down_count++;
151 stats_issue_event(EVENT_COMPLETED, 0, (uintptr_t)ws);
153 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING)
154 peer_list->seed_count++;
156 } else {
157 stats_issue_event(EVENT_RENEW, 0, OT_PEERTIME(peer_dest, peer_size));
158 #ifdef WANT_SPOT_WOODPECKER
159 if ((OT_PEERTIME(peer_dest, peer_size) > 0) && (OT_PEERTIME(peer_dest, peer_size) < 20))
160 stats_issue_event(EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer);
161 #endif
162 #ifdef WANT_SYNC_LIVE
163 /* Won't live sync peers that come back too fast. Only exception:
164 fresh "completed" reports */
165 if (proto != FLAG_MCA) {
166 if (OT_PEERTIME(peer_dest, peer_size) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
167 (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED)))
168 livesync_tell(ws);
170 #endif
172 if ((OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING))
173 peer_list->seed_count--;
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_COMPLETED) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED)) {
177 peer_list->down_count++;
178 stats_issue_event(EVENT_COMPLETED, 0, (uintptr_t)ws);
180 if (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED)
181 OT_PEERFLAG(ws->peer) |= PEER_FLAG_COMPLETED;
184 memcpy(peer_dest, peer_src, peer_size);
185 #ifdef WANT_SYNC
186 if (proto == FLAG_MCA) {
187 mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
188 return 0;
190 #endif
192 ws->reply_size = return_peers_for_torrent(ws, torrent, amount, ws->reply, proto);
193 mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
194 return ws->reply_size;
197 static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *reply) {
198 unsigned int bucket, num_buckets = 1;
199 ot_vector *bucket_list = &peer_list->peers;
200 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
201 size_t result = compare_size * peer_list->peer_count;
202 char *r_end = reply + result;
204 if (OT_PEERLIST_HASBUCKETS(peer_list)) {
205 num_buckets = bucket_list->size;
206 bucket_list = (ot_vector *)bucket_list->data;
209 for (bucket = 0; bucket < num_buckets; ++bucket) {
210 ot_peer *peers = bucket_list[bucket].data;
211 size_t peer_count = bucket_list[bucket].size;
212 while (peer_count--) {
213 if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING) {
214 r_end -= compare_size;
215 memcpy(r_end, peers, compare_size);
216 } else {
217 memcpy(reply, peers, compare_size);
218 reply += compare_size;
220 peers += peer_size;
223 return result;
226 static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply) {
227 unsigned int bucket_offset, bucket_index = 0, num_buckets = 1;
228 ot_vector *bucket_list = &peer_list->peers;
229 unsigned int shifted_pc = peer_list->peer_count;
230 unsigned int shifted_step = 0;
231 unsigned int shift = 0;
232 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
233 size_t result = compare_size * amount;
234 char *r_end = reply + result;
236 if (OT_PEERLIST_HASBUCKETS(peer_list)) {
237 num_buckets = bucket_list->size;
238 bucket_list = (ot_vector *)bucket_list->data;
241 /* Make fixpoint arithmetic as exact as possible */
242 #define MAXPRECBIT (1 << (8 * sizeof(int) - 3))
243 while (!(shifted_pc & MAXPRECBIT)) {
244 shifted_pc <<= 1;
245 shift++;
247 shifted_step = shifted_pc / amount;
248 #undef MAXPRECBIT
250 /* Initialize somewhere in the middle of peers so that
251 fixpoint's aliasing doesn't alway miss the same peers */
252 bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count;
254 while (amount--) {
255 ot_peer *peer;
257 /* This is the aliased, non shifted range, next value may fall into */
258 unsigned int diff = (((amount + 1) * shifted_step) >> shift) - ((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 +=
345 sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie", seed_count, down_count, peer_count, erval, erval / 2);
347 if (amount_v4) {
348 r += sprintf(r, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4);
349 if (amount_v4 == torrent->peer_list4->peer_count)
350 r += return_peers_all(torrent->peer_list4, OT_PEER_SIZE4, r);
351 else
352 r += return_peers_selection(ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r);
355 if (amount_v6) {
356 r += sprintf(r, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6);
357 if (amount_v6 == torrent->peer_list6->peer_count)
358 r += return_peers_all(torrent->peer_list6, OT_PEER_SIZE6, r);
359 else
360 r += return_peers_selection(ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r);
363 *r++ = 'e';
365 return r - reply;
368 /* Compiles a list of random peers for a torrent
369 * Reply must have enough space to hold:
370 * 92 + 6 * amount bytes for TCP/IPv4
371 * 92 + 18 * amount bytes for TCP/IPv6
372 * 12 + 6 * amount bytes for UDP/IPv4
373 * 12 + 18 * amount bytes for UDP/IPv6
374 * Does not yet check not to return self
376 size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto) {
377 return proto == FLAG_TCP ? return_peers_for_torrent_tcp(ws, torrent, amount, reply) : return_peers_for_torrent_udp(ws, torrent, amount, reply);
380 /* Fetches scrape info for a specific torrent */
381 size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply) {
382 int exactmatch, delta_torrentcount = 0;
383 ot_vector *torrents_list = mutex_bucket_lock_by_hash(hash);
384 ot_torrent *torrent = binary_search(hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
386 if (!exactmatch) {
387 memset(reply, 0, 12);
388 } else {
389 uint32_t *r = (uint32_t *)reply;
391 if (clean_single_torrent(torrent)) {
392 vector_remove_torrent(torrents_list, torrent);
393 memset(reply, 0, 12);
394 delta_torrentcount = -1;
395 } else {
396 r[0] = htonl(torrent->peer_list6->seed_count + torrent->peer_list4->seed_count);
397 r[1] = htonl(torrent->peer_list6->down_count + torrent->peer_list4->down_count);
398 r[2] = htonl(torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - 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';
424 *r++ = '0';
425 *r++ = ':';
426 memcpy(r, hash, sizeof(ot_hash));
427 r += sizeof(ot_hash);
428 r += sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", torrent->peer_list6->seed_count + torrent->peer_list4->seed_count,
429 torrent->peer_list6->down_count + torrent->peer_list4->down_count,
430 torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
433 mutex_bucket_unlock_by_hash(*hash, delta_torrentcount);
436 *r++ = 'e';
437 *r++ = 'e';
438 return r - reply;
441 static ot_peerlist dummy_list;
442 size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) {
443 int exactmatch;
444 ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash);
445 ot_torrent *torrent = binary_search(ws->hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
446 ot_peerlist *peer_list = &dummy_list;
447 size_t peer_size; /* initialized in next line */
448 ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
449 size_t peer_count = 0, seed_count = 0;
451 #ifdef WANT_SYNC_LIVE
452 if (proto != FLAG_MCA) {
453 OT_PEERFLAG(ws->peer) |= PEER_FLAG_STOPPED;
454 livesync_tell(ws);
456 #endif
458 if (exactmatch) {
459 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
460 switch (vector_remove_peer(&peer_list->peers, peer_src, peer_size)) {
461 case 2:
462 peer_list->seed_count--; /* Intentional fallthrough */
463 case 1:
464 peer_list->peer_count--; /* Intentional fallthrough */
465 default:
466 break;
469 peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
470 seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
473 if (proto == FLAG_TCP) {
474 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
475 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,
476 erval / 2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4);
479 /* Handle UDP reply */
480 if (proto == FLAG_UDP) {
481 ((uint32_t *)ws->reply)[2] = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM);
482 ((uint32_t *)ws->reply)[3] = htonl(peer_count - seed_count);
483 ((uint32_t *)ws->reply)[4] = htonl(seed_count);
484 ws->reply_size = 20;
487 mutex_bucket_unlock_by_hash(*ws->hash, 0);
488 return ws->reply_size;
491 void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data) {
492 int bucket;
493 size_t j;
495 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
496 ot_vector *torrents_list = mutex_bucket_lock(bucket);
497 ot_torrent *torrents = (ot_torrent *)(torrents_list->data);
499 for (j = 0; j < torrents_list->size; ++j)
500 if (for_each(torrents + j, data))
501 break;
503 mutex_bucket_unlock(bucket, 0);
504 if (!g_opentracker_running)
505 return;
509 ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size) {
510 ot_ip6 *ip = (ot_ip6 *)peer;
511 if (!ip6_isv4mapped(ip)) {
512 *peer_size = OT_PEER_SIZE6;
513 return (ot_peer *)peer;
515 *peer_size = OT_PEER_SIZE4;
516 return (ot_peer *)(((uint8_t *)peer) + 12);
519 size_t peer_size_from_peer6(ot_peer6 *peer) {
520 ot_ip6 *ip = (ot_ip6 *)peer;
521 if (!ip6_isv4mapped(ip))
522 return OT_PEER_SIZE6;
523 return OT_PEER_SIZE4;
526 #ifdef _DEBUG_RANDOMTORRENTS
527 void trackerlogic_add_random_torrents(size_t amount) {
528 struct ot_workstruct ws;
529 memset(&ws, 0, sizeof(ws));
531 ws.inbuf = malloc(G_INBUF_SIZE);
532 ws.outbuf = malloc(G_OUTBUF_SIZE);
533 ws.reply = ws.outbuf;
534 ws.hash = (ot_hash *)ws.inbuf;
536 while (amount--) {
537 arc4random_buf(ws.hash, sizeof(ot_hash));
538 arc4random_buf(&ws.peer, sizeof(ws.peer));
540 OT_PEERFLAG(ws.peer) &= PEER_FLAG_SEEDING | PEER_FLAG_COMPLETED | PEER_FLAG_STOPPED;
542 add_peer_to_torrent_and_return_peers(FLAG_TCP, &ws, 1);
545 free(ws.inbuf);
546 free(ws.outbuf);
548 #endif
550 void exerr(char *message) {
551 fprintf(stderr, "%s\n", message);
552 exit(111);
555 void trackerlogic_init() {
556 g_tracker_id = random();
558 if (!g_stats_path)
559 g_stats_path = "stats";
560 g_stats_path_len = strlen(g_stats_path);
562 /* Initialise background worker threads */
563 mutex_init();
564 clean_init();
565 fullscrape_init();
566 accesslist_init();
567 livesync_init();
568 stats_init();
571 void trackerlogic_deinit(void) {
572 int bucket, delta_torrentcount = 0;
573 size_t j;
575 /* Free all torrents... */
576 for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) {
577 ot_vector *torrents_list = mutex_bucket_lock(bucket);
578 if (torrents_list->size) {
579 for (j = 0; j < torrents_list->size; ++j) {
580 ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + j;
581 free_peerlist(torrent->peer_list6);
582 free_peerlist(torrent->peer_list4);
583 delta_torrentcount -= 1;
585 free(torrents_list->data);
587 mutex_bucket_unlock(bucket, delta_torrentcount);
590 /* Deinitialise background worker threads */
591 stats_deinit();
592 livesync_deinit();
593 accesslist_deinit();
594 fullscrape_deinit();
595 clean_deinit();
596 /* Release mutexes */
597 mutex_deinit();