Prepare opentracker for dual stack capabilities

master
Dirk Engling 9 months ago
parent eb8834f778
commit 2afc4893bf

@ -20,36 +20,36 @@
#include "ot_accesslist.h"
/* Returns amount of removed peers */
static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) {
ot_peer *last_peer = peers + peer_count, *insert_point;
time_t timediff;
static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders ) {
ot_peer *last_peer = peers + peer_count * peer_size, *insert_point;
/* Two scan modes: unless there is one peer removed, just increase ot_peertime */
while( peers < last_peer ) {
if( ( timediff = timedout + OT_PEERTIME( peers ) ) >= OT_PEER_TIMEOUT )
time_t timediff = timedout + OT_PEERTIME( peers, peer_size );
if( timediff >= OT_PEER_TIMEOUT )
break;
OT_PEERTIME( peers++ ) = timediff;
OT_PEERTIME( peers, peer_size ) = timediff;
peers += peer_size;
}
/* If we at least remove one peer, we have to copy */
insert_point = peers;
while( peers < last_peer )
if( ( timediff = timedout + OT_PEERTIME( peers ) ) < OT_PEER_TIMEOUT ) {
OT_PEERTIME( peers ) = timediff;
memcpy( insert_point++, peers++, sizeof(ot_peer));
/* If we at least remove one peer, we have to copy */
for( insert_point = peers; peers < last_peer; peers += peer_size ) {
time_t timediff = timedout + OT_PEERTIME( peers, peer_size );
if( timediff < OT_PEER_TIMEOUT ) {
OT_PEERTIME( peers, peer_size ) = timediff;
memcpy( insert_point, peers, peer_size);
insert_point += peer_size;
} else
if( OT_PEERFLAG( peers++ ) & PEER_FLAG_SEEDING )
if( OT_PEERFLAG_D( peers, peer_size ) & PEER_FLAG_SEEDING )
(*removed_seeders)++;
}
return peers - insert_point;
}
/* Clean a single torrent
return 1 if torrent timed out
*/
int clean_single_torrent( ot_torrent *torrent ) {
ot_peerlist *peer_list = torrent->peer_list;
ot_vector *bucket_list = &peer_list->peers;
int clean_single_peer_list( ot_peerlist *peer_list, size_t peer_size ) {
ot_vector *peer_vector = &peer_list->peers;
time_t timedout = (time_t)( g_now_minutes - peer_list->base );
int num_buckets = 1, removed_seeders = 0;
@ -69,24 +69,26 @@ int clean_single_torrent( ot_torrent *torrent ) {
}
if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
num_buckets = bucket_list->size;
bucket_list = (ot_vector *)bucket_list->data;
num_buckets = peer_vector->size;
peer_vector = (ot_vector *)peer_vector->data;
}
while( num_buckets-- ) {
size_t removed_peers = clean_single_bucket( bucket_list->data, bucket_list->size, timedout, &removed_seeders );
size_t removed_peers = clean_single_bucket( peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders );
peer_list->peer_count -= removed_peers;
bucket_list->size -= removed_peers;
if( bucket_list->size < removed_peers )
vector_fixup_peers( bucket_list );
++bucket_list;
peer_vector->size -= removed_peers;
if( removed_peers )
vector_fixup_peers( peer_vector, peer_size );
/* Skip to next bucket, a vector containing peers */
++peer_vector;
}
peer_list->seed_count -= removed_seeders;
/* See, if we need to convert a torrent from simple vector to bucket list */
/* See if we need to convert a torrent from simple vector to bucket list */
if( ( peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT ) || OT_PEERLIST_HASBUCKETS(peer_list) )
vector_redistribute_buckets( peer_list );
vector_redistribute_buckets( peer_list, peer_size );
if( peer_list->peer_count )
peer_list->base = g_now_minutes;
@ -96,7 +98,14 @@ int clean_single_torrent( ot_torrent *torrent ) {
peer_list->base = g_now_minutes - OT_PEER_TIMEOUT;
}
return 0;
}
/* Clean a single torrent
return 1 if torrent timed out
*/
int clean_single_torrent( ot_torrent *torrent ) {
return clean_single_peer_list( torrent->peer_list6, OT_PEER_SIZE6) *
clean_single_peer_list( torrent->peer_list4, OT_PEER_SIZE4);
}
/* Clean up all peers in current bucket, remove timedout pools and

@ -82,7 +82,11 @@ void fullscrape_deliver( int64 sock, ot_tasktype tasktype ) {
mutex_workqueue_pushtask( sock, tasktype );
}
static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_peerlist *peer_list, ot_hash *hash ) {
static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_torrent *torrent, ot_hash *hash ) {
size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
size_t down_count = torrent->peer_list6->down_count + torrent->peer_list4->down_count;
switch( mode & TASK_TASK_MASK ) {
case TASK_FULLSCRAPE:
default:
@ -90,30 +94,30 @@ static char * fullscrape_write_one( ot_tasktype mode, char *r, ot_peerlist *peer
*r++='2'; *r++='0'; *r++=':';
memcpy( r, hash, sizeof(ot_hash) ); r += sizeof(ot_hash);
/* push rest of the scrape string */
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count );
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seed_count, down_count, peer_count-seed_count );
break;
case TASK_FULLSCRAPE_TPB_ASCII:
to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count );
r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count );
break;
case TASK_FULLSCRAPE_TPB_ASCII_PLUS:
to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
r += sprintf( r, ":%zd:%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count, peer_list->down_count );
r += sprintf( r, ":%zd:%zd:%zd\n", seed_count, peer_count-seed_count, down_count );
break;
case TASK_FULLSCRAPE_TPB_BINARY:
memcpy( r, *hash, sizeof(ot_hash) ); r += sizeof(ot_hash);
*(uint32_t*)(r+0) = htonl( (uint32_t) peer_list->seed_count );
*(uint32_t*)(r+4) = htonl( (uint32_t)( peer_list->peer_count-peer_list->seed_count) );
*(uint32_t*)(r+0) = htonl( (uint32_t) seed_count );
*(uint32_t*)(r+4) = htonl( (uint32_t)( peer_count-seed_count) );
r+=8;
break;
case TASK_FULLSCRAPE_TPB_URLENCODED:
r += fmt_urlencoded( r, (char *)*hash, 20 );
r += sprintf( r, ":%zd:%zd\n", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count );
r += sprintf( r, ":%zd:%zd\n", seed_count, peer_count-seed_count );
break;
case TASK_FULLSCRAPE_TRACKERSTATE:
to_hex( r, *hash ); r+= 2 * sizeof(ot_hash);
r += sprintf( r, ":%zd:%zd\n", peer_list->base, peer_list->down_count );
r += sprintf( r, ":%zd:%zd\n", torrent->peer_list6->base, down_count );
break;
}
return r;
@ -145,7 +149,7 @@ static void fullscrape_make( int *iovec_entries, struct iovec **iovector, ot_tas
/* For each torrent in this bucket.. */
for( i=0; i<torrents_list->size; ++i ) {
r = fullscrape_write_one( mode, r, torrents[i].peer_list, &torrents[i].hash );
r = fullscrape_write_one( mode, r, torrents+i, &torrents[i].hash );
if( r > re) {
/* Allocate a fresh output buffer at the end of our buffers list */
@ -210,7 +214,7 @@ static void fullscrape_make_gzip( int *iovec_entries, struct iovec **iovector, o
/* For each torrent in this bucket.. */
for( i=0; i<torrents_list->size; ++i ) {
char compress_buffer[OT_SCRAPE_MAXENTRYLEN];
r = fullscrape_write_one( mode, compress_buffer, torrents[i].peer_list, &torrents[i].hash );
r = fullscrape_write_one( mode, compress_buffer, torrents+i, &torrents[i].hash );
strm.next_in = (uint8_t*)compress_buffer;
strm.avail_in = r - compress_buffer;
zres = deflate( &strm, Z_NO_FLUSH );

@ -421,26 +421,18 @@ static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws,
ot_ip6 proxied_ip;
char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" );
if( fwd && scan_ip6( fwd, proxied_ip ) ) {
/* If proxy reports an ipv6 address but we can only handle v4 (or vice versa), bail out */
#ifndef WANT_V6
if( !ip6_isv4mapped(proxied_ip) )
#else
if( ip6_isv4mapped(proxied_ip) )
#endif
HTTPERROR_400_PARAM;
OT_SETIP( &ws->peer, proxied_ip );
OT_SETIP( ws->peer, proxied_ip );
} else
OT_SETIP( &ws->peer, cookie->ip );
OT_SETIP( ws->peer, cookie->ip );
} else
#endif
OT_SETIP( &ws->peer, cookie->ip );
OT_SETIP( ws->peer, cookie->ip );
ws->peer_id = NULL;
ws->hash = NULL;
OT_SETPORT( &ws->peer, &port );
OT_PEERFLAG( &ws->peer ) = 0;
OT_SETPORT( ws->peer, &port );
OT_PEERFLAG( ws->peer ) = 0;
numwant = 50;
scanon = 1;

@ -127,13 +127,13 @@ static void livesync_handle_peersync( struct ot_workstruct *ws ) {
/* Now basic sanity checks have been done on the live sync packet
We might add more testing and logging. */
while( off + (ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer ) <= ws->request_size ) {
memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), sizeof( ot_peer ) );
while( off + (ssize_t)sizeof( ot_hash ) + OT_PEER_SIZE4 <= ws->request_size ) {
memcpy( &ws->peer, ws->request + off + sizeof(ot_hash), OT_PEER_SIZE4 );
ws->hash = (ot_hash*)(ws->request + off);
if( !g_opentracker_running ) return;
if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_STOPPED )
if( OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED )
remove_peer_from_torrent( FLAG_MCA, ws );
else
add_peer_to_torrent_and_return_peers( FLAG_MCA, ws, /* amount = */ 0 );
@ -143,7 +143,7 @@ static void livesync_handle_peersync( struct ot_workstruct *ws ) {
stats_issue_event(EVENT_SYNC, 0,
(ws->request_size - sizeof( g_tracker_id ) - sizeof( uint32_t ) ) /
((ssize_t)sizeof( ot_hash ) + (ssize_t)sizeof( ot_peer )));
((ssize_t)sizeof( ot_hash ) + OT_PEER_SIZE4));
}
/* Tickle the live sync module from time to time, so no events get
@ -164,9 +164,9 @@ void livesync_tell( struct ot_workstruct *ws ) {
pthread_mutex_lock(&g_outbuf_mutex);
memcpy( g_outbuf + g_outbuf_data, ws->hash, sizeof(ot_hash) );
memcpy( g_outbuf + g_outbuf_data + sizeof(ot_hash), &ws->peer, sizeof(ot_peer) );
memcpy( g_outbuf + g_outbuf_data + sizeof(ot_hash), &ws->peer, OT_PEER_SIZE4 );
g_outbuf_data += sizeof(ot_hash) + sizeof(ot_peer);
g_outbuf_data += sizeof(ot_hash) + OT_PEER_SIZE4;
if( g_outbuf_data >= LIVESYNC_OUTGOING_BUFFSIZE_PEERS - LIVESYNC_OUTGOING_WATERMARK_PEERS )
livesync_issue_peersync();

@ -43,7 +43,7 @@ typedef enum {
TASK_STATS_EVERYTHING = 0x0106,
TASK_STATS_FULLLOG = 0x0107,
TASK_STATS_WOODPECKERS = 0x0108,
TASK_FULLSCRAPE = 0x0200, /* Default mode */
TASK_FULLSCRAPE_TPB_BINARY = 0x0201,
TASK_FULLSCRAPE_TPB_ASCII = 0x0202,

@ -73,13 +73,13 @@ static time_t ot_start_time;
#define __LDR(P,D) ((__BYTE((P),(D))>>__SHFT((D)))&__MSK)
#define __STR(P,D,V) __BYTE((P),(D))=(__BYTE((P),(D))&~(__MSK<<__SHFT((D))))|((V)<<__SHFT((D)))
#ifdef WANT_V6
#define STATS_NETWORK_NODE_MAXDEPTH (68-STATS_NETWORK_NODE_BITWIDTH)
#define STATS_NETWORK_NODE_LIMIT (48-STATS_NETWORK_NODE_BITWIDTH)
#else
//#ifdef WANT_V6
//#define STATS_NETWORK_NODE_MAXDEPTH (68-STATS_NETWORK_NODE_BITWIDTH)
//#define STATS_NETWORK_NODE_LIMIT (48-STATS_NETWORK_NODE_BITWIDTH)
//#else
#define STATS_NETWORK_NODE_MAXDEPTH (28-STATS_NETWORK_NODE_BITWIDTH)
#define STATS_NETWORK_NODE_LIMIT (24-STATS_NETWORK_NODE_BITWIDTH)
#endif
//#endif
typedef union stats_network_node stats_network_node;
union stats_network_node {
@ -219,12 +219,12 @@ static size_t stats_slash24s_txt( char *reply, size_t amount ) {
stats_network_node *slash24s_network_counters_root = NULL;
char *r=reply;
int bucket;
size_t i;
size_t i, peer_size = OT_PEER_SIZE4;
for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
ot_vector *torrents_list = mutex_bucket_lock( bucket );
for( i=0; i<torrents_list->size; ++i ) {
ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list;
ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list4;
ot_vector *bucket_list = &peer_list->peers;
int num_buckets = 1;
@ -236,9 +236,11 @@ static size_t stats_slash24s_txt( char *reply, size_t amount ) {
while( num_buckets-- ) {
ot_peer *peers = (ot_peer*)bucket_list->data;
size_t numpeers = bucket_list->size;
while( numpeers-- )
if( stat_increase_network_count( &slash24s_network_counters_root, 0, (uintptr_t)(peers++) ) )
while( numpeers-- ) {
if( stat_increase_network_count( &slash24s_network_counters_root, 0, (uintptr_t)(peers) ) )
goto bailout_unlock;
peers += peer_size;
}
++bucket_list;
}
}
@ -285,8 +287,8 @@ typedef struct {
static int torrent_statter( ot_torrent *torrent, uintptr_t data ) {
torrent_stats *stats = (torrent_stats*)data;
stats->torrent_count++;
stats->peer_count += torrent->peer_list->peer_count;
stats->seed_count += torrent->peer_list->seed_count;
stats->peer_count += torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
stats->seed_count += torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
return 0;
}
@ -312,21 +314,23 @@ size_t stats_top_txt( char * reply, int amount ) {
ot_vector *torrents_list = mutex_bucket_lock( bucket );
for( j=0; j<torrents_list->size; ++j ) {
ot_torrent *torrent = (ot_torrent*)(torrents_list->data) + j;
size_t peer_count = torrent->peer_list6->peer_count + torrent->peer_list4->peer_count;
size_t seed_count = torrent->peer_list6->seed_count + torrent->peer_list4->seed_count;
idx = amount - 1;
while( (idx >= 0) && ( torrent->peer_list->peer_count > top100c[idx].val ) )
while( (idx >= 0) && ( peer_count > top100c[idx].val ) )
--idx;
if ( idx++ != amount - 1 ) {
memmove( top100c + idx + 1, top100c + idx, ( amount - 1 - idx ) * sizeof( ot_record ) );
memcpy( &top100c[idx].hash, &torrent->hash, sizeof(ot_hash));
top100c[idx].val = torrent->peer_list->peer_count;
top100c[idx].val = peer_count;
}
idx = amount - 1;
while( (idx >= 0) && ( torrent->peer_list->seed_count > top100s[idx].val ) )
while( (idx >= 0) && ( seed_count > top100s[idx].val ) )
--idx;
if ( idx++ != amount - 1 ) {
memmove( top100s + idx + 1, top100s + idx, ( amount - 1 - idx ) * sizeof( ot_record ) );
memcpy( &top100s[idx].hash, &torrent->hash, sizeof(ot_hash));
top100s[idx].val = torrent->peer_list->seed_count;
top100s[idx].val = seed_count;
}
}
mutex_bucket_unlock( bucket, 0 );
@ -718,7 +722,7 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uintptr_t event
break;
case EVENT_SYNC:
ot_overall_sync_count+=event_data;
break;
break;
case EVENT_BUCKET_LOCKED:
ot_overall_stall_count++;
break;

@ -13,6 +13,7 @@
/* Libowfat */
#include "socket.h"
#include "io.h"
#include "ip6.h"
/* Opentracker */
#include "trackerlogic.h"
@ -73,7 +74,7 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
ot_ip6 remoteip;
uint32_t *inpacket = (uint32_t*)ws->inbuf;
uint32_t *outpacket = (uint32_t*)ws->outbuf;
uint32_t numwant, left, event, scopeid;
uint32_t left, event, scopeid;
uint32_t connid[2];
uint32_t action;
uint16_t port, remoteport;
@ -141,34 +142,35 @@ int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) {
/* We do only want to know, if it is zero */
left = inpacket[64/4] | inpacket[68/4];
/* Limit amount of peers to OT_MAX_PEERS_UDP */
numwant = ntohl( inpacket[92/4] );
if (numwant > OT_MAX_PEERS_UDP) numwant = OT_MAX_PEERS_UDP;
event = ntohl( inpacket[80/4] );
port = *(uint16_t*)( ((char*)inpacket) + 96 );
ws->hash = (ot_hash*)( ((char*)inpacket) + 16 );
OT_SETIP( &ws->peer, remoteip );
OT_SETPORT( &ws->peer, &port );
OT_PEERFLAG( &ws->peer ) = 0;
OT_SETIP( ws->peer, remoteip );
OT_SETPORT( ws->peer, &port );
OT_PEERFLAG( ws->peer ) = 0;
switch( event ) {
case 1: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; break;
case 3: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; break;
case 1: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED; break;
case 3: OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED; break;
default: break;
}
if( !left )
OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_SEEDING;
OT_PEERFLAG( ws->peer ) |= PEER_FLAG_SEEDING;
outpacket[0] = htonl( 1 ); /* announce action */
outpacket[1] = inpacket[12/4];
if( OT_PEERFLAG( &ws->peer ) & PEER_FLAG_STOPPED ) { /* Peer is gone. */
if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_STOPPED ) { /* Peer is gone. */
ws->reply = ws->outbuf;
ws->reply_size = remove_peer_from_torrent( FLAG_UDP, ws );
} else {
/* Limit amount of peers to OT_MAX_PEERS_UDP */
uint32_t numwant = ntohl( inpacket[92/4] );
size_t max_peers = ip6_isv4mapped(remoteip) ? OT_MAX_PEERS_UDP4 : OT_MAX_PEERS_UDP6;
if (numwant > max_peers) numwant = max_peers;
ws->reply = ws->outbuf + 8;
ws->reply_size = 8 + add_peer_to_torrent_and_return_peers( FLAG_UDP, ws, numwant );
}

@ -17,8 +17,11 @@
#include "uint32.h"
#include "uint16.h"
static int vector_compare_peer(const void *peer1, const void *peer2 ) {
return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE );
static int vector_compare_peer6(const void *peer1, const void *peer2 ) {
return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE6 );
}
static int vector_compare_peer4(const void *peer1, const void *peer2 ) {
return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE4 );
}
/* This function gives us a binary search that returns a pointer, even if
@ -47,10 +50,10 @@ void *binary_search( const void * const key, const void * base, const size_t mem
return (void*)base;
}
static uint8_t vector_hash_peer( ot_peer *peer, int bucket_count ) {
unsigned int hash = 5381, i = OT_PEER_COMPARE_SIZE;
static uint8_t vector_hash_peer( ot_peer const *peer, size_t compare_size, int bucket_count ) {
unsigned int hash = 5381;
uint8_t *p = (uint8_t*)peer;
while( i-- ) hash += (hash<<5) + *(p++);
while( compare_size-- ) hash += (hash<<5) + *(p++);
return hash % bucket_count;
}
@ -82,27 +85,37 @@ void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, s
return match;
}
ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ) {
ot_peer *match;
ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch ) {
ot_peer *match, *end;
const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
size_t match_to_end;
/* If space is zero but size is set, we're dealing with a list of vector->size buckets */
if( vector->space < vector->size )
vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size );
match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, exactmatch );
vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size );
match = binary_search( peer, vector->data, vector->size, peer_size, compare_size, exactmatch );
if( *exactmatch ) return match;
/* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */
end = (ot_peer*)vector->data + vector->size * peer_size;
match_to_end = end - match;
if( vector->size + 1 > vector->space ) {
ptrdiff_t offset = match - (ot_peer*)vector->data;
size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
ot_peer *new_data = realloc( vector->data, new_space * sizeof(ot_peer) );
ot_peer *new_data = realloc( vector->data, new_space * peer_size );
if( !new_data ) return NULL;
/* Adjust pointer if it moved by realloc */
match = new_data + (match - (ot_peer*)vector->data);
match = new_data + offset;
vector->data = new_data;
vector->space = new_space;
}
memmove( match + 1, match, sizeof(ot_peer) * ( ((ot_peer*)vector->data) + vector->size - match ) );
/* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */
memmove( match + peer_size, match, match_to_end);
vector->size++;
return match;
@ -113,26 +126,27 @@ ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exac
1 if a non-seeding peer was removed
2 if a seeding peer was removed
*/
int vector_remove_peer( ot_vector *vector, ot_peer *peer ) {
int exactmatch;
ot_peer *match, *end;
int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size) {
int exactmatch, was_seeder;
ot_peer *match, *end;
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
if( !vector->size ) return 0;
/* If space is zero but size is set, we're dealing with a list of vector->size buckets */
if( vector->space < vector->size )
vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size );
vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, compare_size, vector->size );
end = ((ot_peer*)vector->data) + vector->size;
match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch );
end = ((ot_peer*)vector->data) + peer_size * vector->size;
match = (ot_peer*)binary_search( peer, vector->data, vector->size, peer_size, compare_size, &exactmatch );
if( !exactmatch ) return 0;
exactmatch = ( OT_PEERFLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1;
memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) );
was_seeder = ( OT_PEERFLAG_D( match, peer_size ) & PEER_FLAG_SEEDING ) ? 2 : 1;
memmove( match, match + peer_size, end - match - peer_size );
vector->size--;
vector_fixup_peers( vector );
return exactmatch;
vector_fixup_peers( vector, peer_size );
return was_seeder;
}
void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
@ -142,7 +156,8 @@ void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) {
/* If this is being called after a unsuccessful malloc() for peer_list
in add_peer_to_torrent, match->peer_list actually might be NULL */
if( match->peer_list) free_peerlist( match->peer_list );
if( match->peer_list6) free_peerlist( match->peer_list6 );
if( match->peer_list4) free_peerlist( match->peer_list4 );
memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) );
if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) {
@ -158,9 +173,11 @@ void vector_clean_list( ot_vector * vector, int num_buckets ) {
return;
}
void vector_redistribute_buckets( ot_peerlist * peer_list ) {
void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size ) {
int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1;
ot_vector * bucket_list_new, * bucket_list_old = &peer_list->peers;
int (*sort_func)(const void *, const void *) =
peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
num_buckets_old = peer_list->peers.size;
@ -198,33 +215,33 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) {
/* preallocate vectors to hold all peers */
for( bucket=0; bucket<num_buckets_new; ++bucket ) {
bucket_list_new[bucket].space = bucket_size_new;
bucket_list_new[bucket].data = malloc( bucket_size_new * sizeof(ot_peer) );
bucket_list_new[bucket].data = malloc( bucket_size_new * peer_size );
if( !bucket_list_new[bucket].data )
return vector_clean_list( bucket_list_new, num_buckets_new );
}
/* Now sort them into the correct bucket */
for( bucket=0; bucket<num_buckets_old; ++bucket ) {
ot_peer * peers_old = bucket_list_old[bucket].data, * peers_new;
ot_peer * peers_old = bucket_list_old[bucket].data;
int peer_count_old = bucket_list_old[bucket].size;
while( peer_count_old-- ) {
ot_vector * bucket_dest = bucket_list_new;
if( num_buckets_new > 1 )
bucket_dest += vector_hash_peer(peers_old, num_buckets_new);
bucket_dest += vector_hash_peer(peers_old, OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size), num_buckets_new);
if( bucket_dest->size + 1 > bucket_dest->space ) {
void * tmp = realloc( bucket_dest->data, sizeof(ot_peer) * OT_VECTOR_GROW_RATIO * bucket_dest->space );
void * tmp = realloc( bucket_dest->data, peer_size * OT_VECTOR_GROW_RATIO * bucket_dest->space );
if( !tmp ) return vector_clean_list( bucket_list_new, num_buckets_new );
bucket_dest->data = tmp;
bucket_dest->space *= OT_VECTOR_GROW_RATIO;
}
peers_new = (ot_peer*)bucket_dest->data;
memcpy(peers_new + bucket_dest->size++, peers_old++, sizeof(ot_peer));
memcpy((ot_peer*)bucket_dest->data + peer_size * bucket_dest->size++, peers_old, peer_size);
peers_old += peer_size;
}
}
/* Now sort each bucket to later allow bsearch */
for( bucket=0; bucket<num_buckets_new; ++bucket )
qsort( bucket_list_new[bucket].data, bucket_list_new[bucket].size, sizeof( ot_peer ), vector_compare_peer );
qsort( bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func );
/* Everything worked fine. Now link new bucket_list to peer_list */
if( OT_PEERLIST_HASBUCKETS( peer_list) )
@ -244,7 +261,7 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) {
}
}
void vector_fixup_peers( ot_vector * vector ) {
void vector_fixup_peers( ot_vector * vector, size_t peer_size ) {
int need_fix = 0;
if( !vector->size ) {
@ -260,7 +277,7 @@ void vector_fixup_peers( ot_vector * vector ) {
need_fix++;
}
if( need_fix )
vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) );
vector->data = realloc( vector->data, vector->space * peer_size );
}
const char *g_version_vector_c = "$Source$: $Revision$\n";

