diff options
-rw-r--r-- | ot_http.c | 2 | ||||
-rw-r--r-- | trackerlogic.c | 104 | ||||
-rw-r--r-- | trackerlogic.h | 2 |
3 files changed, 84 insertions, 24 deletions
@@ -588,7 +588,7 @@ ssize_t http_handle_request( const int64 sock, struct ot_workstruct *ws ) { | |||
588 | memcpy( ws->debugbuf, ws->request, reply_off ); | 588 | memcpy( ws->debugbuf, ws->request, reply_off ); |
589 | ws->debugbuf[ reply_off ] = 0; | 589 | ws->debugbuf[ reply_off ] = 0; |
590 | #endif | 590 | #endif |
591 | 591 | ||
592 | /* Tell subroutines where to put reply data */ | 592 | /* Tell subroutines where to put reply data */ |
593 | ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH; | 593 | ws->reply = ws->outbuf + SUCCESS_HTTP_HEADER_LENGTH; |
594 | 594 | ||
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; |
diff --git a/trackerlogic.h b/trackerlogic.h index 4fb8bc7..9f5886d 100644 --- a/trackerlogic.h +++ b/trackerlogic.h | |||
@@ -82,7 +82,7 @@ typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG; | |||
82 | #define OT_PEER_SIZE6 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE6)) | 82 | #define OT_PEER_SIZE6 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE6)) |
83 | #define OT_PEER_SIZE4 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE4)) | 83 | #define OT_PEER_SIZE4 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE4)) |
84 | 84 | ||
85 | typedef uint8_t ot_peer[1]; /* Generic pointer to a v6 or v4 peer */ | 85 | typedef uint8_t ot_peer; /* Generic pointer to a v6 or v4 peer */ |
86 | typedef uint8_t ot_peer6[OT_PEER_SIZE6]; | 86 | typedef uint8_t ot_peer6[OT_PEER_SIZE6]; |
87 | typedef uint8_t ot_peer4[OT_PEER_SIZE4]; | 87 | typedef uint8_t ot_peer4[OT_PEER_SIZE4]; |
88 | static const uint8_t PEER_FLAG_SEEDING = 0x80; | 88 | static const uint8_t PEER_FLAG_SEEDING = 0x80; |