diff options
Diffstat (limited to 'trackerlogic.c')
-rw-r--r-- | trackerlogic.c | 104 |
1 files changed, 82 insertions, 22 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index a0bbeb4..b52b478 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
@@ -276,32 +276,18 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee | |||
276 | return result; | 276 | return result; |
277 | } | 277 | } |
278 | 278 | ||
279 | /* Compiles a list of random peers for a torrent | 279 | static size_t return_peers_for_torrent_udp( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply ) { |
280 | * Reply must have enough space to hold: | 280 | char *r = reply; |
281 | * 92 + 6 * amount bytes for TCP/IPv4 | ||
282 | * 92 + 18 * amount bytes for TCP/IPv6 | ||
283 | * 12 + 6 * amount bytes for UDP/IPv4 | ||
284 | * 12 + 18 * amount bytes for UDP/IPv6 | ||
285 | * Does not yet check not to return self | ||
286 | */ | ||
287 | size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) { | ||
288 | size_t peer_size = peer_size_from_peer6(&ws->peer); | 281 | size_t peer_size = peer_size_from_peer6(&ws->peer); |
289 | ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; | 282 | ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4; |
290 | char *r = reply; | ||
291 | size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); | ||
292 | 283 | ||
293 | if( amount > peer_list->peer_count ) | 284 | if( amount > peer_list->peer_count ) |
294 | amount = peer_list->peer_count; | 285 | amount = peer_list->peer_count; |
295 | 286 | ||
296 | if( proto == FLAG_TCP ) { | 287 | *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
297 | int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM; | 288 | *(uint32_t*)(r+4) = htonl( peer_list->peer_count - peer_list->seed_count ); |
298 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s%zd:", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count, erval, erval/2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4, compare_size * amount ); | 289 | *(uint32_t*)(r+8) = htonl( peer_list->seed_count ); |
299 | } else { | 290 | r += 12; |
300 | *(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | ||
301 | *(uint32_t*)(r+4) = htonl( peer_list->peer_count - peer_list->seed_count ); | ||
302 | *(uint32_t*)(r+8) = htonl( peer_list->seed_count ); | ||
303 | r += 12; | ||
304 | } | ||
305 | 291 | ||
306 | if( amount ) { | 292 | if( amount ) { |
307 | if( amount == peer_list->peer_count ) | 293 | if( amount == peer_list->peer_count ) |
@@ -309,13 +295,87 @@ size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, | |||
309 | else | 295 | else |
310 | r += return_peers_selection( ws, peer_list, peer_size, amount, r ); | 296 | r += return_peers_selection( ws, peer_list, peer_size, amount, r ); |
311 | } | 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; | ||
342 | } | ||
343 | |||
344 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zde8:intervali%ie12:min intervali%ie", seed_count, down_count, peer_count, erval, erval/2 ); | ||
345 | |||
346 | if( amount_v4 ) { | ||
347 | r += sprintf( r, PEERS_BENCODED4 "%zd:", OT_PEER_COMPARE_SIZE4 * amount_v4); | ||
348 | if( amount_v4 == torrent->peer_list4->peer_count ) | ||
349 | r += return_peers_all( torrent->peer_list4, OT_PEER_SIZE4, r ); | ||
350 | else | ||
351 | r += return_peers_selection( ws, torrent->peer_list4, OT_PEER_SIZE4, amount_v4, r ); | ||
352 | } | ||
312 | 353 | ||
313 | if( proto == FLAG_TCP ) | 354 | if( amount_v6 ) { |
314 | *r++ = 'e'; | 355 | r += sprintf( r, PEERS_BENCODED6 "%zd:", OT_PEER_COMPARE_SIZE6 * amount_v6); |
356 | if( amount_v6 == torrent->peer_list6->peer_count ) | ||
357 | r += return_peers_all( torrent->peer_list6, OT_PEER_SIZE6, r ); | ||
358 | else | ||
359 | r += return_peers_selection( ws, torrent->peer_list6, OT_PEER_SIZE6, amount_v6, r ); | ||
360 | } | ||
361 | |||
362 | *r++ = 'e'; | ||
315 | 363 | ||
316 | return r - reply; | 364 | return r - reply; |
317 | } | 365 | } |
318 | 366 | ||
367 | /* Compiles a list of random peers for a torrent | ||
368 | * Reply must have enough space to hold: | ||
369 | * 92 + 6 * amount bytes for TCP/IPv4 | ||
370 | * 92 + 18 * amount bytes for TCP/IPv6 | ||
371 | * 12 + 6 * amount bytes for UDP/IPv4 | ||
372 | * 12 + 18 * amount bytes for UDP/IPv6 | ||
373 | * Does not yet check not to return self | ||
374 | */ | ||
375 | size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) { | ||
376 | return proto == FLAG_TCP ? return_peers_for_torrent_tcp(ws, torrent, amount, reply) : return_peers_for_torrent_udp(ws, torrent, amount, reply); | ||
377 | } | ||
378 | |||
319 | /* Fetches scrape info for a specific torrent */ | 379 | /* Fetches scrape info for a specific torrent */ |
320 | size_t return_udp_scrape_for_torrent( ot_hash const hash, char *reply ) { | 380 | size_t return_udp_scrape_for_torrent( ot_hash const hash, char *reply ) { |
321 | int exactmatch, delta_torrentcount = 0; | 381 | int exactmatch, delta_torrentcount = 0; |