summaryrefslogtreecommitdiff
path: root/src/trackerlogic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/trackerlogic.c')
-rw-r--r--src/trackerlogic.c109
1 files changed, 55 insertions, 54 deletions
diff --git a/src/trackerlogic.c b/src/trackerlogic.c
index 2313379..6b0659c 100644
--- a/src/trackerlogic.c
+++ b/src/trackerlogic.c
@@ -42,6 +42,7 @@ void free_peerlist(ot_peerlist *peer_list) {
42 what a state dump records. */ 42 what a state dump records. */
43void add_torrent_from_saved_state(ot_hash const hash, ot_time age, size_t down_count) { 43void add_torrent_from_saved_state(ot_hash const hash, ot_time age, size_t down_count) {
44 int exactmatch; 44 int exactmatch;
45 ot_time now = time_now_minutes();
45 ot_torrent *torrent; 46 ot_torrent *torrent;
46 ot_vector *torrents_list; 47 ot_vector *torrents_list;
47 48
@@ -61,19 +62,12 @@ void add_torrent_from_saved_state(ot_hash const hash, ot_time age, size_t down_c
61 return; 62 return;
62 } 63 }
63 64
64 /* Create a new torrent entry, then */ 65 /* A restored torrent starts with no peers, carrying only its base and its
66 download count until the first announce brings a family list to life */
65 memset(torrent, 0, sizeof(ot_torrent)); 67 memset(torrent, 0, sizeof(ot_torrent));
66 memcpy(torrent->hash, hash, sizeof(ot_hash)); 68 memcpy(torrent->hash, hash, sizeof(ot_hash));
67 69 torrent->base = now > age ? (uint32_t)(now - age) : 0;
68 if (!(torrent->peer_list6 = calloc(1, sizeof(ot_peerlist))) || !(torrent->peer_list4 = calloc(1, sizeof(ot_peerlist)))) { 70 torrent->down_count = (uint32_t)down_count;
69 vector_remove_torrent(torrents_list, torrent);
70 mutex_bucket_unlock_by_hash(hash, 0);
71 return;
72 }
73
74 torrent->peer_list6->base = time_now_minutes() - age;
75 torrent->peer_list4->base = time_now_minutes() - age;
76 torrent->peer_list6->down_count = down_count;
77 71
78 mutex_bucket_unlock_by_hash(hash, 1); 72 mutex_bucket_unlock_by_hash(hash, 1);
79} 73}
@@ -113,21 +107,23 @@ size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstru
113 /* Create a new torrent entry, then */ 107 /* Create a new torrent entry, then */
114 memset(torrent, 0, sizeof(ot_torrent)); 108 memset(torrent, 0, sizeof(ot_torrent));
115 memcpy(torrent->hash, *ws->hash, sizeof(ot_hash)); 109 memcpy(torrent->hash, *ws->hash, sizeof(ot_hash));
116
117 if (!(torrent->peer_list6 = calloc(1, sizeof(ot_peerlist))) || !(torrent->peer_list4 = calloc(1, sizeof(ot_peerlist)))) {
118 vector_remove_torrent(torrents_list, torrent);
119 mutex_bucket_unlock_by_hash(*ws->hash, 0);
120 return 0;
121 }
122
123 delta_torrentcount = 1; 110 delta_torrentcount = 1;
124 } else 111 } else
125 clean_single_torrent(torrent); 112 clean_single_torrent(torrent);
126 113
127 torrent->peer_list6->base = time_now_minutes(); 114 torrent->base = time_now_minutes();
128 torrent->peer_list4->base = time_now_minutes();
129 115
130 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; 116 /* The announcing peer's family list is created on first use */
117 {
118 ot_peerlist **slot = peer_size == OT_PEER_SIZE6 ? &torrent->peer_list6 : &torrent->peer_list4;
119 if (!*slot && !(*slot = calloc(1, sizeof(ot_peerlist)))) {
120 if (delta_torrentcount)
121 vector_remove_torrent(torrents_list, torrent);
122 mutex_bucket_unlock_by_hash(*ws->hash, 0);
123 return 0;
124 }
125 peer_list = *slot;
126 }
131 127
132 /* Check for peer in torrent */ 128 /* Check for peer in torrent */
133 peer_dest = vector_find_or_insert_peer(&(peer_list->peers), peer_src, peer_size, &exactmatch); 129 peer_dest = vector_find_or_insert_peer(&(peer_list->peers), peer_src, peer_size, &exactmatch);
@@ -155,7 +151,7 @@ size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstru
155 151
156 peer_list->peer_count++; 152 peer_list->peer_count++;
157 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED) { 153 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED) {
158 peer_list->down_count++; 154 torrent->down_count++;
159 stats_issue_event(ws, EVENT_COMPLETED, 0, 0); 155 stats_issue_event(ws, EVENT_COMPLETED, 0, 0);
160 } 156 }
161 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING) 157 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING)
@@ -182,7 +178,7 @@ size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstru
182 if (!(OT_PEERFLAG_D(peer_dest, peer_size) & 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))
183 peer_list->seed_count++; 179 peer_list->seed_count++;
184 if (!(OT_PEERFLAG_D(peer_dest, peer_size) & 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)) {
185 peer_list->down_count++; 181 torrent->down_count++;
186 stats_issue_event(ws, EVENT_COMPLETED, 0, 0); 182 stats_issue_event(ws, EVENT_COMPLETED, 0, 0);
187 } 183 }
188 if (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) 184 if (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED)
@@ -286,11 +282,12 @@ static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent
286 char *r = reply; 282 char *r = reply;
287 size_t peer_size = peer_size_from_peer6(&ws->peer); 283 size_t peer_size = peer_size_from_peer6(&ws->peer);
288 ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; 284 ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
289 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; 285 size_t list_count = peerlist_peer_count(peer_list);
290 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; 286 size_t peer_count = peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4);
287 size_t seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4);
291 288
292 if (amount > peer_list->peer_count) 289 if (amount > list_count)
293 amount = peer_list->peer_count; 290 amount = list_count;
294 291
295 *(uint32_t *)(r + 0) = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM); 292 *(uint32_t *)(r + 0) = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM);
296 *(uint32_t *)(r + 4) = htonl(peer_count - seed_count); 293 *(uint32_t *)(r + 4) = htonl(peer_count - seed_count);
@@ -298,7 +295,7 @@ static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent
298 r += 12; 295 r += 12;
299 296
300 if (amount) { 297 if (amount) {
301 if (amount == peer_list->peer_count) 298 if (amount == list_count)
302 r += return_peers_all(peer_list, peer_size, r); 299 r += return_peers_all(peer_list, peer_size, r);
303 else 300 else
304 r += return_peers_selection(ws, peer_list, peer_size, amount, r); 301 r += return_peers_selection(ws, peer_list, peer_size, amount, r);
@@ -310,13 +307,15 @@ static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent
310 char *r = reply; 307 char *r = reply;
311 const char *r_end = ws->outbuf + G_OUTBUF_SIZE; 308 const char *r_end = ws->outbuf + G_OUTBUF_SIZE;
312 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; 309 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
313 size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; 310 size_t count6 = peerlist_peer_count(torrent->peer_list6);
314 size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count; 311 size_t count4 = peerlist_peer_count(torrent->peer_list4);
315 size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - seed_count; 312 size_t seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4);
313 size_t down_count = torrent->down_count;
314 size_t peer_count = count6 + count4 - seed_count;
316 315
317 /* Simple case: amount of peers in both lists is less than requested, here we return all results */ 316 /* Simple case: amount of peers in both lists is less than requested, here we return all results */
318 size_t amount_v4 = torrent->peer_list4->peer_count; 317 size_t amount_v4 = count4;
319 size_t amount_v6 = torrent->peer_list6->peer_count; 318 size_t amount_v6 = count6;
320 319
321 /* Complex case: both lists have more than enough entries and we need to split between v4 and v6 clients */ 320 /* Complex case: both lists have more than enough entries and we need to split between v4 and v6 clients */
322 if (amount_v4 + amount_v6 > amount) { 321 if (amount_v4 + amount_v6 > amount) {
@@ -332,8 +331,8 @@ static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent
332 /* Fill the rest according to which family's pool provides more peers */ 331 /* Fill the rest according to which family's pool provides more peers */
333 amount_left = amount - (amount_v4 + amount_v6); 332 amount_left = amount - (amount_v4 + amount_v6);
334 333
335 left_v4 = torrent->peer_list4->peer_count - amount_v4; 334 left_v4 = count4 - amount_v4;
336 left_v6 = torrent->peer_list6->peer_count - amount_v6; 335 left_v6 = count6 - amount_v6;
337 336
338 if (left_v4 + left_v6) { 337 if (left_v4 + left_v6) {
339 percent_v4 = (SCALE * left_v4) / (left_v4 + left_v6); 338 percent_v4 = (SCALE * left_v4) / (left_v4 + left_v6);
@@ -344,9 +343,9 @@ static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent
344 amount_v6 += (amount_left * percent_v6) / SCALE; 343 amount_v6 += (amount_left * percent_v6) / SCALE;
345 344
346 /* Integer division rounding can leave out a peer */ 345 /* Integer division rounding can leave out a peer */
347 if (amount_v4 + amount_v6 < amount && amount_v6 < torrent->peer_list6->peer_count) 346 if (amount_v4 + amount_v6 < amount && amount_v6 < count6)
348 ++amount_v6; 347 ++amount_v6;
349 if (amount_v4 + amount_v6 < amount && amount_v4 < torrent->peer_list4->peer_count) 348 if (amount_v4 + amount_v6 < amount && amount_v4 < count4)
350 ++amount_v4; 349 ++amount_v4;
351 } 350 }
352 351
@@ -355,7 +354,7 @@ static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent
355 354
356 if (amount_v4) { 355 if (amount_v4) {
357 fmt_append(&r, r_end, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4); 356 fmt_append(&r, r_end, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4);
358 if (amount_v4 == torrent->peer_list4->peer_count) 357 if (amount_v4 == count4)
359 r += return_peers_all(torrent->peer_list4, OT_PEER_SIZE4, r); 358 r += return_peers_all(torrent->peer_list4, OT_PEER_SIZE4, r);
360 else 359 else
361 r += return_peers_selection(ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r); 360 r += return_peers_selection(ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r);
@@ -363,7 +362,7 @@ static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent
363 362
364 if (amount_v6) { 363 if (amount_v6) {
365 fmt_append(&r, r_end, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6); 364 fmt_append(&r, r_end, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6);
366 if (amount_v6 == torrent->peer_list6->peer_count) 365 if (amount_v6 == count6)
367 r += return_peers_all(torrent->peer_list6, OT_PEER_SIZE6, r); 366 r += return_peers_all(torrent->peer_list6, OT_PEER_SIZE6, r);
368 else 367 else
369 r += return_peers_selection(ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r); 368 r += return_peers_selection(ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r);
@@ -402,9 +401,9 @@ size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply) {
402 memset(reply, 0, 12); 401 memset(reply, 0, 12);
403 delta_torrentcount = -1; 402 delta_torrentcount = -1;
404 } else { 403 } else {
405 r[0] = htonl(torrent->peer_list6->seed_count + torrent->peer_list4->seed_count); 404 r[0] = htonl(peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4));
406 r[1] = htonl(torrent->peer_list6->down_count + torrent->peer_list4->down_count); 405 r[1] = htonl(torrent->down_count);
407 r[2] = htonl(torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - torrent->peer_list6->seed_count - torrent->peer_list4->seed_count); 406 r[2] = htonl(peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4) - peerlist_seed_count(torrent->peer_list6) - peerlist_seed_count(torrent->peer_list4));
408 } 407 }
409 } 408 }
410 mutex_bucket_unlock_by_hash(hash, delta_torrentcount); 409 mutex_bucket_unlock_by_hash(hash, delta_torrentcount);
@@ -431,9 +430,9 @@ void return_tcp_scrape_for_torrent(ot_hash const *hash_list, size_t amount, char
431 } else { 430 } else {
432 fmt_append(reply, reply_end, "20:"); 431 fmt_append(reply, reply_end, "20:");
433 fmt_bytes(reply, reply_end, hash, sizeof(ot_hash)); 432 fmt_bytes(reply, reply_end, hash, sizeof(ot_hash));
434 fmt_append(reply, reply_end, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", 433 size_t seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4);
435 torrent->peer_list6->seed_count + torrent->peer_list4->seed_count, torrent->peer_list6->down_count + torrent->peer_list4->down_count, 434 size_t peer_count = peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4);
436 torrent->peer_list6->peer_count + torrent->peer_list4->peer_count - torrent->peer_list6->seed_count - torrent->peer_list4->seed_count); 435 fmt_append(reply, reply_end, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, (size_t)torrent->down_count, peer_count - seed_count);
437 } 436 }
438 } 437 }
439 mutex_bucket_unlock_by_hash(*hash, delta_torrentcount); 438 mutex_bucket_unlock_by_hash(*hash, delta_torrentcount);
@@ -461,17 +460,19 @@ size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) {
461 460
462 if (exactmatch) { 461 if (exactmatch) {
463 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; 462 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
464 switch (vector_remove_peer(&peer_list->peers, peer_src, peer_size)) { 463 if (peer_list) {
465 case 2: 464 switch (vector_remove_peer(&peer_list->peers, peer_src, peer_size)) {
466 peer_list->seed_count--; /* Intentional fallthrough */ 465 case 2:
467 case 1: 466 peer_list->seed_count--; /* Intentional fallthrough */
468 peer_list->peer_count--; /* Intentional fallthrough */ 467 case 1:
469 default: 468 peer_list->peer_count--; /* Intentional fallthrough */
470 break; 469 default:
470 break;
471 }
471 } 472 }
472 473
473 peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; 474 peer_count = peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4);
474 seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; 475 seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4);
475 } 476 }
476 477
477 if (proto == FLAG_TCP) { 478 if (proto == FLAG_TCP) {