@ -24,11 +24,13 @@ typedef struct {
void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size,
size_t compare_size, int *exactmatch );
void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch );
ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch );
ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch );
int vector_remove_peer( ot_vector *vector, ot_peer *peer );
int vector_remove_peer( ot_vector *vector, ot_peer const *peer, size_t peer_size);
void vector_remove_torrent( ot_vector *vector, ot_torrent *match );
void vector_redistribute_buckets( ot_peerlist * peer_list );
void vector_fixup_peers( ot_vector * vector );
/* For ot_clean.c */
void vector_redistribute_buckets( ot_peerlist * peer_list, size_t peer_size );
void vector_fixup_peers( ot_vector * vector, size_t peer_size );
#endif

@ -16,6 +16,7 @@
#include "byte.h"
#include "io.h"
#include "iob.h"
#include "ip6.h"
#include "array.h"
/* Opentracker */
@ -57,25 +58,33 @@ void add_torrent_from_saved_state( ot_hash hash, ot_time base, size_t down_count
return mutex_bucket_unlock_by_hash( hash, 0 );
/* Create a new torrent entry, then */
byte_zero( torrent, sizeof( ot_torrent ) );
memcpy( torrent->hash, hash, sizeof(ot_hash) );
if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) ||
!( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) {
vector_remove_torrent( torrents_list, torrent );
return mutex_bucket_unlock_by_hash( hash, 0 );
}
byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
torrent->peer_list->base = base;
torrent->peer_list->down_count = down_count;
byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) );
byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) );
torrent->peer_list6->base = base;
torrent->peer_list4->base = base;
torrent->peer_list6->down_count = down_count;
torrent->peer_list4->down_count = down_count;
return mutex_bucket_unlock_by_hash( hash, 1 );
}
size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstruct *ws, size_t amount ) {
int exactmatch, delta_torrentcount = 0;
ot_torrent *torrent;
ot_peer *peer_dest;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
int exactmatch, delta_torrentcount = 0;
ot_torrent *torrent;
ot_peer *peer_dest;
ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
ot_peerlist *peer_list;
size_t peer_size; /* initialized in next line */
ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size);
if( !accesslist_hashisvalid( *ws->hash ) ) {
mutex_bucket_unlock_by_hash( *ws->hash, 0 );
@ -95,82 +104,88 @@ size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstr
if( !exactmatch ) {
/* Create a new torrent entry, then */
byte_zero( torrent, sizeof(ot_torrent));
memcpy( torrent->hash, *ws->hash, sizeof(ot_hash) );
if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) {
if( !( torrent->peer_list6 = malloc( sizeof (ot_peerlist) ) ) ||
!( torrent->peer_list4 = malloc( sizeof (ot_peerlist) ) ) ) {
vector_remove_torrent( torrents_list, torrent );
mutex_bucket_unlock_by_hash( *ws->hash, 0 );
return 0;
}
byte_zero( torrent->peer_list, sizeof( ot_peerlist ) );
byte_zero( torrent->peer_list6, sizeof( ot_peerlist ) );
byte_zero( torrent->peer_list4, sizeof( ot_peerlist ) );
delta_torrentcount = 1;
} else
clean_single_torrent( torrent );
torrent->peer_list->base = g_now_minutes;
torrent->peer_list6->base = g_now_minutes;
torrent->peer_list4->base = g_now_minutes;
peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
/* Check for peer in torrent */
peer_dest = vector_find_or_insert_peer( &(torrent->peer_list->peers), &ws->peer, &exactmatch );
peer_dest = vector_find_or_insert_peer( &(peer_list->peers), peer_src, peer_size, &exactmatch );
if( !peer_dest ) {
mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
return 0;
}
/* Tell peer that it's fresh */
OT_PEERTIME( &ws->peer ) = 0;
OT_PEERTIME( ws->peer, OT_PEER_SIZE6 ) = 0;
/* Sanitize flags: Whoever claims to have completed download, must be a seeder */
if( ( OT_PEERFLAG( &ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
OT_PEERFLAG( &ws->peer ) ^= PEER_FLAG_COMPLETED;
if( ( OT_PEERFLAG( ws->peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED )
OT_PEERFLAG( ws->peer ) ^= PEER_FLAG_COMPLETED;
/* If we hadn't had a match create peer there */
if( !exactmatch ) {
#ifdef WANT_SYNC_LIVE
if( proto == FLAG_MCA )
OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_FROM_SYNC;
OT_PEERFLAG( ws->peer ) |= PEER_FLAG_FROM_SYNC;
else
livesync_tell( ws );
#endif
torrent->peer_list->peer_count++;
if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) {
torrent->peer_list->down_count++;
peer_list->peer_count++;
if( OT_PEERFLAG( ws->peer ) & PEER_FLAG_COMPLETED ) {
peer_list->down_count++;
stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
}
if( OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING )
torrent->peer_list->seed_count++;
if( OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING )
peer_list->seed_count++;
} else {
stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest ) );
stats_issue_event( EVENT_RENEW, 0, OT_PEERTIME( peer_dest, peer_size ) );
#ifdef WANT_SPOT_WOODPECKER
if( ( OT_PEERTIME(peer_dest) > 0 ) && ( OT_PEERTIME(peer_dest) < 20 ) )
if( ( OT_PEERTIME(peer_dest, peer_size) > 0 ) && ( OT_PEERTIME(peer_dest, peer_size) < 20 ) )
stats_issue_event( EVENT_WOODPECKER, 0, (uintptr_t)&ws->peer );
#endif
#ifdef WANT_SYNC_LIVE
/* Won't live sync peers that come back too fast. Only exception:
fresh "completed" reports */
if( proto != FLAG_MCA ) {
if( OT_PEERTIME( peer_dest ) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) )
if( OT_PEERTIME( peer_dest, peer_size ) > OT_CLIENT_SYNC_RENEW_BOUNDARY ||
( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) )
livesync_tell( ws );
}
#endif
if( (OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) )
torrent->peer_list->seed_count--;
if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_SEEDING ) )
torrent->peer_list->seed_count++;
if( !(OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(&ws->peer) & PEER_FLAG_COMPLETED ) ) {
torrent->peer_list->down_count++;
if( (OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && !(OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) )
peer_list->seed_count--;
if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_SEEDING ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_SEEDING ) )
peer_list->seed_count++;
if( !(OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED ) && (OT_PEERFLAG(ws->peer) & PEER_FLAG_COMPLETED ) ) {
peer_list->down_count++;
stats_issue_event( EVENT_COMPLETED, 0, (uintptr_t)ws );
}
if( OT_PEERFLAG(peer_dest) & PEER_FLAG_COMPLETED )
OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED;
if( OT_PEERFLAG_D(peer_dest, peer_size) & PEER_FLAG_COMPLETED )
OT_PEERFLAG( ws->peer ) |= PEER_FLAG_COMPLETED;
}
memcpy( peer_dest, &ws->peer, sizeof(ot_peer) );
memcpy( peer_dest, peer_src, peer_size );
#ifdef WANT_SYNC
if( proto == FLAG_MCA ) {
mutex_bucket_unlock_by_hash( *ws->hash, delta_torrentcount );
@ -183,10 +198,11 @@ size_t add_peer_to_torrent_and_return_peers( PROTO_FLAG proto, struct ot_workstr
return ws->reply_size;
}
static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) {
static size_t return_peers_all( ot_peerlist *peer_list, size_t peer_size, char *reply ) {
unsigned int bucket, num_buckets = 1;
ot_vector * bucket_list = &peer_list->peers;
size_t result = OT_PEER_COMPARE_SIZE * peer_list->peer_count;
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
size_t result = compare_size * peer_list->peer_count;
char * r_end = reply + result;
if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
@ -195,28 +211,30 @@ static size_t return_peers_all( ot_peerlist *peer_list, char *reply ) {
}
for( bucket = 0; bucket<num_buckets; ++bucket ) {
ot_peer * peers = (ot_peer*)bucket_list[bucket].data;
size_t peer_count = bucket_list[bucket].size;
ot_peer *peers = bucket_list[bucket].data;
size_t peer_count = bucket_list[bucket].size;
while( peer_count-- ) {
if( OT_PEERFLAG(peers) & PEER_FLAG_SEEDING ) {
r_end-=OT_PEER_COMPARE_SIZE;
memcpy(r_end,peers++,OT_PEER_COMPARE_SIZE);
if( OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING ) {
r_end -= peer_size;
memcpy( r_end, peers, compare_size);
} else {
memcpy(reply,peers++,OT_PEER_COMPARE_SIZE);
reply+=OT_PEER_COMPARE_SIZE;
memcpy( reply, peers, compare_size );
reply += compare_size;
}
peers += peer_size;
}
}
return result;
}
static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *peer_list, size_t amount, char *reply ) {
static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *peer_list, size_t peer_size, size_t amount, char *reply ) {
unsigned int bucket_offset, bucket_index = 0, num_buckets = 1;
ot_vector * bucket_list = &peer_list->peers;
unsigned int shifted_pc = peer_list->peer_count;
unsigned int shifted_step = 0;
unsigned int shift = 0;
size_t result = OT_PEER_COMPARE_SIZE * amount;
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
size_t result = compare_size * amount;
char * r_end = reply + result;
if( OT_PEERLIST_HASBUCKETS(peer_list) ) {
@ -235,7 +253,7 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
bucket_offset = nrand48(ws->rand48_state) % peer_list->peer_count;
while( amount-- ) {
ot_peer * peer;
ot_peer *peer;
/* This is the aliased, non shifted range, next value may fall into */
unsigned int diff = ( ( ( amount + 1 ) * shifted_step ) >> shift ) -
@ -246,13 +264,13 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
bucket_offset -= bucket_list[bucket_index].size;
bucket_index = ( bucket_index + 1 ) % num_buckets;
}
peer = ((ot_peer*)bucket_list[bucket_index].data) + bucket_offset;
if( OT_PEERFLAG(peer) & PEER_FLAG_SEEDING ) {
r_end-=OT_PEER_COMPARE_SIZE;
memcpy(r_end,peer,OT_PEER_COMPARE_SIZE);
peer = bucket_list[bucket_index].data + peer_size * bucket_offset;
if( OT_PEERFLAG_D(peer, peer_size) & PEER_FLAG_SEEDING ) {
r_end -= compare_size;
memcpy(r_end, peer, compare_size);
} else {
memcpy(reply,peer,OT_PEER_COMPARE_SIZE);
reply+=OT_PEER_COMPARE_SIZE;
memcpy(reply, peer, compare_size);
reply += compare_size;
}
}
return result;
@ -267,15 +285,17 @@ static size_t return_peers_selection( struct ot_workstruct *ws, ot_peerlist *pee
* Does not yet check not to return self
*/
size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent, size_t amount, char *reply, PROTO_FLAG proto ) {
ot_peerlist *peer_list = torrent->peer_list;
size_t peer_size = peer_size_from_peer6(&ws->peer);
ot_peerlist *peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
char *r = reply;
size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
if( amount > peer_list->peer_count )
amount = peer_list->peer_count;
if( proto == FLAG_TCP ) {
int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
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 );
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 );
} else {
*(uint32_t*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM );
*(uint32_t*)(r+4) = htonl( peer_list->peer_count - peer_list->seed_count );
@ -285,9 +305,9 @@ size_t return_peers_for_torrent( struct ot_workstruct * ws, ot_torrent *torrent,
if( amount ) {
if( amount == peer_list->peer_count )
r += return_peers_all( peer_list, r );
r += return_peers_all( peer_list, peer_size, r );
else
r += return_peers_selection( ws, peer_list, amount, r );
r += return_peers_selection( ws, peer_list, peer_size, amount, r );
}
if( proto == FLAG_TCP )
@ -312,9 +332,10 @@ size_t return_udp_scrape_for_torrent( ot_hash hash, char *reply ) {
memset( reply, 0, 12);
delta_torrentcount = -1;
} else {
r[0] = htonl( torrent->peer_list->seed_count );
r[1] = htonl( torrent->peer_list->down_count );
r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count );
r[0] = htonl( torrent->peer_list6->seed_count + torrent->peer_list4->seed_count );
r[1] = htonl( torrent->peer_list6->down_count + torrent->peer_list4->down_count );
r[2] = htonl( torrent->peer_list6->peer_count + torrent->peer_list4->peer_count -
torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
}
}
mutex_bucket_unlock_by_hash( hash, delta_torrentcount );
@ -342,7 +363,10 @@ size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *repl
*r++='2';*r++='0';*r++=':';
memcpy( r, hash, sizeof(ot_hash) ); r+=sizeof(ot_hash);
r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee",
torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count );
torrent->peer_list6->seed_count + torrent->peer_list4->seed_count,
torrent->peer_list6->down_count + torrent->peer_list4->down_count,
torrent->peer_list6->peer_count + torrent->peer_list4->peer_count -
torrent->peer_list6->seed_count - torrent->peer_list4->seed_count);
}
}
mutex_bucket_unlock_by_hash( *hash, delta_torrentcount );
@ -358,17 +382,19 @@ size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) {
ot_vector *torrents_list = mutex_bucket_lock_by_hash( *ws->hash );
ot_torrent *torrent = binary_search( ws->hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch );
ot_peerlist *peer_list = &dummy_list;
size_t peer_size; /* initialized in next line */
ot_peer *peer_src = peer_from_peer6(&ws->peer, &peer_size);
#ifdef WANT_SYNC_LIVE
if( proto != FLAG_MCA ) {
OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED;
OT_PEERFLAG( ws->peer ) |= PEER_FLAG_STOPPED;
livesync_tell( ws );
}
#endif
if( exactmatch ) {
peer_list = torrent->peer_list;
switch( vector_remove_peer( &peer_list->peers, &ws->peer ) ) {
peer_list = peer_size == OT_PEER_SIZE6 ? torrent->peer_list6 : torrent->peer_list4;
switch( vector_remove_peer( &peer_list->peers, peer_src, peer_size ) ) {
case 2: peer_list->seed_count--; /* Intentional fallthrough */
case 1: peer_list->peer_count--; /* Intentional fallthrough */
default: break;
@ -377,7 +403,7 @@ size_t remove_peer_from_torrent( PROTO_FLAG proto, struct ot_workstruct *ws ) {
if( proto == FLAG_TCP ) {
int erval = OT_CLIENT_REQUEST_INTERVAL_RANDOM;
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 );
ws->reply_size = sprintf( ws->reply, "d8:completei%zde10:incompletei%zde8:intervali%ie12:min intervali%ie%s0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, erval, erval / 2, peer_size == OT_PEER_SIZE6 ? PEERS_BENCODED6 : PEERS_BENCODED4 );
}
/* Handle UDP reply */
@ -409,6 +435,23 @@ void iterate_all_torrents( int (*for_each)( ot_torrent* torrent, uintptr_t data
}
}
ot_peer *peer_from_peer6( ot_peer6 *peer, size_t *peer_size ) {
ot_ip6 *ip = (ot_ip6*)peer;
if( !ip6_isv4mapped(ip) ) {
*peer_size = OT_PEER_SIZE6;
return (ot_peer*)peer;
}
*peer_size = OT_PEER_SIZE4;
return (ot_peer*)(((uint8_t*)peer) + 12);
}
size_t peer_size_from_peer6(ot_peer6 *peer) {
ot_ip6 *ip = (ot_ip6*)peer;
if( !ip6_isv4mapped(ip))
return OT_PEER_SIZE6;
return OT_PEER_SIZE4;
}
void exerr( char * message ) {
fprintf( stderr, "%s\n", message );
exit( 111 );
@ -440,7 +483,8 @@ void trackerlogic_deinit( void ) {
if( torrents_list->size ) {
for( j=0; j<torrents_list->size; ++j ) {
ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + j;
free_peerlist( torrent->peer_list );
free_peerlist( torrent->peer_list6 );
free_peerlist( torrent->peer_list4 );
delta_torrentcount -= 1;
}
free( torrents_list->data );

@ -24,16 +24,12 @@ typedef time_t ot_time;
typedef char ot_ip6[16];
typedef struct { ot_ip6 address; int bits; }
ot_net;
#ifdef WANT_V6
#define OT_IP_SIZE 16
#define PEERS_BENCODED "6:peers6"
/* List of peers should fit in a single UDP packet (around 1200 bytes) */
#define OT_MAX_PEERS_UDP 66
#else
#define OT_IP_SIZE 4
#define PEERS_BENCODED "5:peers"
#define OT_MAX_PEERS_UDP 200
#endif
#define OT_MAX_PEERS_UDP6 66
#define OT_MAX_PEERS_UDP4 200
#define OT_IP_SIZE6 16
#define OT_IP_SIZE4 4
#define OT_PORT_SIZE 2
#define OT_FLAG_SIZE 1
#define OT_TIME_SIZE 1
@ -61,6 +57,7 @@ typedef struct { ot_ip6 address; int bits; }
#define OT_ADMINIP_MAX 64
#define OT_MAX_THREADS 64
/* Number of minutes after announce before peer is removed */
#define OT_PEER_TIMEOUT 45
/* We maintain a list of 1024 pointers to sorted list of ot_torrent structs
@ -78,23 +75,35 @@ extern volatile int g_opentracker_running;
extern uint32_t g_tracker_id;
typedef enum { FLAG_TCP, FLAG_UDP, FLAG_MCA, FLAG_SELFPIPE } PROTO_FLAG;
#define OT_PEER_COMPARE_SIZE ((OT_IP_SIZE)+(OT_PORT_SIZE))
#define OT_PEER_SIZE ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE))
typedef uint8_t ot_peer[OT_PEER_SIZE];
#define OT_PEER_COMPARE_SIZE6 ((OT_IP_SIZE6)+(OT_PORT_SIZE))
#define OT_PEER_COMPARE_SIZE4 ((OT_IP_SIZE4)+(OT_PORT_SIZE))
#define OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(PEER_SIZE) ((PEER_SIZE)-(OT_TIME_SIZE)-(OT_FLAG_SIZE))
#define OT_PEER_SIZE6 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE6))
#define OT_PEER_SIZE4 ((OT_TIME_SIZE)+(OT_FLAG_SIZE)+(OT_PEER_COMPARE_SIZE4))
typedef uint8_t ot_peer[1];
typedef uint8_t ot_peer6[OT_PEER_SIZE6];
typedef uint8_t ot_peer4[OT_PEER_SIZE4];
static const uint8_t PEER_FLAG_SEEDING = 0x80;
static const uint8_t PEER_FLAG_COMPLETED = 0x40;
static const uint8_t PEER_FLAG_STOPPED = 0x20;
static const uint8_t PEER_FLAG_FROM_SYNC = 0x10;
static const uint8_t PEER_FLAG_LEECHING = 0x00;
#ifdef WANT_V6
#define OT_SETIP(peer,ip) memcpy((peer),(ip),(OT_IP_SIZE))
#else
#define OT_SETIP(peer,ip) memcpy((peer),(((uint8_t*)ip)+12),(OT_IP_SIZE))
#endif
#define OT_SETPORT(peer,port) memcpy(((uint8_t*)(peer))+(OT_IP_SIZE),(port),2)
#define OT_PEERFLAG(peer) (((uint8_t*)(peer))[(OT_IP_SIZE)+2])
#define OT_PEERTIME(peer) (((uint8_t*)(peer))[(OT_IP_SIZE)+3])
/* Takes an ot_peer6 and returns the proper pointer to the peer and sets peer_size */
ot_peer *peer_from_peer6(ot_peer6 *peer, size_t *peer_size);
size_t peer_size_from_peer6(ot_peer6 *peer);
/* New style */
#define OT_SETIP(peer,ip) memcpy((peer),(ip),OT_IP_SIZE6)
#define OT_SETPORT(peer,port) memcpy(((uint8_t*)(peer))+(OT_IP_SIZE6),(port),2)
#define OT_PEERFLAG(peer) (((uint8_t*)(peer))[(OT_IP_SIZE6)+2])
#define OT_PEERFLAG_D(peer,peersize) (((uint8_t*)(peer))[(peersize)-2])
#define OT_PEERTIME(peer,peersize) (((uint8_t*)(peer))[(peersize)-1])
#define PEERS_BENCODED6 "6:peers6"
#define PEERS_BENCODED4 "5:peers"
#define OT_HASH_COMPARE_SIZE (sizeof(ot_hash))
@ -102,7 +111,8 @@ struct ot_peerlist;
typedef struct ot_peerlist ot_peerlist;
typedef struct {
ot_hash hash;
ot_peerlist *peer_list;
ot_peerlist *peer_list6;
ot_peerlist *peer_list4;
} ot_torrent;
#include "ot_vector.h"
@ -131,7 +141,7 @@ struct ot_workstruct {
#endif
/* The peer currently in the working */
ot_peer peer;
ot_peer6 peer; /* Can fit v6 and v4 peers */
/* Pointers into the request buffer */
ot_hash *hash;

Loading…
Cancel
Save