diff options
Diffstat (limited to 'trackerlogic.c')
-rw-r--r-- | trackerlogic.c | 635 |
1 files changed, 388 insertions, 247 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index ea4b489..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( struct ot_workstruct * ws, 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); |
51 | 50 | ||
52 | if( !accesslist_hashisvalid( hash ) ) | 51 | if (!accesslist_hashisvalid(hash)) |
53 | return mutex_bucket_unlock_by_hash( hash, 0 ); | 52 | return mutex_bucket_unlock_by_hash(hash, 0); |
54 | 53 | ||
55 | torrent = vector_find_or_insert( torrents_list, (void*)hash, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 54 | torrent = vector_find_or_insert(torrents_list, (void *)hash, sizeof(ot_torrent), OT_HASH_COMPARE_SIZE, &exactmatch); |
56 | if( !torrent || exactmatch ) | 55 | if (!torrent || exactmatch) |
57 | return mutex_bucket_unlock_by_hash( hash, 0 ); | 56 | 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)); |
60 | memcpy(torrent->hash, hash, sizeof(ot_hash)); | ||
61 | 61 | ||
62 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { | 62 | if (!(torrent->peer_list6 = malloc(sizeof(ot_peerlist))) || !(torrent->peer_list4 = malloc(sizeof(ot_peerlist)))) { |
63 | vector_remove_torrent( torrents_list, torrent ); | 63 | vector_remove_torrent(torrents_list, torrent); |
64 | return mutex_bucket_unlock_by_hash( hash, 0 ); | 64 | return mutex_bucket_unlock_by_hash(hash, 0); |
65 | } | 65 | } |
66 | 66 | ||
67 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); | 67 | byte_zero(torrent->peer_list6, sizeof(ot_peerlist)); |
68 | torrent->peer_list->base = base; | 68 | byte_zero(torrent->peer_list4, sizeof(ot_peerlist)); |
69 | torrent->peer_list->down_count = down_count; | 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; | ||
70 | 73 | ||
71 | return mutex_bucket_unlock_by_hash( hash, 1 ); | 74 | return mutex_bucket_unlock_by_hash(hash, 1); |
72 | } | 75 | } |
73 | 76 | ||
74 | size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) { | 77 | size_t add_peer_to_torrent_and_return_peers(PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount) { |
75 | int exactmatch, delta_torrentcount = 0; | 78 | int exactmatch, delta_torrentcount = 0; |
76 | ot_torrent *torrent; | 79 | ot_torrent *torrent; |
77 | ot_peer *peer_dest; | 80 | ot_peer *peer_dest; |
78 | ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash ); | 81 | ot_vector *torrents_list = mutex_bucket_lock_by_hash(*ws->hash); |
79 | 82 | ot_peerlist *peer_list; | |
80 | if( !accesslist_hashisvalid( *ws->hash ) ) { | 83 | size_t peer_size; /* initialized in next line */ |
81 | mutex_bucket_unlock_by_hash( *ws->hash, 0 ); | 84 | ot_peer const *peer_src = peer_from_peer6(&ws->peer, &peer_size); |
82 | if( proto == FLAG_TCP ) { | 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); |
110 | 118 | ||
111 | torrent->peer_list->base = g_now_minutes; | 119 | torrent->peer_list6->base = g_now_minutes; |
120 | torrent->peer_list4->base = g_now_minutes; | ||
121 | |||
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( ws, 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( struct ot_workstruct *ws, 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; |
234 | char *r_end = reply + result; | ||
221 | 235 | ||
222 | if( OT_PEERLIST_HASBUCKETS(peer_list) ) { | 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 = nrand48(ws->rand48_state) % 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 + nrand48(ws->rand48_state) % 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( struct ot_workstruct * ws, 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); | ||
297 | } | ||
298 | return r - reply; | ||
299 | } | ||
300 | |||
301 | static size_t return_peers_for_torrent_tcp(struct ot_workstruct *ws, ot_torrent *torrent, size_t amount, char *reply) { | ||
302 | char *r = reply; | ||
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; | ||
280 | } | 342 | } |
281 | 343 | ||
282 | if( amount ) { | 344 | r += |
283 | if( amount == peer_list->peer_count ) | 345 | sprintf(r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie", seed_count, down_count, peer_count, erval, erval / 2); |
284 | r += return_peers_all( peer_list, r ); | 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( ws, 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; | ||
514 | } | ||
515 | *peer_size = OT_PEER_SIZE4; | ||
516 | return (ot_peer *)(((uint8_t *)peer) + 12); | ||
517 | } | ||
518 | |||
519 | size_t peer_size_from_peer6(ot_peer6 *peer) { | ||
520 | ot_ip6 *ip = (ot_ip6 *)peer; | ||
521 | if (!ip6_isv4mapped(ip)) | ||
522 | return OT_PEER_SIZE6; | ||
523 | return OT_PEER_SIZE4; | ||
524 | } | ||
525 | |||
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); | ||
405 | } | 543 | } |
544 | |||
545 | free(ws.inbuf); | ||
546 | free(ws.outbuf); | ||
406 | } | 547 | } |
548 | #endif | ||
407 | 549 | ||
408 | void exerr( char * message ) { | 550 | void exerr(char *message) { |
409 | fprintf( stderr, "%s\n", message ); | 551 | fprintf(stderr, "%s\n", message); |
410 | exit( 111 ); | 552 | exit(111); |
411 | } | 553 | } |
412 | 554 | ||
413 | void trackerlogic_init( ) { | 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"; | ||