diff options
Diffstat (limited to 'src/trackerlogic.c')
| -rw-r--r-- | src/trackerlogic.c | 118 |
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 */ |
| 29 | size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto); | 29 | size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto); |
| 30 | 30 | ||
| 31 | void 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 | |||
| 31 | void free_peerlist(ot_peerlist *peer_list) { | 38 | void 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 | ||
| 201 | static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *reply) { | 202 | static 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 | ||
| 230 | static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply) { | 231 | static 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 | |||
| 281 | static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) { | 282 | static 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 | ||
| 444 | static ot_peerlist dummy_list; | ||
| 445 | size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) { | 447 | size_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); |
