summaryrefslogtreecommitdiff
path: root/src/trackerlogic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/trackerlogic.c')
-rw-r--r--src/trackerlogic.c118
1 files changed, 55 insertions, 63 deletions
diff --git a/src/trackerlogic.c b/src/trackerlogic.c
index 6b0659c..4ba3a41 100644
--- a/src/trackerlogic.c
+++ b/src/trackerlogic.c
@@ -28,13 +28,18 @@
28/* Forward declaration */ 28/* Forward declaration */
29size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto); 29size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto);
30 30
31void free_peer_vector(ot_vector *peer_vector) {
32 if (OT_VECTOR_HASBUCKETS(peer_vector))
33 vector_clean_list((ot_vector *)peer_vector->data, peer_vector->size);
34 else
35 free(peer_vector->data); /* free(NULL) on an absent family is fine */
36}
37
31void free_peerlist(ot_peerlist *peer_list) { 38void free_peerlist(ot_peerlist *peer_list) {
32 if (peer_list && peer_list->peers.data) { 39 if (!peer_list)
33 if (OT_PEERLIST_HASBUCKETS(peer_list)) 40 return;
34 vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size); 41 free_peer_vector(&peer_list->peers6);
35 else 42 free_peer_vector(&peer_list->peers4);
36 free(peer_list->peers.data);
37 }
38 free(peer_list); 43 free(peer_list);
39} 44}
40 45
@@ -113,20 +118,17 @@ size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstru
113 118
114 torrent->base = time_now_minutes(); 119 torrent->base = time_now_minutes();
115 120
116 /* The announcing peer's family list is created on first use */ 121 /* The peerlist, holding both families, is created on the first peer */
117 { 122 if (!torrent->peer_list && !(torrent->peer_list = calloc(1, sizeof(ot_peerlist)))) {
118 ot_peerlist **slot = peer_size == OT_PEER_SIZE6 ? &torrent->peer_list6 : &torrent->peer_list4; 123 if (delta_torrentcount)
119 if (!*slot && !(*slot = calloc(1, sizeof(ot_peerlist)))) { 124 vector_remove_torrent(torrents_list, torrent);
120 if (delta_torrentcount) 125 mutex_bucket_unlock_by_hash(*ws->hash, 0);
121 vector_remove_torrent(torrents_list, torrent); 126 return 0;
122 mutex_bucket_unlock_by_hash(*ws->hash, 0);
123 return 0;
124 }
125 peer_list = *slot;
126 } 127 }
128 peer_list = torrent->peer_list;
127 129
128 /* Check for peer in torrent */ 130 /* Check for peer in its family's vector */
129 peer_dest = vector_find_or_insert_peer(&(peer_list->peers), peer_src, peer_size, &exactmatch); 131 peer_dest = vector_find_or_insert_peer(peer_size == OT_PEER_SIZE6 ? &peer_list->peers6 : &peer_list->peers4, peer_src, peer_size, &exactmatch);
130 if (!peer_dest) { 132 if (!peer_dest) {
131 mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount); 133 mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount);
132 return 0; 134 return 0;
@@ -149,7 +151,6 @@ size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstru
149 livesync_tell(ws); 151 livesync_tell(ws);
150#endif 152#endif
151 153
152 peer_list->peer_count++;
153 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED) { 154 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED) {
154 torrent->down_count++; 155 torrent->down_count++;
155 stats_issue_event(ws, EVENT_COMPLETED, 0, 0); 156 stats_issue_event(ws, EVENT_COMPLETED, 0, 0);
@@ -198,14 +199,14 @@ size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstru
198 return ws->reply_size; 199 return ws->reply_size;
199} 200}
200 201
201static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *reply) { 202static size_t return_peers_all(ot_vector *peer_vector, size_t peer_size, size_t peer_count, char *reply) {
202 size_t bucket, num_buckets = 1; 203 size_t bucket, num_buckets = 1;
203 ot_vector *bucket_list = &peer_list->peers; 204 ot_vector *bucket_list = peer_vector;
204 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); 205 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
205 size_t result = compare_size * peer_list->peer_count; 206 size_t result = compare_size * peer_count;
206 char *r_end = reply + result; 207 char *r_end = reply + result;
207 208
208 if (OT_PEERLIST_HASBUCKETS(peer_list)) { 209 if (OT_VECTOR_HASBUCKETS(peer_vector)) {
209 num_buckets = bucket_list->size; 210 num_buckets = bucket_list->size;
210 bucket_list = (ot_vector *)bucket_list->data; 211 bucket_list = (ot_vector *)bucket_list->data;
211 } 212 }
@@ -227,17 +228,17 @@ static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *r
227 return result; 228 return result;
228} 229}
229 230
230static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply) { 231static size_t return_peers_selection(struct ot_workstruct *ws, ot_vector *peer_vector, size_t peer_size, size_t amount, size_t peer_count, char *reply) {
231 size_t bucket_offset, bucket_index = 0, num_buckets = 1; 232 size_t bucket_offset, bucket_index = 0, num_buckets = 1;
232 ot_vector *bucket_list = &peer_list->peers; 233 ot_vector *bucket_list = peer_vector;
233 unsigned int shifted_pc = peer_list->peer_count; 234 unsigned int shifted_pc = peer_count;
234 unsigned int shifted_step = 0; 235 unsigned int shifted_step = 0;
235 unsigned int shift = 0; 236 unsigned int shift = 0;
236 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); 237 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
237 size_t result = compare_size * amount; 238 size_t result = compare_size * amount;
238 char *r_end = reply + result; 239 char *r_end = reply + result;
239 240
240 if (OT_PEERLIST_HASBUCKETS(peer_list)) { 241 if (OT_VECTOR_HASBUCKETS(peer_vector)) {
241 num_buckets = bucket_list->size; 242 num_buckets = bucket_list->size;
242 bucket_list = (ot_vector *)bucket_list->data; 243 bucket_list = (ot_vector *)bucket_list->data;
243 } 244 }
@@ -253,7 +254,7 @@ static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer
253 254
254 /* Initialize somewhere in the middle of peers so that 255 /* Initialize somewhere in the middle of peers so that
255 fixpoint's aliasing doesn't alway miss the same peers */ 256 fixpoint's aliasing doesn't alway miss the same peers */
256 bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count; 257 bucket_offset = nrand48(ws->rand48_state) % peer_count;
257 258
258 while (amount--) { 259 while (amount--) {
259 ot_peer *peer; 260 ot_peer *peer;
@@ -281,10 +282,11 @@ static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer
281static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) { 282static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) {
282 char *r = reply; 283 char *r = reply;
283 size_t peer_size = peer_size_from_peer6(&ws->peer); 284 size_t peer_size = peer_size_from_peer6(&ws->peer);
284 ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; 285 ot_peerlist *peer_list = torrent->peer_list;
285 size_t list_count = peerlist_peer_count(peer_list); 286 ot_vector *family = peer_size == OT_PEER_SIZE6 ? &peer_list->peers6 : &peer_list->peers4;
286 size_t peer_count = peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4); 287 size_t list_count = vector_peer_count(family);
287 size_t seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4); 288 size_t peer_count = torrent_peer_count(torrent);
289 size_t seed_count = torrent_seed_count(torrent);
288 290
289 if (amount > list_count) 291 if (amount > list_count)
290 amount = list_count; 292 amount = list_count;
@@ -296,9 +298,9 @@ static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent
296 298
297 if (amount) { 299 if (amount) {
298 if (amount == list_count) 300 if (amount == list_count)
299 r += return_peers_all(peer_list, peer_size, r); 301 r += return_peers_all(family, peer_size, list_count, r);
300 else 302 else
301 r += return_peers_selection(ws, peer_list, peer_size, amount, r); 303 r += return_peers_selection(ws, family, peer_size, amount, list_count, r);
302 } 304 }
303 return r - reply; 305 return r - reply;
304} 306}
@@ -307,9 +309,10 @@ static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent
307 char *r = reply; 309 char *r = reply;
308 const char *r_end = ws->outbuf + G_OUTBUF_SIZE; 310 const char *r_end = ws->outbuf + G_OUTBUF_SIZE;
309 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; 311 int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
310 size_t count6 = peerlist_peer_count(torrent->peer_list6); 312 ot_peerlist *peer_list = torrent->peer_list;
311 size_t count4 = peerlist_peer_count(torrent->peer_list4); 313 size_t count6 = vector_peer_count(&peer_list->peers6);
312 size_t seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4); 314 size_t count4 = vector_peer_count(&peer_list->peers4);
315 size_t seed_count = peer_list->seed_count;
313 size_t down_count = torrent->down_count; 316 size_t down_count = torrent->down_count;
314 size_t peer_count = count6 + count4 - seed_count; 317 size_t peer_count = count6 + count4 - seed_count;
315 318
@@ -355,17 +358,17 @@ static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent
355 if (amount_v4) { 358 if (amount_v4) {
356 fmt_append(&r, r_end, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4); 359 fmt_append(&r, r_end, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4);
357 if (amount_v4 == count4) 360 if (amount_v4 == count4)
358 r += return_peers_all(torrent->peer_list4, OT_PEER_SIZE4, r); 361 r += return_peers_all(&peer_list->peers4, OT_PEER_SIZE4, count4, r);
359 else 362 else
360 r += return_peers_selection(ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r); 363 r += return_peers_selection(ws, &peer_list->peers4, OT_PEER_SIZE4, amount_v4, count4, r);
361 } 364 }
362 365
363 if (amount_v6) { 366 if (amount_v6) {
364 fmt_append(&r, r_end, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6); 367 fmt_append(&r, r_end, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6);
365 if (amount_v6 == count6) 368 if (amount_v6 == count6)
366 r += return_peers_all(torrent->peer_list6, OT_PEER_SIZE6, r); 369 r += return_peers_all(&peer_list->peers6, OT_PEER_SIZE6, count6, r);
367 else 370 else
368 r += return_peers_selection(ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r); 371 r += return_peers_selection(ws, &peer_list->peers6, OT_PEER_SIZE6, amount_v6, count6, r);
369 } 372 }
370 373
371 fmt_append(&r, r_end, "e"); 374 fmt_append(&r, r_end, "e");
@@ -401,9 +404,9 @@ size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply) {
401 memset(reply, 0, 12); 404 memset(reply, 0, 12);
402 delta_torrentcount = -1; 405 delta_torrentcount = -1;
403 } else { 406 } else {
404 r[0] = htonl(peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4)); 407 r[0] = htonl(torrent_seed_count(torrent));
405 r[1] = htonl(torrent->down_count); 408 r[1] = htonl(torrent->down_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)); 409 r[2] = htonl(torrent_peer_count(torrent) - torrent_seed_count(torrent));
407 } 410 }
408 } 411 }
409 mutex_bucket_unlock_by_hash(hash, delta_torrentcount); 412 mutex_bucket_unlock_by_hash(hash, delta_torrentcount);
@@ -430,8 +433,8 @@ void return_tcp_scrape_for_torrent(ot_hash const *hash_list, size_t amount, char
430 } else { 433 } else {
431 fmt_append(reply, reply_end, "20:"); 434 fmt_append(reply, reply_end, "20:");
432 fmt_bytes(reply, reply_end, hash, sizeof(ot_hash)); 435 fmt_bytes(reply, reply_end, hash, sizeof(ot_hash));
433 size_t seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4); 436 size_t seed_count = torrent_seed_count(torrent);
434 size_t peer_count = peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4); 437 size_t peer_count = torrent_peer_count(torrent);
435 fmt_append(reply, reply_end, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, (size_t)torrent->down_count, peer_count - seed_count); 438 fmt_append(reply, reply_end, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, (size_t)torrent->down_count, peer_count - seed_count);
436 } 439 }
437 } 440 }
@@ -441,12 +444,10 @@ void return_tcp_scrape_for_torrent(ot_hash const *hash_list, size_t amount, char
441 fmt_append(reply, reply_end, "ee"); 444 fmt_append(reply, reply_end, "ee");
442} 445}
443 446
444static ot_peerlist dummy_list;
445size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) { 447size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) {
446 int exactmatch; 448 int exactmatch;
447 ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash); 449 ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash);
448 ot_torrent *torrent = vector_binary_search(ws->hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch); 450 ot_torrent *torrent = vector_binary_search(ws->hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch);
449 ot_peerlist *peer_list = &dummy_list;
450 size_t peer_size; /* initialized in next line */ 451 size_t peer_size; /* initialized in next line */
451 ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size); 452 ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size);
452 size_t peer_count = 0, seed_count = 0; 453 size_t peer_count = 0, seed_count = 0;
@@ -458,21 +459,13 @@ size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) {
458 } 459 }
459#endif 460#endif
460 461
461 if (exactmatch) { 462 if (exactmatch && torrent->peer_list) {
462 peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; 463 ot_vector *family = peer_size == OT_PEER_SIZE6 ? &torrent->peer_list->peers6 : &torrent->peer_list->peers4;
463 if (peer_list) { 464 if (vector_remove_peer(family, peer_src, peer_size) == 2)
464 switch (vector_remove_peer(&peer_list->peers, peer_src, peer_size)) { 465 torrent->peer_list->seed_count--;
465 case 2:
466 peer_list->seed_count--; /* Intentional fallthrough */
467 case 1:
468 peer_list->peer_count--; /* Intentional fallthrough */
469 default:
470 break;
471 }
472 }
473 466
474 peer_count = peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4); 467 peer_count = torrent_peer_count(torrent);
475 seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4); 468 seed_count = torrent_seed_count(torrent);
476 } 469 }
477 470
478 if (proto == FLAG_TCP) { 471 if (proto == FLAG_TCP) {
@@ -621,8 +614,7 @@ void trackerlogic_deinit(void) {
621 if (torrents_list->size) { 614 if (torrents_list->size) {
622 for (j = 0; j < torrents_list->size; ++j) { 615 for (j = 0; j < torrents_list->size; ++j) {
623 ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + j; 616 ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + j;
624 free_peerlist(torrent->peer_list6); 617 free_peerlist(torrent->peer_list);
625 free_peerlist(torrent->peer_list4);
626 delta_torrentcount -= 1; 618 delta_torrentcount -= 1;
627 } 619 }
628 free(torrents_list->data); 620 free(torrents_list->data);