diff options
Diffstat (limited to 'trackerlogic.c')
| -rw-r--r-- | trackerlogic.c | 645 |
1 files changed, 393 insertions, 252 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index 310466c..04df544 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
| @@ -4,454 +4,595 @@ | |||
| 4 | $id$ */ | 4 | $id$ */ |
| 5 | 5 | ||
| 6 | /* System */ | 6 | /* System */ |
| 7 | #include <stdlib.h> | ||
| 8 | #include <string.h> | ||
| 9 | #include <stdio.h> | ||
| 10 | #include <arpa/inet.h> | 7 | #include <arpa/inet.h> |
| 11 | #include <unistd.h> | ||
| 12 | #include <errno.h> | 8 | #include <errno.h> |
| 13 | #include <stdint.h> | 9 | #include <stdint.h> |
| 10 | #include <stdio.h> | ||
| 11 | #include <stdlib.h> | ||
| 12 | #include <string.h> | ||
| 13 | #include <unistd.h> | ||
| 14 | 14 | ||
| 15 | /* Libowfat */ | 15 | /* Libowfat */ |
| 16 | #include "array.h" | ||
| 16 | #include "byte.h" | 17 | #include "byte.h" |
| 17 | #include "io.h" | 18 | #include "io.h" |
| 18 | #include "iob.h" | 19 | #include "iob.h" |
| 19 | #include "array.h" | 20 | #include "ip6.h" |
| 20 | 21 | ||
| 21 | /* Opentracker */ | 22 | /* Opentracker */ |
| 22 | #include "trackerlogic.h" | ||
| 23 | #include "ot_mutex.h" | ||
| 24 | #include "ot_stats.h" | ||
| 25 | #include "ot_clean.h" | ||
| 26 | #include "ot_http.h" | ||
| 27 | #include "ot_accesslist.h" | 23 | #include "ot_accesslist.h" |
| 24 | #include "ot_clean.h" | ||
| 28 | #include "ot_fullscrape.h" | 25 | #include "ot_fullscrape.h" |
| 26 | #include "ot_http.h" | ||
| 29 | #include "ot_livesync.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" | ||
| 30 | 32 | ||
| 31 | /* Forward declaration */ | 33 | /* Forward declaration */ |
| 32 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ); | 34 | size_t return_peers_for_torrent(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto); |
| 33 | 35 | ||
| 34 | void free_peerlist( ot_peerlist *peer_list ) { | 36 | void free_peerlist(ot_peerlist *peer_list) { |
| 35 | if( peer_list->peers.data ) { | 37 | if (peer_list->peers.data) { |
| 36 | if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { | 38 | if (OT_PEERLIST_HASBUCKETS(peer_list)) |
| 37 | ot_vector *bucket_list = (ot_vector*)(peer_list->peers.data); | 39 | vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size); |
| 38 | 40 | else | |
| 39 | while( peer_list->peers.size-- ) | 41 | free(peer_list->peers.data); |
| 40 | free( bucket_list++->data ); | ||
| 41 | } | ||
| 42 | free( peer_list->peers.data ); | ||
| 43 | } | 42 | } |
| 44 | free( peer_list ); | 43 | free(peer_list); |
| 45 | } | 44 | } |
| 46 | 45 | ||
| 47 | void add_torrent_from_saved_state( ot_hash hash, ot_time base, size_t down_count ) { | 46 | void add_torrent_from_saved_state(ot_hash const hash, ot_time base, size_t down_count) { |
| 48 | int exactmatch; | 47 | int exactmatch; |
| 49 | ot_torrent *torrent; | 48 | ot_torrent *torrent; |
| 50 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); | 49 | ot_vector *torrents_list = mutex_bucket_lock_by_hash(hash); |
| 50 | |||
| 51 | if (!accesslist_hashisvalid(hash)) | ||
| 52 | return mutex_bucket_unlock_by_hash(hash, 0); | ||
| 51 | 53 | ||
| 52 | if( !accesslist_hashisvalid( hash ) ) | 54 | torrent = vector_find_or_insert(torrents_list, (void *)hash, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch); |
| 53 | return mutex_bucket_unlock_by_hash( hash, 0 ); | 55 | if (!torrent || exactmatch) |
| 54 | 56 | return mutex_bucket_unlock_by_hash(hash, 0); | |
| 55 | torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | ||
| 56 | if( !torrent || exactmatch ) | ||
| 57 | return mutex_bucket_unlock_by_hash( hash, 0 ); | ||
| 58 | 57 | ||
| 59 | /* Create a new torrent entry, then */ | 58 | /* Create a new torrent entry, then */ |
| 60 | memcpy( torrent->hash, hash, sizeof(ot_hash) ); | 59 | byte_zero(torrent, sizeof(ot_torrent)); |
| 61 | 60 | memcpy(torrent->hash, hash, sizeof(ot_hash)); | |
| 62 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { | 61 | |
| 63 | vector_remove_torrent( torrents_list, torrent ); | 62 | if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) { |
| 64 | return mutex_bucket_unlock_by_hash( hash, 0 ); | 63 | vector_remove_torrent(torrents_list, torrent); |
| 64 | return mutex_bucket_unlock_by_hash(hash, 0); | ||
| 65 | } | 65 | } |
| 66 | |||
| 67 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); | ||
| 68 | torrent->peer_list->base = base; | ||
| 69 | torrent->peer_list->down_count = down_count; | ||
| 70 | 66 | ||
| 71 | return mutex_bucket_unlock_by_hash( hash, 1 ); | 67 | byte_zero(torrent->peer_list6, sizeof(ot_peerlist)); |
| 72 | } | 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; | ||
| 73 | 73 | ||
| 74 | size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) { | 74 | return mutex_bucket_unlock_by_hash(hash, 1); |
| 75 | int exactmatch, delta_torrentcount = 0; | 75 | } |
| 76 | ot_torrent *torrent; | ||
| 77 | ot_peer *peer_dest; | ||
| 78 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); | ||
| 79 | 76 | ||
| 80 | if( !accesslist_hashisvalid( *ws->hash ) ) { | 77 | size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount) { |
| 81 | mutex_bucket_unlock_by_hash( *ws->hash, 0 ); | 78 | int exactmatch, delta_torrentcount = 0; |
| 82 | if( proto == FLAG_TCP ) { | 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); | ||
| 85 | |||
| 86 | if (!accesslist_hashisvalid(*ws->hash)) { | ||
| 87 | mutex_bucket_unlock_by_hash(*ws->hash, 0); | ||
| 88 | if (proto == FLAG_TCP) { | ||
| 83 | const char invalid_hash[] = "d14:failure reason63:Requested download is not authorized for use with this tracker.e"; | 89 | const char invalid_hash[] = "d14:failure reason63:Requested download is not authorized for use with this tracker.e"; |
| 84 | memcpy( ws->reply, invalid_hash, strlen( invalid_hash ) ); | 90 | memcpy(ws->reply, invalid_hash, strlen(invalid_hash)); |
| 85 | return strlen( invalid_hash ); | 91 | return strlen(invalid_hash); |
| 86 | } | 92 | } |
| 87 | return 0; | 93 | return 0; |
| 88 | } | 94 | } |
| 89 | 95 | ||
| 90 | torrent = vector_find_or_insert( torrents_list, (void*)ws->hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 96 | torrent = vector_find_or_insert(torrents_list, (void *)ws->hash, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch); |
| 91 | if( !torrent ) { | 97 | if (!torrent) { |
| 92 | mutex_bucket_unlock_by_hash( *ws->hash, 0 ); | 98 | mutex_bucket_unlock_by_hash(*ws->hash, 0); |
| 93 | return 0; | 99 | return 0; |
| 94 | } | 100 | } |
| 95 | 101 | ||
| 96 | if( !exactmatch ) { | 102 | if (!exactmatch) { |
| 97 | /* Create a new torrent entry, then */ | 103 | /* Create a new torrent entry, then */ |
| 98 | memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) ); | 104 | byte_zero(torrent, sizeof(ot_torrent)); |
| 105 | memcpy(torrent->hash, *ws->hash, sizeof(ot_hash)); | ||
| 99 | 106 | ||
| 100 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { | 107 | if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) { |
| 101 | vector_remove_torrent( torrents_list, torrent ); | 108 | vector_remove_torrent(torrents_list, torrent); |
| 102 | mutex_bucket_unlock_by_hash( *ws->hash, 0 ); | 109 | mutex_bucket_unlock_by_hash(*ws->hash, 0); |
| 103 | return 0; | 110 | return 0; |
| 104 | } | 111 | } |
| 105 | 112 | ||
| 106 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); | 113 | byte_zero(torrent->peer_list6, sizeof(ot_peerlist)); |
| 114 | byte_zero(torrent->peer_list4, sizeof(ot_peerlist)); | ||
| 107 | delta_torrentcount = 1; | 115 | delta_torrentcount = 1; |
| 108 | } else | 116 | } else |
| 109 | clean_single_torrent( torrent ); | 117 | clean_single_torrent(torrent); |
| 118 | |||
| 119 | torrent->peer_list6->base = g_now_minutes; | ||
| 120 | torrent->peer_list4->base = g_now_minutes; | ||
| 110 | 121 | ||
| 111 | torrent->peer_list->base = g_now_minutes; | 122 | peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; |
| 112 | 123 | ||
| 113 | /* Check for peer in torrent */ | 124 | /* Check for peer in torrent */ |
| 114 | peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), &ws->peer, &exactmatch ); | 125 | peer_dest = vector_find_or_insert_peer(&(peer_list->peers), peer_src, peer_size, &exactmatch); |
| 115 | if( !peer_dest ) { | 126 | if (!peer_dest) { |
| 116 | mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); | 127 | mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount); |
| 117 | return 0; | 128 | return 0; |
| 118 | } | 129 | } |
| 119 | 130 | ||
| 120 | /* Tell peer that it's fresh */ | 131 | /* Tell peer that it's fresh */ |
| 121 | OT_PEERTIME( &ws->peer ) = 0; | 132 | OT_PEERTIME(ws->peer, OT_PEER_SIZE6) = 0; |
| 122 | 133 | ||
| 123 | /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ | 134 | /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ |
| 124 | if( ( OT_PEERFLAG( &ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) | 135 | if ((OT_PEERFLAG(ws->peer) & (PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING)) == PEER_FLAG_COMPLETED) |
| 125 | OT_PEERFLAG( &ws->peer ) ^= PEER_FLAG_COMPLETED; | 136 | OT_PEERFLAG(ws->peer) ^= PEER_FLAG_COMPLETED; |
| 126 | 137 | ||
| 127 | /* If we hadn't had a match create peer there */ | 138 | /* If we hadn't had a match create peer there */ |
| 128 | if( !exactmatch ) { | 139 | if (!exactmatch) { |
| 129 | 140 | ||
| 130 | #ifdef WANT_SYNC_LIVE | 141 | #ifdef WANT_SYNC_LIVE |
| 131 | if( proto == FLAG_MCA ) | 142 | if (proto == FLAG_MCA) |
| 132 | OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_FROM_SYNC; | 143 | OT_PEERFLAG(ws->peer) |= PEER_FLAG_FROM_SYNC; |
| 133 | else | 144 | else |
| 134 | livesync_tell( ws ); | 145 | livesync_tell(ws); |
| 135 | #endif | 146 | #endif |
| 136 | 147 | ||
| 137 | torrent->peer_list->peer_count++; | 148 | peer_list->peer_count++; |
| 138 | if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) { | 149 | if (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED) { |
| 139 | torrent->peer_list->down_count++; | 150 | peer_list->down_count++; |
| 140 | stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws ); | 151 | stats_issue_event(EVENT_COMPLETED, 0, (uintptr_t)ws); |
| 141 | } | 152 | } |
| 142 | if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) | 153 | if (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING) |
| 143 | torrent->peer_list->seed_count++; | 154 | peer_list->seed_count++; |
| 144 | 155 | ||
| 145 | } else { | 156 | } else { |
| 146 | stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest ) ); | 157 | stats_issue_event(EVENT_RENEW, 0, OT_PEERTIME(peer_dest, peer_size)); |
| 147 | #ifdef WANT_SPOT_WOODPECKER | 158 | #ifdef WANT_SPOT_WOODPECKER |
| 148 | if( ( OT_PEERTIME(peer_dest) > 0 ) && ( OT_PEERTIME(peer_dest) < 20 ) ) | 159 | if ((OT_PEERTIME(peer_dest, peer_size) > 0) && (OT_PEERTIME(peer_dest, peer_size) < 20)) |
| 149 | stats_issue_event( EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer ); | 160 | stats_issue_event(EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer); |
| 150 | #endif | 161 | #endif |
| 151 | #ifdef WANT_SYNC_LIVE | 162 | #ifdef WANT_SYNC_LIVE |
| 152 | /* Won't live sync peers that come back too fast. Only exception: | 163 | /* Won't live sync peers that come back too fast. Only exception: |
| 153 | fresh "completed" reports */ | 164 | fresh "completed" reports */ |
| 154 | if( proto != FLAG_MCA ) { | 165 | if (proto != FLAG_MCA) { |
| 155 | if( OT_PEERTIME( peer_dest ) > OT_CLIENT_SYNC_RENEW_BOUNDARY || | 166 | if (OT_PEERTIME(peer_dest, peer_size) > OT_CLIENT_SYNC_RENEW_BOUNDARY || |
| 156 | ( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) ) | 167 | (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED))) |
| 157 | livesync_tell( ws ); | 168 | livesync_tell(ws); |
| 158 | } | 169 | } |
| 159 | #endif | 170 | #endif |
| 160 | 171 | ||
| 161 | if( (OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) ) | 172 | if ((OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING)) |
| 162 | torrent->peer_list->seed_count--; | 173 | peer_list->seed_count--; |
| 163 | if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) ) | 174 | if (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING)) |
| 164 | torrent->peer_list->seed_count++; | 175 | peer_list->seed_count++; |
| 165 | if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) { | 176 | if (!(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED)) { |
| 166 | torrent->peer_list->down_count++; | 177 | peer_list->down_count++; |
| 167 | stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws ); | 178 | stats_issue_event(EVENT_COMPLETED, 0, (uintptr_t)ws); |
| 168 | } | 179 | } |
| 169 | if( OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) | 180 | if (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED) |
| 170 | OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; | 181 | OT_PEERFLAG(ws->peer) |= PEER_FLAG_COMPLETED; |
| 171 | } | 182 | } |
| 172 | 183 | ||
| 173 | memcpy( peer_dest, &ws->peer, sizeof(ot_peer) ); | 184 | memcpy(peer_dest, peer_src, peer_size); |
| 174 | #ifdef WANT_SYNC | 185 | #ifdef WANT_SYNC |
| 175 | if( proto == FLAG_MCA ) { | 186 | if (proto == FLAG_MCA) { |
| 176 | mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); | 187 | mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount); |
| 177 | return 0; | 188 | return 0; |
| 178 | } | 189 | } |
| 179 | #endif | 190 | #endif |
| 180 | 191 | ||
| 181 | ws->reply_size = return_peers_for_torrent( torrent, amount, ws->reply, proto ); | 192 | ws->reply_size = return_peers_for_torrent(ws, torrent, amount, ws->reply, proto); |
| 182 | mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount ); | 193 | mutex_bucket_unlock_by_hash(*ws->hash, delta_torrentcount); |
| 183 | return ws->reply_size; | 194 | return ws->reply_size; |
| 184 | } | 195 | } |
| 185 | 196 | ||
| 186 | static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) { | 197 | static size_t return_peers_all(ot_peerlist *peer_list, size_t peer_size, char *reply) { |
| 187 | unsigned int bucket, num_buckets = 1; | 198 | unsigned int bucket, num_buckets = 1; |
| 188 | ot_vector * bucket_list = &peer_list->peers; | 199 | ot_vector *bucket_list = &peer_list->peers; |
| 189 | size_t result = OT_PEER_COMPARE_SIZE * peer_list->peer_count; | 200 | size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); |
| 190 | char * r_end = reply + result; | 201 | size_t result = compare_size * peer_list->peer_count; |
| 202 | char *r_end = reply + result; | ||
| 191 | 203 | ||
| 192 | if( OT_PEERLIST_HASBUCKETS(peer_list) ) { | 204 | if (OT_PEERLIST_HASBUCKETS(peer_list)) { |
| 193 | num_buckets = bucket_list->size; | 205 | num_buckets = bucket_list->size; |
| 194 | bucket_list = (ot_vector *)bucket_list->data; | 206 | bucket_list = (ot_vector *)bucket_list->data; |
| 195 | } | 207 | } |
| 196 | 208 | ||
| 197 | for( bucket = 0; bucket<num_buckets; ++bucket ) { | 209 | for (bucket = 0; bucket < num_buckets; ++bucket) { |
| 198 | ot_peer * peers = (ot_peer*)bucket_list[bucket].data; | 210 | ot_peer *peers = bucket_list[bucket].data; |
| 199 | size_t peer_count = bucket_list[bucket].size; | 211 | size_t peer_count = bucket_list[bucket].size; |
| 200 | while( peer_count-- ) { | 212 | while (peer_count--) { |
| 201 | if( OT_PEERFLAG(peers) & PEER_FLAG_SEEDING ) { | 213 | if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING) { |
| 202 | r_end-=OT_PEER_COMPARE_SIZE; | 214 | r_end -= compare_size; |
| 203 | memcpy(r_end,peers++,OT_PEER_COMPARE_SIZE); | 215 | memcpy(r_end, peers, compare_size); |
| 204 | } else { | 216 | } else { |
| 205 | memcpy(reply,peers++,OT_PEER_COMPARE_SIZE); | 217 | memcpy(reply, peers, compare_size); |
| 206 | reply+=OT_PEER_COMPARE_SIZE; | 218 | reply += compare_size; |
| 207 | } | 219 | } |
| 220 | peers += peer_size; | ||
| 208 | } | 221 | } |
| 209 | } | 222 | } |
| 210 | return result; | 223 | return result; |
| 211 | } | 224 | } |
| 212 | 225 | ||
| 213 | static size_t return_peers_selection( ot_peerlist *peer_list, size_t amount, char *reply ) { | 226 | static size_t return_peers_selection(struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply) { |
| 214 | unsigned int bucket_offset, bucket_index = 0, num_buckets = 1; | 227 | unsigned int bucket_offset, bucket_index = 0, num_buckets = 1; |
| 215 | ot_vector * bucket_list = &peer_list->peers; | 228 | ot_vector *bucket_list = &peer_list->peers; |
| 216 | unsigned int shifted_pc = peer_list->peer_count; | 229 | unsigned int shifted_pc = peer_list->peer_count; |
| 217 | unsigned int shifted_step = 0; | 230 | unsigned int shifted_step = 0; |
| 218 | unsigned int shift = 0; | 231 | unsigned int shift = 0; |
| 219 | size_t result = OT_PEER_COMPARE_SIZE * amount; | 232 | size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); |
| 220 | char * r_end = reply + result; | 233 | size_t result = compare_size * amount; |
| 221 | 234 | char *r_end = reply + result; | |
| 222 | if( OT_PEERLIST_HASBUCKETS(peer_list) ) { | 235 | |
| 236 | if (OT_PEERLIST_HASBUCKETS(peer_list)) { | ||
| 223 | num_buckets = bucket_list->size; | 237 | num_buckets = bucket_list->size; |
| 224 | bucket_list = (ot_vector *)bucket_list->data; | 238 | bucket_list = (ot_vector *)bucket_list->data; |
| 225 | } | 239 | } |
| 226 | 240 | ||
| 227 | /* Make fixpoint arithmetic as exact as possible */ | 241 | /* Make fixpoint arithmetic as exact as possible */ |
| 228 | #define MAXPRECBIT (1<<(8*sizeof(int)-3)) | 242 | #define MAXPRECBIT (1 << (8 * sizeof(int) - 3)) |
| 229 | while( !(shifted_pc & MAXPRECBIT ) ) { shifted_pc <<= 1; shift++; } | 243 | while (!(shifted_pc & MAXPRECBIT)) { |
| 230 | shifted_step = shifted_pc/amount; | 244 | shifted_pc <<= 1; |
| 245 | shift++; | ||
| 246 | } | ||
| 247 | shifted_step = shifted_pc / amount; | ||
| 231 | #undef MAXPRECBIT | 248 | #undef MAXPRECBIT |
| 232 | 249 | ||
| 233 | /* Initialize somewhere in the middle of peers so that | 250 | /* Initialize somewhere in the middle of peers so that |
| 234 | fixpoint's aliasing doesn't alway miss the same peers */ | 251 | fixpoint's aliasing doesn't alway miss the same peers */ |
| 235 | bucket_offset = random() % peer_list->peer_count; | 252 | bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count; |
| 236 | 253 | ||
| 237 | while( amount-- ) { | 254 | while (amount--) { |
| 238 | ot_peer * peer; | 255 | ot_peer *peer; |
| 239 | 256 | ||
| 240 | /* This is the aliased, non shifted range, next value may fall into */ | 257 | /* This is the aliased, non shifted range, next value may fall into */ |
| 241 | unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) - | 258 | unsigned int diff = (((amount + 1) * shifted_step) >> shift) - ((amount * shifted_step) >> shift); |
| 242 | ( ( amount * shifted_step ) >> shift ); | 259 | bucket_offset += 1 + nrand48(ws->rand48_state) % diff; |
| 243 | bucket_offset += 1 + random() % diff; | ||
| 244 | 260 | ||
| 245 | while( bucket_offset >= bucket_list[bucket_index].size ) { | 261 | while (bucket_offset >= bucket_list[bucket_index].size) { |
| 246 | bucket_offset -= bucket_list[bucket_index].size; | 262 | bucket_offset -= bucket_list[bucket_index].size; |
| 247 | bucket_index = ( bucket_index + 1 ) % num_buckets; | 263 | bucket_index = (bucket_index + 1) % num_buckets; |
| 248 | } | 264 | } |
| 249 | peer = ((ot_peer*)bucket_list[bucket_index].data) + bucket_offset; | 265 | peer = bucket_list[bucket_index].data + peer_size * bucket_offset; |
| 250 | if( OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) { | 266 | if (OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING) { |
| 251 | r_end-=OT_PEER_COMPARE_SIZE; | 267 | r_end -= compare_size; |
| 252 | memcpy(r_end,peer,OT_PEER_COMPARE_SIZE); | 268 | memcpy(r_end, peer, compare_size); |
| 253 | } else { | 269 | } else { |
| 254 | memcpy(reply,peer,OT_PEER_COMPARE_SIZE); | 270 | memcpy(reply, peer, compare_size); |
| 255 | reply+=OT_PEER_COMPARE_SIZE; | 271 | reply += compare_size; |
| 256 | } | 272 | } |
| 257 | } | 273 | } |
| 258 | return result; | 274 | return result; |
| 259 | } | 275 | } |
| 260 | 276 | ||
| 261 | /* Compiles a list of random peers for a torrent | 277 | static size_t return_peers_for_torrent_udp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) { |
| 262 | * reply must have enough space to hold 92+6*amount bytes | 278 | char *r = reply; |
| 263 | * does not yet check not to return self | 279 | size_t peer_size = peer_size_from_peer6(&ws->peer); |
| 264 | */ | 280 | ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; |
| 265 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) { | 281 | size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count; |
| 266 | ot_peerlist *peer_list = torrent->peer_list; | 282 | size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count; |
| 267 | char *r = reply; | 283 | |
| 268 | 284 | if (amount > peer_list->peer_count) | |
| 269 | if( amount > peer_list->peer_count ) | ||
| 270 | amount = peer_list->peer_count; | 285 | amount = peer_list->peer_count; |
| 271 | 286 | ||
| 272 | if( proto == FLAG_TCP ) { | 287 | *(uint32_t *)(r + 0) = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM); |
| 273 | int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; | 288 | *(uint32_t *)(r + 4) = htonl(peer_count - seed_count); |
| 274 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie" PEERS_BENCODED "%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, OT_PEER_COMPARE_SIZE*amount ); | 289 | *(uint32_t *)(r + 8) = htonl(seed_count); |
| 275 | } else { | 290 | r += 12; |
| 276 | *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 291 | |
| 277 | *(uint32_t*)(r+4) = htonl( peer_list->peer_count - peer_list->seed_count ); | 292 | if (amount) { |
| 278 | *(uint32_t*)(r+8) = htonl( peer_list->seed_count ); | 293 | if (amount == peer_list->peer_count) |
| 279 | r += 12; | 294 | r += return_peers_all(peer_list, peer_size, r); |
| 295 | else | ||
| 296 | r += return_peers_selection(ws, peer_list, peer_size, amount, r); | ||
| 280 | } | 297 | } |
| 298 | return r - reply; | ||
| 299 | } | ||
| 281 | 300 | ||
| 282 | if( amount ) { | 301 | static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) { |
| 283 | if( amount == peer_list->peer_count ) | 302 | char *r = reply; |
| 284 | r += return_peers_all( peer_list, r ); | 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; | ||
| 307 | |||
| 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; | ||
| 311 | |||
| 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; | ||
| 316 | |||
| 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; | ||
| 322 | |||
| 323 | /* Fill the rest according to which family's pool provides more peers */ | ||
| 324 | amount_left = amount - (amount_v4 + amount_v6); | ||
| 325 | |||
| 326 | left_v4 = torrent->peer_list4->peer_count - amount_v4; | ||
| 327 | left_v6 = torrent->peer_list6->peer_count - amount_v6; | ||
| 328 | |||
| 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); | ||
| 332 | } | ||
| 333 | |||
| 334 | amount_v4 += (amount_left * percent_v4) / SCALE; | ||
| 335 | amount_v6 += (amount_left * percent_v6) / SCALE; | ||
| 336 | |||
| 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; | ||
| 342 | } | ||
| 343 | |||
| 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); | ||
| 346 | |||
| 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); | ||
| 353 | } | ||
| 354 | |||
| 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); | ||
| 285 | else | 359 | else |
| 286 | r += return_peers_selection( peer_list, amount, r ); | 360 | r += return_peers_selection(ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r); |
| 287 | } | 361 | } |
| 288 | 362 | ||
| 289 | if( proto == FLAG_TCP ) | 363 | *r++ = 'e'; |
| 290 | *r++ = 'e'; | ||
| 291 | 364 | ||
| 292 | return r - reply; | 365 | return r - reply; |
| 293 | } | 366 | } |
| 294 | 367 | ||
| 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 | ||
| 375 | */ | ||
| 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); | ||
| 378 | } | ||
| 379 | |||
| 295 | /* Fetches scrape info for a specific torrent */ | 380 | /* Fetches scrape info for a specific torrent */ |
| 296 | size_t return_udp_scrape_for_torrent( ot_hash hash, char *reply ) { | 381 | size_t return_udp_scrape_for_torrent(ot_hash const hash, char *reply) { |
| 297 | int exactmatch, delta_torrentcount = 0; | 382 | int exactmatch, delta_torrentcount = 0; |
| 298 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( hash ); | 383 | ot_vector *torrents_list = mutex_bucket_lock_by_hash(hash); |
| 299 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 384 | ot_torrent *torrent = binary_search(hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch); |
| 300 | 385 | ||
| 301 | if( !exactmatch ) { | 386 | if (!exactmatch) { |
| 302 | memset( reply, 0, 12); | 387 | memset(reply, 0, 12); |
| 303 | } else { | 388 | } else { |
| 304 | uint32_t *r = (uint32_t*) reply; | 389 | uint32_t *r = (uint32_t *)reply; |
| 305 | 390 | ||
| 306 | if( clean_single_torrent( torrent ) ) { | 391 | if (clean_single_torrent(torrent)) { |
| 307 | vector_remove_torrent( torrents_list, torrent ); | 392 | vector_remove_torrent(torrents_list, torrent); |
| 308 | memset( reply, 0, 12); | 393 | memset(reply, 0, 12); |
| 309 | delta_torrentcount = -1; | 394 | delta_torrentcount = -1; |
| 310 | } else { | 395 | } else { |
| 311 | r[0] = htonl( torrent->peer_list->seed_count ); | 396 | r[0] = htonl(torrent->peer_list6->seed_count + torrent->peer_list4->seed_count); |
| 312 | r[1] = htonl( torrent->peer_list->down_count ); | 397 | r[1] = htonl(torrent->peer_list6->down_count + torrent->peer_list4->down_count); |
| 313 | r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_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); |
| 314 | } | 399 | } |
| 315 | } | 400 | } |
| 316 | mutex_bucket_unlock_by_hash( hash, delta_torrentcount ); | 401 | mutex_bucket_unlock_by_hash(hash, delta_torrentcount); |
| 317 | return 12; | 402 | return 12; |
| 318 | } | 403 | } |
| 319 | 404 | ||
| 320 | /* Fetches scrape info for a specific torrent */ | 405 | /* Fetches scrape info for a specific torrent */ |
| 321 | size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) { | 406 | size_t return_tcp_scrape_for_torrent(ot_hash const *hash_list, int amount, char *reply) { |
| 322 | char *r = reply; | 407 | char *r = reply; |
| 323 | int exactmatch, i; | 408 | int exactmatch, i; |
| 324 | 409 | ||
| 325 | r += sprintf( r, "d5:filesd" ); | 410 | r += sprintf(r, "d5:filesd"); |
| 326 | 411 | ||
| 327 | for( i=0; i<amount; ++i ) { | 412 | for (i = 0; i < amount; ++i) { |
| 328 | int delta_torrentcount = 0; | 413 | int delta_torrentcount = 0; |
| 329 | ot_hash *hash = hash_list + i; | 414 | ot_hash const *hash = hash_list + i; |
| 330 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( *hash ); | 415 | ot_vector *torrents_list = mutex_bucket_lock_by_hash(*hash); |
| 331 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 416 | ot_torrent *torrent = binary_search(hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch); |
| 332 | 417 | ||
| 333 | if( exactmatch ) { | 418 | if (exactmatch) { |
| 334 | if( clean_single_torrent( torrent ) ) { | 419 | if (clean_single_torrent(torrent)) { |
| 335 | vector_remove_torrent( torrents_list, torrent ); | 420 | vector_remove_torrent(torrents_list, torrent); |
| 336 | delta_torrentcount = -1; | 421 | delta_torrentcount = -1; |
| 337 | } else { | 422 | } else { |
| 338 | *r++='2';*r++='0';*r++=':'; | 423 | *r++ = '2'; |
| 339 | memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash); | 424 | *r++ = '0'; |
| 340 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", | 425 | *r++ = ':'; |
| 341 | torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ); | 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); | ||
| 342 | } | 431 | } |
| 343 | } | 432 | } |
| 344 | mutex_bucket_unlock_by_hash( *hash, delta_torrentcount ); | 433 | mutex_bucket_unlock_by_hash(*hash, delta_torrentcount); |
| 345 | } | 434 | } |
| 346 | 435 | ||
| 347 | *r++ = 'e'; *r++ = 'e'; | 436 | *r++ = 'e'; |
| 437 | *r++ = 'e'; | ||
| 348 | return r - reply; | 438 | return r - reply; |
| 349 | } | 439 | } |
| 350 | 440 | ||
| 351 | static ot_peerlist dummy_list; | 441 | static ot_peerlist dummy_list; |
| 352 | size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) { | 442 | size_t remove_peer_from_torrent(PROTO_FLAG proto, struct ot_workstruct *ws) { |
| 353 | int exactmatch; | 443 | int exactmatch; |
| 354 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); | 444 | ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash); |
| 355 | ot_torrent *torrent = binary_search( ws->hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 445 | ot_torrent *torrent = binary_search(ws->hash, torrents_list->data, torrents_list->size, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch); |
| 356 | ot_peerlist *peer_list = &dummy_list; | 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; | ||
| 357 | 450 | ||
| 358 | #ifdef WANT_SYNC_LIVE | 451 | #ifdef WANT_SYNC_LIVE |
| 359 | if( proto != FLAG_MCA ) { | 452 | if (proto != FLAG_MCA) { |
| 360 | OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; | 453 | OT_PEERFLAG(ws->peer) |= PEER_FLAG_STOPPED; |
| 361 | livesync_tell( ws ); | 454 | livesync_tell(ws); |
| 362 | } | 455 | } |
| 363 | #endif | 456 | #endif |
| 364 | 457 | ||
| 365 | if( exactmatch ) { | 458 | if (exactmatch) { |
| 366 | peer_list = torrent->peer_list; | 459 | peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; |
| 367 | switch( vector_remove_peer( &peer_list->peers, &ws->peer ) ) { | 460 | switch (vector_remove_peer(&peer_list->peers, peer_src, peer_size)) { |
| 368 | case 2: peer_list->seed_count--; /* Fall throughs intended */ | 461 | case 2: |
| 369 | case 1: peer_list->peer_count--; /* Fall throughs intended */ | 462 | peer_list->seed_count--; /* Intentional fallthrough */ |
| 370 | default: break; | 463 | case 1: |
| 464 | peer_list->peer_count--; /* Intentional fallthrough */ | ||
| 465 | default: | ||
| 466 | break; | ||
| 371 | } | 467 | } |
| 468 | |||
| 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; | ||
| 372 | } | 471 | } |
| 373 | 472 | ||
| 374 | if( proto == FLAG_TCP ) { | 473 | if (proto == FLAG_TCP) { |
| 375 | int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; | 474 | int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; |
| 376 | ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie" PEERS_BENCODED "0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2 ); | 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); | ||
| 377 | } | 477 | } |
| 378 | 478 | ||
| 379 | /* Handle UDP reply */ | 479 | /* Handle UDP reply */ |
| 380 | if( proto == FLAG_UDP ) { | 480 | if (proto == FLAG_UDP) { |
| 381 | ((uint32_t*)ws->reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 481 | ((uint32_t *)ws->reply)[2] = htonl(OT_CLIENT_REQUEST_INTERVAL_RANDOM); |
| 382 | ((uint32_t*)ws->reply)[3] = htonl( peer_list->peer_count - peer_list->seed_count ); | 482 | ((uint32_t *)ws->reply)[3] = htonl(peer_count - seed_count); |
| 383 | ((uint32_t*)ws->reply)[4] = htonl( peer_list->seed_count); | 483 | ((uint32_t *)ws->reply)[4] = htonl(seed_count); |
| 384 | ws->reply_size = 20; | 484 | ws->reply_size = 20; |
| 385 | } | 485 | } |
| 386 | 486 | ||
| 387 | mutex_bucket_unlock_by_hash( *ws->hash, 0 ); | 487 | mutex_bucket_unlock_by_hash(*ws->hash, 0); |
| 388 | return ws->reply_size; | 488 | return ws->reply_size; |
| 389 | } | 489 | } |
| 390 | 490 | ||
| 391 | void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data ), uintptr_t data ) { | 491 | void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), uintptr_t data) { |
| 392 | int bucket; | 492 | int bucket; |
| 393 | size_t j; | 493 | size_t j; |
| 394 | 494 | ||
| 395 | for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | 495 | for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { |
| 396 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); | 496 | ot_vector *torrents_list = mutex_bucket_lock(bucket); |
| 397 | ot_torrent *torrents = (ot_torrent*)(torrents_list->data); | 497 | ot_torrent *torrents = (ot_torrent *)(torrents_list->data); |
| 398 | 498 | ||
| 399 | for( j=0; j<torrents_list->size; ++j ) | 499 | for (j = 0; j < torrents_list->size; ++j) |
| 400 | if( for_each( torrents + j, data ) ) | 500 | if (for_each(torrents + j, data)) |
| 401 | break; | 501 | break; |
| 402 | 502 | ||
| 403 | mutex_bucket_unlock( bucket, 0 ); | 503 | mutex_bucket_unlock(bucket, 0); |
| 404 | if( !g_opentracker_running ) return; | 504 | if (!g_opentracker_running) |
| 505 | return; | ||
| 506 | } | ||
| 507 | } | ||
| 508 | |||
| 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; | ||
| 405 | } | 514 | } |
| 515 | *peer_size = OT_PEER_SIZE4; | ||
| 516 | return (ot_peer *)(((uint8_t *)peer) + 12); | ||
| 406 | } | 517 | } |
| 407 | 518 | ||
| 408 | void exerr( char * message ) { | 519 | size_t peer_size_from_peer6(ot_peer6 *peer) { |
| 409 | fprintf( stderr, "%s\n", message ); | 520 | ot_ip6 *ip = (ot_ip6 *)peer; |
| 410 | exit( 111 ); | 521 | if (!ip6_isv4mapped(ip)) |
| 522 | return OT_PEER_SIZE6; | ||
| 523 | return OT_PEER_SIZE4; | ||
| 411 | } | 524 | } |
| 412 | 525 | ||
| 413 | void trackerlogic_init( ) { | 526 | #ifdef _DEBUG_RANDOMTORRENTS |
| 527 | void trackerlogic_add_random_torrents(size_t amount) { | ||
| 528 | struct ot_workstruct ws; | ||
| 529 | memset(&ws, 0, sizeof(ws)); | ||
| 530 | |||
| 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; | ||
| 535 | |||
| 536 | while (amount--) { | ||
| 537 | arc4random_buf(ws.hash, sizeof(ot_hash)); | ||
| 538 | arc4random_buf(&ws.peer, sizeof(ws.peer)); | ||
| 539 | |||
| 540 | OT_PEERFLAG(ws.peer) &= PEER_FLAG_SEEDING | PEER_FLAG_COMPLETED | PEER_FLAG_STOPPED; | ||
| 541 | |||
| 542 | add_peer_to_torrent_and_return_peers(FLAG_TCP, &ws, 1); | ||
| 543 | } | ||
| 544 | |||
| 545 | free(ws.inbuf); | ||
| 546 | free(ws.outbuf); | ||
| 547 | } | ||
| 548 | #endif | ||
| 549 | |||
| 550 | void exerr(char *message) { | ||
| 551 | fprintf(stderr, "%s\n", message); | ||
| 552 | exit(111); | ||
| 553 | } | ||
| 554 | |||
| 555 | void trackerlogic_init() { | ||
| 414 | g_tracker_id = random(); | 556 | g_tracker_id = random(); |
| 415 | 557 | ||
| 416 | if( !g_stats_path ) | 558 | if (!g_stats_path) |
| 417 | g_stats_path = "stats"; | 559 | g_stats_path = "stats"; |
| 418 | g_stats_path_len = strlen( g_stats_path ); | 560 | g_stats_path_len = strlen(g_stats_path); |
| 419 | 561 | ||
| 420 | /* Initialise background worker threads */ | 562 | /* Initialise background worker threads */ |
| 421 | mutex_init( ); | 563 | mutex_init(); |
| 422 | clean_init( ); | 564 | clean_init(); |
| 423 | fullscrape_init( ); | 565 | fullscrape_init(); |
| 424 | accesslist_init( ); | 566 | accesslist_init(); |
| 425 | livesync_init( ); | 567 | livesync_init(); |
| 426 | stats_init( ); | 568 | stats_init(); |
| 427 | } | 569 | } |
| 428 | 570 | ||
| 429 | void trackerlogic_deinit( void ) { | 571 | void trackerlogic_deinit(void) { |
| 430 | int bucket, delta_torrentcount = 0; | 572 | int bucket, delta_torrentcount = 0; |
| 431 | size_t j; | 573 | size_t j; |
| 432 | 574 | ||
| 433 | /* Free all torrents... */ | 575 | /* Free all torrents... */ |
| 434 | for(bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { | 576 | for (bucket = 0; bucket < OT_BUCKET_COUNT; ++bucket) { |
| 435 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); | 577 | ot_vector *torrents_list = mutex_bucket_lock(bucket); |
| 436 | if( torrents_list->size ) { | 578 | if (torrents_list->size) { |
| 437 | for( j=0; j<torrents_list->size; ++j ) { | 579 | for (j = 0; j < torrents_list->size; ++j) { |
| 438 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j; | 580 | ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + j; |
| 439 | free_peerlist( torrent->peer_list ); | 581 | free_peerlist(torrent->peer_list6); |
| 582 | free_peerlist(torrent->peer_list4); | ||
| 440 | delta_torrentcount -= 1; | 583 | delta_torrentcount -= 1; |
| 441 | } | 584 | } |
| 442 | free( torrents_list->data ); | 585 | free(torrents_list->data); |
| 443 | } | 586 | } |
| 444 | mutex_bucket_unlock( bucket, delta_torrentcount ); | 587 | mutex_bucket_unlock(bucket, delta_torrentcount); |
| 445 | } | 588 | } |
| 446 | 589 | ||
| 447 | /* Deinitialise background worker threads */ | 590 | /* Deinitialise background worker threads */ |
| 448 | stats_deinit( ); | 591 | stats_deinit(); |
| 449 | livesync_deinit( ); | 592 | livesync_deinit(); |
| 450 | accesslist_deinit( ); | 593 | accesslist_deinit(); |
| 451 | fullscrape_deinit( ); | 594 | fullscrape_deinit(); |
| 452 | clean_deinit( ); | 595 | clean_deinit(); |
| 453 | /* Release mutexes */ | 596 | /* Release mutexes */ |
| 454 | mutex_deinit( ); | 597 | mutex_deinit(); |
| 455 | } | 598 | } |
| 456 | |||
| 457 | const char *g_version_trackerlogic_c = "$Source$: $Revision$\n"; | ||
