diff options
| author | Dirk Engling <erdgeist@erdgeist.org> | 2024-04-06 19:21:03 +0200 |
|---|---|---|
| committer | Dirk Engling <erdgeist@erdgeist.org> | 2024-04-06 19:21:03 +0200 |
| commit | d9a5f046754581f0edaa0e385f865bcc5ee842e3 (patch) | |
| tree | c73dc6a2ae9b1c0fa96c8dde05a11f60cae745fe | |
| parent | 880d5145a0644e348e06f5660de5c2256fdebd25 (diff) | |
Return peer from both address families on announce
| -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; |
