diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ot_clean.c | 77 | ||||
| -rw-r--r-- | src/ot_fullscrape.c | 8 | ||||
| -rw-r--r-- | src/ot_stats.c | 8 | ||||
| -rw-r--r-- | src/trackerlogic.c | 109 | ||||
| -rw-r--r-- | src/trackerlogic.h | 15 |
5 files changed, 120 insertions, 97 deletions
diff --git a/src/ot_clean.c b/src/ot_clean.c index eaf069a..77cb4ba 100644 --- a/src/ot_clean.c +++ b/src/ot_clean.c | |||
| @@ -49,26 +49,17 @@ static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t pee | |||
| 49 | return (peers - insert_point) / peer_size; | 49 | return (peers - insert_point) / peer_size; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) { | 52 | /* Age one family's peers by timedout minutes. Frees the list and clears the |
| 53 | ot_vector *peer_vector = &peer_list->peers; | 53 | slot once its last peer is gone, so an absent family costs nothing. */ |
| 54 | ot_time timedout = time_since_minutes(peer_list->base); | 54 | static void clean_peer_list_family(ot_peerlist **slot, size_t peer_size, ot_time timedout) { |
| 55 | size_t num_buckets = 1, removed_seeders = 0; | 55 | ot_peerlist *peer_list = *slot; |
| 56 | ot_vector *peer_vector; | ||
| 57 | size_t num_buckets = 1, removed_seeders = 0; | ||
| 56 | 58 | ||
| 57 | /* No need to clean empty torrent */ | 59 | if (!peer_list) |
| 58 | if (!timedout) | 60 | return; |
| 59 | return 0; | ||
| 60 | |||
| 61 | /* Torrent has idled out */ | ||
| 62 | if (timedout > OT_TORRENT_TIMEOUT) | ||
| 63 | return 1; | ||
| 64 | |||
| 65 | /* Nothing to be cleaned here? Test if torrent is worth keeping */ | ||
| 66 | if (timedout > OT_PEER_TIMEOUT) { | ||
| 67 | if (!peer_list->peer_count) | ||
| 68 | return peer_list->down_count ? 0 : 1; | ||
| 69 | timedout = OT_PEER_TIMEOUT; | ||
| 70 | } | ||
| 71 | 61 | ||
| 62 | peer_vector = &peer_list->peers; | ||
| 72 | if (OT_PEERLIST_HASBUCKETS(peer_list)) { | 63 | if (OT_PEERLIST_HASBUCKETS(peer_list)) { |
| 73 | num_buckets = peer_vector->size; | 64 | num_buckets = peer_vector->size; |
| 74 | peer_vector = (ot_vector *)peer_vector->data; | 65 | peer_vector = (ot_vector *)peer_vector->data; |
| @@ -87,25 +78,53 @@ int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) { | |||
| 87 | 78 | ||
| 88 | peer_list->seed_count -= removed_seeders; | 79 | peer_list->seed_count -= removed_seeders; |
| 89 | 80 | ||
| 90 | /* See if we need to convert a torrent from simple vector to bucket list */ | 81 | if (!peer_list->peer_count) { |
| 82 | free_peerlist(peer_list); | ||
| 83 | *slot = NULL; | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 87 | /* See if we need to convert the list from simple vector to bucket list */ | ||
| 91 | if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list)) | 88 | if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list)) |
| 92 | vector_redistribute_buckets(peer_list, peer_size); | 89 | vector_redistribute_buckets(peer_list, peer_size); |
| 93 | |||
| 94 | if (peer_list->peer_count) | ||
| 95 | peer_list->base = time_now_minutes(); | ||
| 96 | else { | ||
| 97 | /* When we got here, the last time that torrent | ||
| 98 | has been touched is OT_PEER_TIMEOUT Minutes before */ | ||
| 99 | peer_list->base = time_now_minutes() - OT_PEER_TIMEOUT; | ||
| 100 | } | ||
| 101 | return 0; | ||
| 102 | } | 90 | } |
| 103 | 91 | ||
| 104 | /* Clean a single torrent | 92 | /* Clean a single torrent |
| 105 | return 1 if torrent timed out | 93 | return 1 if torrent timed out |
| 106 | */ | 94 | */ |
| 107 | int clean_single_torrent(ot_torrent *torrent) { | 95 | int clean_single_torrent(ot_torrent *torrent) { |
| 108 | return clean_single_peer_list(torrent->peer_list6, OT_PEER_SIZE6) * clean_single_peer_list(torrent->peer_list4, OT_PEER_SIZE4); | 96 | ot_time timedout = time_since_minutes(torrent->base); |
| 97 | |||
| 98 | /* Touched since the last sweep: nothing to do */ | ||
| 99 | if (!timedout) | ||
| 100 | return 0; | ||
| 101 | |||
| 102 | /* Torrent has idled out */ | ||
| 103 | if (timedout > OT_TORRENT_TIMEOUT) | ||
| 104 | return 1; | ||
| 105 | |||
| 106 | /* Already empty and nothing arrived before the peer timeout: keep it only | ||
| 107 | while a down count is worth remembering */ | ||
| 108 | if (timedout > OT_PEER_TIMEOUT && !torrent->peer_list6 && !torrent->peer_list4) | ||
| 109 | return torrent->down_count ? 0 : 1; | ||
| 110 | |||
| 111 | /* Peers past the peer timeout are gone regardless, which caps how far the | ||
| 112 | lists are aged in this pass */ | ||
| 113 | if (timedout > OT_PEER_TIMEOUT) | ||
| 114 | timedout = OT_PEER_TIMEOUT; | ||
| 115 | |||
| 116 | clean_peer_list_family(&torrent->peer_list6, OT_PEER_SIZE6, timedout); | ||
| 117 | clean_peer_list_family(&torrent->peer_list4, OT_PEER_SIZE4, timedout); | ||
| 118 | |||
| 119 | if (torrent->peer_list6 || torrent->peer_list4) | ||
| 120 | torrent->base = time_now_minutes(); /* still carrying peers */ | ||
| 121 | else { | ||
| 122 | /* Fell empty: hold base a peer timeout back so a later idle sweep makes | ||
| 123 | the keep-or-drop decision above */ | ||
| 124 | ot_time now = time_now_minutes(); | ||
| 125 | torrent->base = now > OT_PEER_TIMEOUT ? (uint32_t)(now - OT_PEER_TIMEOUT) : 0; | ||
| 126 | } | ||
| 127 | return 0; | ||
| 109 | } | 128 | } |
| 110 | 129 | ||
| 111 | /* Written to once, by clean_deinit, and never read: the byte stays in and | 130 | /* Written to once, by clean_deinit, and never read: the byte stays in and |
diff --git a/src/ot_fullscrape.c b/src/ot_fullscrape.c index 52ec480..9fae444 100644 --- a/src/ot_fullscrape.c +++ b/src/ot_fullscrape.c | |||
| @@ -90,9 +90,9 @@ static void fullscrape_write_one( ot_tasktype mode, char **cursor, ot_torrent *t | |||
| 90 | exactly that size */ | 90 | exactly that size */ |
| 91 | char *r = *cursor; | 91 | char *r = *cursor; |
| 92 | const char *r_end = r + OT_SCRAPE_MAXENTRYLEN; | 92 | const char *r_end = r + OT_SCRAPE_MAXENTRYLEN; |
| 93 | size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; | 93 | size_t seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4); |
| 94 | size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; | 94 | size_t peer_count = peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4); |
| 95 | size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count; | 95 | size_t down_count = torrent->down_count; |
| 96 | 96 | ||
| 97 | switch (mode & TASK_TASK_MASK) { | 97 | switch (mode & TASK_TASK_MASK) { |
| 98 | case TASK_FULLSCRAPE: | 98 | case TASK_FULLSCRAPE: |
| @@ -131,7 +131,7 @@ static void fullscrape_write_one( ot_tasktype mode, char **cursor, ot_torrent *t | |||
| 131 | case TASK_FULLSCRAPE_TRACKERSTATE: | 131 | case TASK_FULLSCRAPE_TRACKERSTATE: |
| 132 | hex_from_hash(r, *hash); | 132 | hex_from_hash(r, *hash); |
| 133 | r += 2 * sizeof(ot_hash); | 133 | r += 2 * sizeof(ot_hash); |
| 134 | fmt_append(&r, r_end, ":%zd:%zd\n", (ssize_t)(time_wall_minutes() - time_since_minutes(torrent->peer_list6->base)), down_count); | 134 | fmt_append(&r, r_end, ":%zd:%zd\n", (ssize_t)(time_wall_minutes() - time_since_minutes(torrent->base)), down_count); |
| 135 | break; | 135 | break; |
| 136 | } | 136 | } |
| 137 | *cursor = r; | 137 | *cursor = r; |
diff --git a/src/ot_stats.c b/src/ot_stats.c index 9901081..c50d4e3 100644 --- a/src/ot_stats.c +++ b/src/ot_stats.c | |||
| @@ -299,8 +299,8 @@ typedef struct { | |||
| 299 | static int torrent_statter(ot_torrent *torrent, uintptr_t data) { | 299 | static int torrent_statter(ot_torrent *torrent, uintptr_t data) { |
| 300 | torrent_stats *stats = (torrent_stats *)data; | 300 | torrent_stats *stats = (torrent_stats *)data; |
| 301 | stats->torrent_count++; | 301 | stats->torrent_count++; |
| 302 | stats->peer_count += torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; | 302 | stats->peer_count += peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4); |
| 303 | stats->seed_count += torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; | 303 | stats->seed_count += peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4); |
| 304 | return 0; | 304 | return 0; |
| 305 | } | 305 | } |
| 306 | 306 | ||
| @@ -343,8 +343,8 @@ void stats_top_txt(char **reply, const char *reply_end, size_t amount) { | |||
| 343 | ot_vector *torrents_list = mutex_bucket_lock(bucket); | 343 | ot_vector *torrents_list = mutex_bucket_lock(bucket); |
| 344 | for (j = 0; j < torrents_list->size; ++j) { | 344 | for (j = 0; j < torrents_list->size; ++j) { |
| 345 | ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j; | 345 | ot_torrent *torrent = (ot_torrent *)(torrents_list->data) + j; |
| 346 | size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; | 346 | size_t peer_count = peerlist_peer_count(torrent->peer_list6) + peerlist_peer_count(torrent->peer_list4); |
| 347 | size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; | 347 | size_t seed_count = peerlist_seed_count(torrent->peer_list6) + peerlist_seed_count(torrent->peer_list4); |
| 348 | size_t leech_count = peer_count - seed_count; | 348 | size_t leech_count = peer_count - seed_count; |
| 349 | 349 | ||
| 350 | stats_insert_into_highscore(peer_count, top100c, amount, &torrent->hash); | 350 | stats_insert_into_highscore(peer_count, top100c, amount, &torrent->hash); |
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. */ |
| 43 | void add_torrent_from_saved_state(ot_hash const hash, ot_time age, size_t down_count) { | 43 | void 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) { |
diff --git a/src/trackerlogic.h b/src/trackerlogic.h index 241b6a7..6b53406 100644 --- a/src/trackerlogic.h +++ b/src/trackerlogic.h | |||
| @@ -165,17 +165,17 @@ struct ot_peerlist; | |||
| 165 | typedef struct ot_peerlist ot_peerlist; | 165 | typedef struct ot_peerlist ot_peerlist; |
| 166 | typedef struct { | 166 | typedef struct { |
| 167 | ot_hash hash; | 167 | ot_hash hash; |
| 168 | ot_peerlist *peer_list6; | 168 | ot_peerlist *peer_list6; /* NULL until the torrent has a v6 peer */ |
| 169 | ot_peerlist *peer_list4; | 169 | ot_peerlist *peer_list4; /* NULL until the torrent has a v4 peer */ |
| 170 | uint32_t base; /* minutes, when the torrent was last cleaned */ | ||
| 171 | uint32_t down_count; /* completed events, summed over both families */ | ||
| 170 | } ot_torrent; | 172 | } ot_torrent; |
| 171 | 173 | ||
| 172 | #include "ot_vector.h" | 174 | #include "ot_vector.h" |
| 173 | 175 | ||
| 174 | struct ot_peerlist { | 176 | struct ot_peerlist { |
| 175 | ot_time base; | 177 | uint32_t seed_count; |
| 176 | size_t seed_count; | 178 | uint32_t peer_count; |
| 177 | size_t peer_count; | ||
| 178 | size_t down_count; | ||
| 179 | /* normal peers vector or | 179 | /* normal peers vector or |
| 180 | pointer to ot_vector[32] buckets if data != NULL and space == 0 | 180 | pointer to ot_vector[32] buckets if data != NULL and space == 0 |
| 181 | */ | 181 | */ |
| @@ -183,6 +183,9 @@ struct ot_peerlist { | |||
| 183 | }; | 183 | }; |
| 184 | #define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list)->peers.size > (peer_list)->peers.space) | 184 | #define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list)->peers.size > (peer_list)->peers.space) |
| 185 | 185 | ||
| 186 | static inline uint32_t peerlist_peer_count(const ot_peerlist *peer_list) { return peer_list ? peer_list->peer_count : 0; } | ||
| 187 | static inline uint32_t peerlist_seed_count(const ot_peerlist *peer_list) { return peer_list ? peer_list->seed_count : 0; } | ||
| 188 | |||
| 186 | /* The http replies the tracker counts when it has to refuse a request. */ | 189 | /* The http replies the tracker counts when it has to refuse a request. */ |
| 187 | enum { | 190 | enum { |
| 188 | CODE_HTTPERROR_302, | 191 | CODE_HTTPERROR_302, |
