summaryrefslogtreecommitdiff
path: root/trackerlogic.c
diff options
context:
space:
mode:
Diffstat (limited to 'trackerlogic.c')
-rw-r--r--trackerlogic.c104
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 279static 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*/
287size_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
301static 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*/
375size_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 */
320size_t return_udp_scrape_for_torrent( ot_hash const hash, char *reply ) { 380size_t return_udp_scrape_for_torrent( ot_hash const hash, char *reply ) {
321 int exactmatch, delta_torrentcount = 0; 381 int exactmatch, delta_torrentcount = 0;