mirror of
https://github.com/transmission/transmission
synced 2025-03-13 07:33:02 +00:00
(trunk libT) add ipv6 support by jhujhiti. I think this is the largest user-contributed patch we've ever used... thanks jhujhiti :)
This commit is contained in:
parent
da6b7ee137
commit
54be88dec3
11 changed files with 671 additions and 232 deletions
|
@ -450,16 +450,19 @@ getSocketMax( struct tr_fd_s * gFd )
|
|||
}
|
||||
|
||||
int
|
||||
tr_fdSocketCreate( int type )
|
||||
tr_fdSocketCreate( int domain, int type )
|
||||
{
|
||||
int s = -1;
|
||||
|
||||
tr_lockLock( gFd->lock );
|
||||
|
||||
if( gFd->socketCount < getSocketMax( gFd ) )
|
||||
if( ( s = socket( AF_INET, type, 0 ) ) < 0 )
|
||||
if( ( s = socket( domain, type, 0 ) ) < 0 )
|
||||
{
|
||||
tr_err( _( "Couldn't create socket: %s" ),
|
||||
tr_strerror( sockerrno ) );
|
||||
s = -sockerrno;
|
||||
}
|
||||
|
||||
if( s > -1 )
|
||||
++gFd->socketCount;
|
||||
|
@ -485,7 +488,7 @@ tr_fdSocketAccept( int b,
|
|||
tr_lockLock( gFd->lock );
|
||||
if( gFd->socketCount < getSocketMax( gFd ) )
|
||||
{
|
||||
len = sizeof( struct sockaddr );
|
||||
len = sizeof( struct sockaddr_storage );
|
||||
s = accept( b, (struct sockaddr *) &sock, &len );
|
||||
}
|
||||
if( s > -1 )
|
||||
|
@ -503,8 +506,7 @@ tr_fdSocketAccept( int b,
|
|||
{
|
||||
struct sockaddr_in6 * sock6 = (struct sockaddr_in6 *)&sock;
|
||||
addr->type = TR_AF_INET6;
|
||||
memcpy( &addr->addr, &sock6->sin6_addr,
|
||||
sizeof( struct sockaddr_in6 ) );
|
||||
addr->addr.addr6 = sock6->sin6_addr;
|
||||
*port = sock6->sin6_port;
|
||||
}
|
||||
++gFd->socketCount;
|
||||
|
|
|
@ -85,7 +85,7 @@ void tr_fdFileClose( const char * filename );
|
|||
/***********************************************************************
|
||||
* Sockets
|
||||
**********************************************************************/
|
||||
int tr_fdSocketCreate( int type );
|
||||
int tr_fdSocketCreate( int domain, int type );
|
||||
|
||||
int tr_fdSocketAccept( int b,
|
||||
tr_address * addr,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -109,6 +110,16 @@ tr_pton( const char * src, tr_address * dst )
|
|||
return dst;
|
||||
}
|
||||
|
||||
void
|
||||
tr_normalizeV4Mapped( tr_address * const addr )
|
||||
{
|
||||
if( addr->type == TR_AF_INET6 && IN6_IS_ADDR_V4MAPPED( &addr->addr.addr6 ) )
|
||||
{
|
||||
addr->type = TR_AF_INET;
|
||||
memcpy( &addr->addr.addr4.s_addr, addr->addr.addr6.s6_addr + 12, 4 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two tr_address structures.
|
||||
* Returns:
|
||||
|
@ -139,6 +150,98 @@ tr_compareAddresses( const tr_address * a, const tr_address * b)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Socket list housekeeping
|
||||
**********************************************************************/
|
||||
struct tr_socketList
|
||||
{
|
||||
int socket;
|
||||
tr_address addr;
|
||||
tr_socketList * next;
|
||||
};
|
||||
|
||||
tr_socketList *
|
||||
tr_socketListAppend( tr_socketList * const head,
|
||||
const tr_address * const addr )
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
assert( head );
|
||||
for( tmp = head; tmp->next; tmp = tmp->next );
|
||||
tmp->next = tr_socketListNew( addr );
|
||||
return tmp->next;
|
||||
}
|
||||
|
||||
tr_socketList *
|
||||
tr_socketListNew( const tr_address * const addr )
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
tmp = tr_new( tr_socketList, 1 );
|
||||
tmp->socket = -1;
|
||||
tmp->addr = *addr;
|
||||
tmp->next = NULL;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void
|
||||
tr_socketListFree( tr_socketList * const head )
|
||||
{
|
||||
assert( head );
|
||||
if( head->next )
|
||||
tr_socketListFree( head->next );
|
||||
tr_free( head );
|
||||
}
|
||||
|
||||
void
|
||||
tr_socketListRemove( tr_socketList * const head,
|
||||
tr_socketList * const el)
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
assert( head );
|
||||
assert( el );
|
||||
for( tmp = head; tmp->next && tmp->next != el; tmp = tmp->next );
|
||||
tmp->next = el->next;
|
||||
el->next = NULL;
|
||||
tr_socketListFree(el);
|
||||
}
|
||||
|
||||
void
|
||||
tr_socketListTruncate( tr_socketList * const head,
|
||||
tr_socketList * const start )
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
assert( head );
|
||||
assert( start );
|
||||
for( tmp = head; tmp->next && tmp->next != start; tmp = tmp->next );
|
||||
tr_socketListFree( start );
|
||||
tmp->next = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
tr_socketListGetSocket( const tr_socketList * const el )
|
||||
{
|
||||
assert( el );
|
||||
return el->socket;
|
||||
}
|
||||
|
||||
const tr_address *
|
||||
tr_socketListGetAddress( const tr_socketList * const el )
|
||||
{
|
||||
assert( el );
|
||||
return &el->addr;
|
||||
}
|
||||
|
||||
void
|
||||
tr_socketListForEach( tr_socketList * const head,
|
||||
void ( * cb ) ( int * const,
|
||||
tr_address * const,
|
||||
void * const),
|
||||
void * const userData )
|
||||
{
|
||||
tr_socketList * tmp;
|
||||
for( tmp = head; tmp; tmp = tmp->next )
|
||||
cb( &tmp->socket, &tmp->addr, userData );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TCP sockets
|
||||
**********************************************************************/
|
||||
|
@ -161,10 +264,12 @@ makeSocketNonBlocking( int fd )
|
|||
{
|
||||
if( evutil_make_socket_nonblocking( fd ) )
|
||||
{
|
||||
int tmperrno;
|
||||
tr_err( _( "Couldn't create socket: %s" ),
|
||||
tr_strerror( sockerrno ) );
|
||||
tmperrno = sockerrno;
|
||||
tr_netClose( fd );
|
||||
fd = -1;
|
||||
fd = -tmperrno;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,9 +277,9 @@ makeSocketNonBlocking( int fd )
|
|||
}
|
||||
|
||||
static int
|
||||
createSocket( int type )
|
||||
createSocket( int domain, int type )
|
||||
{
|
||||
return makeSocketNonBlocking( tr_fdSocketCreate( type ) );
|
||||
return makeSocketNonBlocking( tr_fdSocketCreate( domain, type ) );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -191,14 +296,13 @@ setSndBuf( tr_session * session UNUSED, int fd UNUSED )
|
|||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
static socklen_t
|
||||
setup_sockaddr( const tr_address * addr,
|
||||
tr_port port,
|
||||
struct sockaddr_storage * sockaddr)
|
||||
{
|
||||
struct sockaddr_in sock4;
|
||||
struct sockaddr_in6 sock6;
|
||||
|
||||
if( addr->type == TR_AF_INET )
|
||||
{
|
||||
memset( &sock4, 0, sizeof( sock4 ) );
|
||||
|
@ -206,14 +310,17 @@ setup_sockaddr( const tr_address * addr,
|
|||
sock4.sin_addr.s_addr = addr->addr.addr4.s_addr;
|
||||
sock4.sin_port = port;
|
||||
memcpy( sockaddr, &sock4, sizeof( sock4 ) );
|
||||
return sizeof( struct sockaddr_in );
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( &sock6, 0, sizeof( sock6 ) );
|
||||
sock6.sin6_family = AF_INET6;
|
||||
sock6.sin6_port = port;
|
||||
memcpy( &sock6.sin6_addr, &addr->addr, sizeof( struct in6_addr ) );
|
||||
sock6.sin6_flowinfo = 0;
|
||||
sock6.sin6_addr = addr->addr.addr6;
|
||||
memcpy( sockaddr, &sock6, sizeof( sock6 ) );
|
||||
return sizeof( struct sockaddr_in6 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,25 +332,29 @@ tr_netOpenTCP( tr_session * session,
|
|||
int s;
|
||||
struct sockaddr_storage sock;
|
||||
const int type = SOCK_STREAM;
|
||||
socklen_t addrlen;
|
||||
|
||||
if( ( s = createSocket( type ) ) < 0 )
|
||||
return -1;
|
||||
if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
|
||||
type ) ) < 0 )
|
||||
return s;
|
||||
|
||||
setSndBuf( session, s );
|
||||
|
||||
setup_sockaddr( addr, port, &sock );
|
||||
addrlen = setup_sockaddr( addr, port, &sock );
|
||||
|
||||
if( ( connect( s, (struct sockaddr *) &sock,
|
||||
sizeof( struct sockaddr ) ) < 0 )
|
||||
addrlen ) < 0 )
|
||||
#ifdef WIN32
|
||||
&& ( sockerrno != WSAEWOULDBLOCK )
|
||||
#endif
|
||||
&& ( sockerrno != EINPROGRESS ) )
|
||||
{
|
||||
int tmperrno;
|
||||
tr_err( _( "Couldn't connect socket %d to %s, port %d (errno %d - %s)" ),
|
||||
s, tr_ntop_non_ts( addr ), (int)port, sockerrno, tr_strerror( sockerrno ) );
|
||||
tmperrno = sockerrno;
|
||||
tr_netClose( s );
|
||||
s = -1;
|
||||
s = -tmperrno;
|
||||
}
|
||||
|
||||
tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)",
|
||||
|
@ -253,35 +364,40 @@ tr_netOpenTCP( tr_session * session,
|
|||
}
|
||||
|
||||
int
|
||||
tr_netBindTCP( const tr_address * addr, tr_port port )
|
||||
tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_storage sock;
|
||||
const int type = SOCK_STREAM;
|
||||
int addrlen;
|
||||
|
||||
#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
|
||||
int optval;
|
||||
#endif
|
||||
|
||||
if( ( s = createSocket( type ) ) < 0 )
|
||||
return -1;
|
||||
if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
|
||||
type ) ) < 0 )
|
||||
return s;
|
||||
|
||||
#ifdef SO_REUSEADDR
|
||||
optval = 1;
|
||||
setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) );
|
||||
#endif
|
||||
|
||||
setup_sockaddr( addr, htons( port ), &sock );
|
||||
addrlen = setup_sockaddr( addr, htons( port ), &sock );
|
||||
|
||||
if( bind( s, (struct sockaddr *) &sock,
|
||||
sizeof( struct sockaddr ) ) )
|
||||
addrlen ) )
|
||||
{
|
||||
int tmperrno;
|
||||
if( !suppressMsgs )
|
||||
tr_err( _( "Couldn't bind port %d on %s: %s" ), port,
|
||||
tr_ntop_non_ts( addr ), tr_strerror( sockerrno ) );
|
||||
tmperrno = sockerrno;
|
||||
tr_netClose( s );
|
||||
return -1;
|
||||
return -tmperrno;
|
||||
}
|
||||
|
||||
if( !suppressMsgs )
|
||||
tr_dbg( "Bound socket %d to port %d on %s",
|
||||
s, port, tr_ntop_non_ts( addr ) );
|
||||
return s;
|
||||
|
|
|
@ -59,7 +59,7 @@ struct tr_session;
|
|||
#define TR_AF_INET6 1
|
||||
|
||||
typedef struct tr_address {
|
||||
unsigned short type : 1;
|
||||
uint8_t type;
|
||||
union {
|
||||
/* The order here is important for tr_in{,6}addr_any initialization,
|
||||
* since we can't use C99 designated initializers */
|
||||
|
@ -79,6 +79,27 @@ tr_address *tr_pton( const char * src,
|
|||
tr_address * dst );
|
||||
int tr_compareAddresses( const tr_address * a,
|
||||
const tr_address * b);
|
||||
void tr_normalizeV4Mapped( tr_address * const addr );
|
||||
|
||||
/***********************************************************************
|
||||
* Socket list housekeeping
|
||||
**********************************************************************/
|
||||
typedef struct tr_socketList tr_socketList;
|
||||
tr_socketList *tr_socketListAppend( tr_socketList * const head,
|
||||
const tr_address * const addr );
|
||||
tr_socketList *tr_socketListNew( const tr_address * const addr );
|
||||
void tr_socketListFree( tr_socketList * const head );
|
||||
void tr_socketListRemove( tr_socketList * const head,
|
||||
tr_socketList * const el);
|
||||
void tr_socketListTruncate( tr_socketList * const head,
|
||||
tr_socketList * const start );
|
||||
int tr_socketListGetSocket( const tr_socketList * const el );
|
||||
const tr_address *tr_socketListGetAddress( const tr_socketList * const el );
|
||||
void tr_socketListForEach( tr_socketList * const head,
|
||||
void ( * cb ) ( int * const,
|
||||
tr_address * const,
|
||||
void * const ),
|
||||
void * const userData);
|
||||
|
||||
/***********************************************************************
|
||||
* Sockets
|
||||
|
@ -88,7 +109,8 @@ int tr_netOpenTCP( struct tr_handle * session,
|
|||
tr_port port );
|
||||
|
||||
int tr_netBindTCP( const tr_address * addr,
|
||||
tr_port port );
|
||||
tr_port port,
|
||||
tr_bool suppressMsgs );
|
||||
|
||||
int tr_netAccept( struct tr_handle * session,
|
||||
int bound,
|
||||
|
|
|
@ -1375,6 +1375,53 @@ tr_peerMgrCompactToPex( const void * compact,
|
|||
return pex;
|
||||
}
|
||||
|
||||
tr_pex *
|
||||
tr_peerMgrCompact6ToPex( const void * compact,
|
||||
size_t compactLen,
|
||||
const uint8_t * added_f,
|
||||
size_t added_f_len,
|
||||
size_t * pexCount )
|
||||
{
|
||||
size_t i;
|
||||
size_t n = compactLen / 18;
|
||||
const uint8_t * walk = compact;
|
||||
tr_pex * pex = tr_new0( tr_pex, n );
|
||||
|
||||
for( i = 0; i < n; ++i )
|
||||
{
|
||||
pex[i].addr.type = TR_AF_INET6;
|
||||
memcpy( &pex[i].addr.addr.addr6.s6_addr, walk, 16 ); walk += 16;
|
||||
memcpy( &pex[i].port, walk, 2 ); walk += 2;
|
||||
if( added_f && ( n == added_f_len ) )
|
||||
pex[i].flags = added_f[i];
|
||||
}
|
||||
|
||||
*pexCount = n;
|
||||
return pex;
|
||||
}
|
||||
|
||||
tr_pex *
|
||||
tr_peerMgrArrayToPex( const void * array,
|
||||
size_t arrayLen,
|
||||
size_t * pexCount )
|
||||
{
|
||||
size_t i;
|
||||
size_t n = arrayLen / ( sizeof( tr_address ) + 2 );
|
||||
/*size_t n = arrayLen / sizeof( tr_peerArrayElement );*/
|
||||
const uint8_t * walk = array;
|
||||
tr_pex * pex = tr_new0( tr_pex, n );
|
||||
|
||||
for( i = 0 ; i < n ; i++ ) {
|
||||
memcpy( &pex[i].addr, walk, sizeof( tr_address ) );
|
||||
memcpy( &pex[i].port, walk + sizeof( tr_address ), 2 );
|
||||
pex[i].flags = 0x00;
|
||||
walk += sizeof( tr_address ) + 2;
|
||||
}
|
||||
|
||||
*pexCount = n;
|
||||
return pex;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
@ -1436,9 +1483,11 @@ peerPrefersCrypto( const tr_peer * peer )
|
|||
int
|
||||
tr_peerMgrGetPeers( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
tr_pex ** setme_pex )
|
||||
tr_pex ** setme_pex,
|
||||
uint8_t af)
|
||||
{
|
||||
int peerCount = 0;
|
||||
int peersReturning = 0;
|
||||
const Torrent * t;
|
||||
|
||||
managerLock( manager );
|
||||
|
@ -1452,30 +1501,36 @@ tr_peerMgrGetPeers( tr_peerMgr * manager,
|
|||
{
|
||||
int i;
|
||||
const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
|
||||
/* for now, this will waste memory on torrents that have both
|
||||
* ipv6 and ipv4 peers */
|
||||
tr_pex * pex = tr_new( tr_pex, peerCount );
|
||||
tr_pex * walk = pex;
|
||||
|
||||
for( i=0; i<peerCount; ++i, ++walk )
|
||||
{
|
||||
const tr_peer * peer = peers[i];
|
||||
if( peer->addr.type == af )
|
||||
{
|
||||
const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
|
||||
|
||||
walk->addr = peer->addr;
|
||||
memcpy( &walk->addr, &peer->addr, sizeof( walk->addr ) );
|
||||
walk->port = peer->port;
|
||||
walk->flags = 0;
|
||||
if( peerPrefersCrypto( peer ) )
|
||||
walk->flags |= ADDED_F_ENCRYPTION_FLAG;
|
||||
if( ( atom->uploadOnly == UPLOAD_ONLY_YES ) || ( peer->progress >= 1.0 ) )
|
||||
if( ( atom->uploadOnly == UPLOAD_ONLY_YES ) ||
|
||||
( peer->progress >= 1.0 ) )
|
||||
walk->flags |= ADDED_F_SEED_FLAG;
|
||||
peersReturning++;
|
||||
}
|
||||
}
|
||||
|
||||
assert( ( walk - pex ) == peerCount );
|
||||
qsort( pex, peerCount, sizeof( tr_pex ), tr_pexCompare );
|
||||
qsort( pex, peersReturning, sizeof( tr_pex ), tr_pexCompare );
|
||||
*setme_pex = pex;
|
||||
}
|
||||
|
||||
managerUnlock( manager );
|
||||
return peerCount;
|
||||
return peersReturning;
|
||||
}
|
||||
|
||||
static int reconnectPulse( void * vtorrent );
|
||||
|
@ -1785,9 +1840,13 @@ tr_peerMgrPeerStats( const tr_peerMgr * manager,
|
|||
const tr_peer * peer = peers[i];
|
||||
const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
|
||||
tr_peer_stat * stat = ret + i;
|
||||
tr_address norm_addr;
|
||||
|
||||
tr_ntop( &peer->addr, stat->addr, sizeof(stat->addr) );
|
||||
tr_strlcpy( stat->client, (peer->client ? peer->client : ""), sizeof(stat->client) );
|
||||
memcpy( &norm_addr, &peer->addr, sizeof( tr_address ) );
|
||||
tr_normalizeV4Mapped( &norm_addr );
|
||||
tr_ntop( &norm_addr, stat->addr, sizeof( stat->addr ) );
|
||||
tr_strlcpy( stat->client, ( peer->client ? peer->client : "" ),
|
||||
sizeof( stat->client ) );
|
||||
stat->port = ntohs( peer->port );
|
||||
stat->from = atom->from;
|
||||
stat->progress = peer->progress;
|
||||
|
|
|
@ -67,6 +67,16 @@ tr_pex * tr_peerMgrCompactToPex( const void * compact,
|
|||
size_t added_f_len,
|
||||
size_t * setme_pex_count );
|
||||
|
||||
tr_pex * tr_peerMgrCompact6ToPex( const void * compact,
|
||||
size_t compactLen,
|
||||
const uint8_t * added_f,
|
||||
size_t added_f_len,
|
||||
size_t * pexCount );
|
||||
|
||||
tr_pex * tr_peerMgrArrayToPex( const void * array,
|
||||
size_t arrayLen,
|
||||
size_t * setme_pex_count );
|
||||
|
||||
void tr_peerMgrAddPex( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
uint8_t from,
|
||||
|
@ -79,7 +89,8 @@ void tr_peerMgrSetBlame( tr_peerMgr * manager,
|
|||
|
||||
int tr_peerMgrGetPeers( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash,
|
||||
tr_pex ** setme_pex );
|
||||
tr_pex ** setme_pex,
|
||||
uint8_t af);
|
||||
|
||||
void tr_peerMgrStartTorrent( tr_peerMgr * manager,
|
||||
const uint8_t * torrentHash );
|
||||
|
|
|
@ -282,6 +282,7 @@ struct tr_peermsgs
|
|||
uint8_t state;
|
||||
uint8_t ut_pex_id;
|
||||
uint16_t pexCount;
|
||||
uint16_t pexCount6;
|
||||
uint16_t minActiveRequests;
|
||||
uint16_t maxActiveRequests;
|
||||
|
||||
|
@ -308,6 +309,7 @@ struct tr_peermsgs
|
|||
|
||||
tr_timer * pexTimer;
|
||||
tr_pex * pex;
|
||||
tr_pex * pex6;
|
||||
|
||||
time_t clientSentPexAt;
|
||||
time_t clientSentAnythingAt;
|
||||
|
@ -1181,21 +1183,42 @@ parseUtPex( tr_peermsgs * msgs, int msglen, struct evbuffer * inbuf )
|
|||
tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp, msglen );
|
||||
|
||||
if( tr_torrentAllowsPex( tor )
|
||||
&& (( loaded = !tr_bencLoad( tmp, msglen, &val, NULL )))
|
||||
&& tr_bencDictFindRaw( &val, "added", &added, &added_len ))
|
||||
&& ( ( loaded = !tr_bencLoad( tmp, msglen, &val, NULL ) ) ) )
|
||||
{
|
||||
if( tr_bencDictFindRaw( &val, "added", &added, &added_len ) )
|
||||
{
|
||||
const uint8_t * added_f = NULL;
|
||||
tr_pex * pex;
|
||||
size_t i, n;
|
||||
size_t added_f_len = 0;
|
||||
tr_bencDictFindRaw( &val, "added.f", &added_f, &added_f_len );
|
||||
pex = tr_peerMgrCompactToPex( added, added_len, added_f, added_f_len, &n );
|
||||
pex =
|
||||
tr_peerMgrCompactToPex( added, added_len, added_f, added_f_len,
|
||||
&n );
|
||||
for( i = 0; i < n; ++i )
|
||||
tr_peerMgrAddPex( msgs->session->peerMgr, tor->info.hash,
|
||||
TR_PEER_FROM_PEX, pex + i );
|
||||
tr_free( pex );
|
||||
}
|
||||
|
||||
if( tr_bencDictFindRaw( &val, "added6", &added, &added_len ) )
|
||||
{
|
||||
const uint8_t * added_f = NULL;
|
||||
tr_pex * pex;
|
||||
size_t i, n;
|
||||
size_t added_f_len = 0;
|
||||
tr_bencDictFindRaw( &val, "added6.f", &added_f, &added_f_len );
|
||||
pex =
|
||||
tr_peerMgrCompact6ToPex( added, added_len, added_f, added_f_len,
|
||||
&n );
|
||||
for( i = 0; i < n; ++i )
|
||||
tr_peerMgrAddPex( msgs->session->peerMgr, tor->info.hash,
|
||||
TR_PEER_FROM_PEX, pex + i );
|
||||
tr_free( pex );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( loaded )
|
||||
tr_bencFree( &val );
|
||||
tr_free( tmp );
|
||||
|
@ -2005,17 +2028,21 @@ pexElementCb( void * vpex,
|
|||
diffs->elements[diffs->elementCount++] = *pex;
|
||||
}
|
||||
|
||||
/* TODO: ipv6 pex */
|
||||
static void
|
||||
sendPex( tr_peermsgs * msgs )
|
||||
{
|
||||
if( msgs->peerSupportsPex && tr_torrentAllowsPex( msgs->torrent ) )
|
||||
{
|
||||
PexDiffs diffs;
|
||||
PexDiffs diffs6;
|
||||
tr_pex * newPex = NULL;
|
||||
tr_pex * newPex6 = NULL;
|
||||
const int newCount = tr_peerMgrGetPeers( msgs->session->peerMgr,
|
||||
msgs->torrent->info.hash,
|
||||
&newPex );
|
||||
&newPex, TR_AF_INET );
|
||||
const int newCount6 = tr_peerMgrGetPeers( msgs->session->peerMgr,
|
||||
msgs->torrent->info.hash,
|
||||
&newPex6, TR_AF_INET6 );
|
||||
|
||||
/* build the diffs */
|
||||
diffs.added = tr_new( tr_pex, newCount );
|
||||
|
@ -2028,14 +2055,28 @@ sendPex( tr_peermsgs * msgs )
|
|||
newPex, newCount,
|
||||
tr_pexCompare, sizeof( tr_pex ),
|
||||
pexDroppedCb, pexAddedCb, pexElementCb, &diffs );
|
||||
diffs6.added = tr_new( tr_pex, newCount6 );
|
||||
diffs6.addedCount = 0;
|
||||
diffs6.dropped = tr_new( tr_pex, msgs->pexCount6 );
|
||||
diffs6.droppedCount = 0;
|
||||
diffs6.elements = tr_new( tr_pex, newCount6 + msgs->pexCount6 );
|
||||
diffs6.elementCount = 0;
|
||||
tr_set_compare( msgs->pex6, msgs->pexCount6,
|
||||
newPex6, newCount6,
|
||||
tr_pexCompare, sizeof( tr_pex ),
|
||||
pexDroppedCb, pexAddedCb, pexElementCb, &diffs6 );
|
||||
dbgmsg(
|
||||
msgs,
|
||||
"pex: old peer count %d, new peer count %d, added %d, removed %d",
|
||||
msgs->pexCount, newCount, diffs.addedCount, diffs.droppedCount );
|
||||
msgs->pexCount, newCount + newCount6,
|
||||
diffs.addedCount + diffs6.addedCount,
|
||||
diffs.droppedCount + diffs6.droppedCount );
|
||||
|
||||
if( !diffs.addedCount && !diffs.droppedCount )
|
||||
if( !diffs.addedCount && !diffs.droppedCount && !diffs6.addedCount &&
|
||||
!diffs6.droppedCount )
|
||||
{
|
||||
tr_free( diffs.elements );
|
||||
tr_free( diffs6.elements );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2050,13 +2091,18 @@ sendPex( tr_peermsgs * msgs )
|
|||
tr_free( msgs->pex );
|
||||
msgs->pex = diffs.elements;
|
||||
msgs->pexCount = diffs.elementCount;
|
||||
tr_free( msgs->pex6 );
|
||||
msgs->pex6 = diffs6.elements;
|
||||
msgs->pexCount6 = diffs6.elementCount;
|
||||
|
||||
/* build the pex payload */
|
||||
tr_bencInitDict( &val, 3 );
|
||||
tr_bencInitDict( &val, 3 ); /* ipv6 support: left as 3:
|
||||
* speed vs. likelihood? */
|
||||
|
||||
/* "added" */
|
||||
tmp = walk = tr_new( uint8_t, diffs.addedCount * 6 );
|
||||
for( i = 0; i < diffs.addedCount; ++i ) {
|
||||
for( i = 0; i < diffs.addedCount; ++i )
|
||||
{
|
||||
memcpy( walk, &diffs.added[i].addr.addr, 4 ); walk += 4;
|
||||
memcpy( walk, &diffs.added[i].port, 2 ); walk += 2;
|
||||
}
|
||||
|
@ -2074,7 +2120,8 @@ sendPex( tr_peermsgs * msgs )
|
|||
|
||||
/* "dropped" */
|
||||
tmp = walk = tr_new( uint8_t, diffs.droppedCount * 6 );
|
||||
for( i = 0; i < diffs.droppedCount; ++i ) {
|
||||
for( i = 0; i < diffs.droppedCount; ++i )
|
||||
{
|
||||
memcpy( walk, &diffs.dropped[i].addr.addr, 4 ); walk += 4;
|
||||
memcpy( walk, &diffs.dropped[i].port, 2 ); walk += 2;
|
||||
}
|
||||
|
@ -2082,6 +2129,40 @@ sendPex( tr_peermsgs * msgs )
|
|||
tr_bencDictAddRaw( &val, "dropped", tmp, walk - tmp );
|
||||
tr_free( tmp );
|
||||
|
||||
/* "added6" */
|
||||
tmp = walk = tr_new( uint8_t, diffs6.addedCount * 18 );
|
||||
for( i = 0; i < diffs6.addedCount; ++i )
|
||||
{
|
||||
memcpy( walk, &diffs6.added[i].addr.addr.addr6.s6_addr, 16 );
|
||||
walk += 16;
|
||||
memcpy( walk, &diffs6.added[i].port, 2 );
|
||||
walk += 2;
|
||||
}
|
||||
assert( ( walk - tmp ) == diffs6.addedCount * 18 );
|
||||
tr_bencDictAddRaw( &val, "added6", tmp, walk - tmp );
|
||||
tr_free( tmp );
|
||||
|
||||
/* "added6.f" */
|
||||
tmp = walk = tr_new( uint8_t, diffs6.addedCount );
|
||||
for( i = 0; i < diffs6.addedCount; ++i )
|
||||
*walk++ = diffs6.added[i].flags;
|
||||
assert( ( walk - tmp ) == diffs6.addedCount );
|
||||
tr_bencDictAddRaw( &val, "added6.f", tmp, walk - tmp );
|
||||
tr_free( tmp );
|
||||
|
||||
/* "dropped6" */
|
||||
tmp = walk = tr_new( uint8_t, diffs6.droppedCount * 18 );
|
||||
for( i = 0; i < diffs6.droppedCount; ++i )
|
||||
{
|
||||
memcpy( walk, &diffs6.dropped[i].addr.addr.addr6.s6_addr, 16 );
|
||||
walk += 16;
|
||||
memcpy( walk, &diffs6.dropped[i].port, 2 );
|
||||
walk += 2;
|
||||
}
|
||||
assert( ( walk - tmp ) == diffs6.droppedCount * 18);
|
||||
tr_bencDictAddRaw( &val, "dropped6", tmp, walk - tmp );
|
||||
tr_free( tmp );
|
||||
|
||||
/* write the pex message */
|
||||
benc = tr_bencSave( &val, &bencLen );
|
||||
tr_peerIoWriteUint32( msgs->peer->io, out, 2 * sizeof( uint8_t ) + bencLen );
|
||||
|
@ -2099,6 +2180,9 @@ sendPex( tr_peermsgs * msgs )
|
|||
tr_free( diffs.added );
|
||||
tr_free( diffs.dropped );
|
||||
tr_free( newPex );
|
||||
tr_free( diffs6.added );
|
||||
tr_free( diffs6.dropped );
|
||||
tr_free( newPex6 );
|
||||
|
||||
msgs->clientSentPexAt = time( NULL );
|
||||
}
|
||||
|
@ -2175,6 +2259,7 @@ tr_peerMsgsFree( tr_peermsgs* msgs )
|
|||
|
||||
evbuffer_free( msgs->incoming.block );
|
||||
evbuffer_free( msgs->outMessages );
|
||||
tr_free( msgs->pex6 );
|
||||
tr_free( msgs->pex );
|
||||
|
||||
memset( msgs, ~0, sizeof( tr_peermsgs ) );
|
||||
|
|
|
@ -38,9 +38,9 @@ struct tr_shared
|
|||
tr_port_forwarding natpmpStatus;
|
||||
tr_port_forwarding upnpStatus;
|
||||
|
||||
int bindPort;
|
||||
int bindSocket;
|
||||
int publicPort;
|
||||
tr_bool shouldChange;
|
||||
tr_socketList * bindSockets;
|
||||
tr_port publicPort;
|
||||
|
||||
tr_timer * pulseTimer;
|
||||
|
||||
|
@ -84,7 +84,7 @@ getNatStateStr( int state )
|
|||
static void
|
||||
natPulse( tr_shared * s )
|
||||
{
|
||||
const int port = s->publicPort;
|
||||
const tr_port port = s->publicPort;
|
||||
const int isEnabled = s->isEnabled && !s->isShuttingDown;
|
||||
int oldStatus;
|
||||
int newStatus;
|
||||
|
@ -100,75 +100,103 @@ natPulse( tr_shared * s )
|
|||
getNatStateStr( newStatus ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Callbacks for socket list
|
||||
*/
|
||||
static void
|
||||
incomingPeersPulse( tr_shared * s )
|
||||
closeCb( int * const socket,
|
||||
tr_address * const addr,
|
||||
void * const userData )
|
||||
{
|
||||
tr_bool allPaused;
|
||||
tr_torrent * tor;
|
||||
|
||||
if( s->bindSocket >= 0 && ( s->bindPort != s->publicPort ) )
|
||||
tr_shared * s = ( tr_shared * )userData;
|
||||
if( *socket >= 0 )
|
||||
{
|
||||
tr_ninf( getKey( ), _( "Closing port %d" ), s->bindPort );
|
||||
tr_netClose( s->bindSocket );
|
||||
s->bindSocket = -1;
|
||||
tr_ninf( getKey( ), _( "Closing port %d on %s" ), s->publicPort,
|
||||
tr_ntop_non_ts( addr ) );
|
||||
tr_netClose( *socket );
|
||||
}
|
||||
}
|
||||
|
||||
if( ( s->publicPort > 0 ) && ( s->bindPort != s->publicPort ) )
|
||||
static void
|
||||
acceptCb( int * const socket,
|
||||
tr_address * const addr,
|
||||
void * const userData )
|
||||
{
|
||||
int socket;
|
||||
errno = 0;
|
||||
socket = tr_netBindTCP( &tr_inaddr_any, s->publicPort );
|
||||
if( socket >= 0 )
|
||||
tr_shared * s = ( tr_shared * )userData;
|
||||
tr_address clientAddr;
|
||||
tr_port clientPort;
|
||||
int clientSocket;
|
||||
clientSocket = tr_netAccept( s->session, *socket, &clientAddr, &clientPort );
|
||||
if( clientSocket > 0 )
|
||||
{
|
||||
tr_deepLog( __FILE__, __LINE__, NULL,
|
||||
"New INCOMING connection %d (%s)",
|
||||
clientSocket, tr_peerIoAddrStr( &clientAddr, clientPort ) );
|
||||
|
||||
tr_peerMgrAddIncoming( s->session->peerMgr, &clientAddr, clientPort,
|
||||
clientSocket );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bindCb( int * const socket,
|
||||
tr_address * const addr,
|
||||
void * const userData )
|
||||
{
|
||||
tr_shared * s = ( tr_shared * )userData;
|
||||
*socket = tr_netBindTCP( addr, s->publicPort, FALSE );
|
||||
if( *socket >= 0 )
|
||||
{
|
||||
tr_ninf( getKey( ),
|
||||
_(
|
||||
"Opened port %d to listen for incoming peer connections" ),
|
||||
s->publicPort );
|
||||
s->bindPort = s->publicPort;
|
||||
s->bindSocket = socket;
|
||||
listen( s->bindSocket, 5 );
|
||||
_( "Opened port %d on %s to listen for incoming peer connections" ),
|
||||
s->publicPort, tr_ntop_non_ts( addr ) );
|
||||
listen( *socket, 10 );
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_nerr( getKey( ),
|
||||
_(
|
||||
"Couldn't open port %d to listen for incoming peer connections (errno %d - %s)" ),
|
||||
s->publicPort, errno, tr_strerror( errno ) );
|
||||
s->bindPort = -1;
|
||||
s->bindSocket = -1;
|
||||
"Couldn't open port %d on %s to listen for incoming peer connections (errno %d - %s)" ),
|
||||
s->publicPort, tr_ntop_non_ts( addr ), errno, tr_strerror( errno ) );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
incomingPeersPulse( tr_shared * s )
|
||||
{
|
||||
int allPaused;
|
||||
tr_torrent * tor;
|
||||
|
||||
if( s->shouldChange )
|
||||
{
|
||||
tr_socketListForEach( s->bindSockets, &closeCb, s );
|
||||
s->shouldChange = FALSE;
|
||||
if( s->publicPort > 0 )
|
||||
tr_socketListForEach( s->bindSockets, &bindCb, s );
|
||||
}
|
||||
|
||||
/* see if any torrents aren't paused */
|
||||
allPaused = 1;
|
||||
tor = NULL;
|
||||
while(( tor = tr_torrentNext( s->session, tor ))) {
|
||||
if( TR_STATUS_IS_ACTIVE( tr_torrentGetActivity( tor ))) {
|
||||
while( ( tor = tr_torrentNext( s->session, tor ) ) )
|
||||
{
|
||||
if( TR_STATUS_IS_ACTIVE( tr_torrentGetActivity( tor ) ) )
|
||||
{
|
||||
allPaused = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we have any running torrents, check for new incoming peer connections */
|
||||
while( !allPaused )
|
||||
{
|
||||
int socket;
|
||||
tr_port port;
|
||||
tr_address addr;
|
||||
|
||||
if( s->bindSocket < 0 )
|
||||
break;
|
||||
|
||||
socket = tr_netAccept( s->session, s->bindSocket, &addr, &port );
|
||||
if( socket < 0 )
|
||||
break;
|
||||
|
||||
tr_deepLog( __FILE__, __LINE__, NULL,
|
||||
"New INCOMING connection %d (%s)",
|
||||
socket, tr_peerIoAddrStr( &addr, port ) );
|
||||
|
||||
tr_peerMgrAddIncoming( s->session->peerMgr, &addr, port, socket );
|
||||
}
|
||||
/* (jhujhiti):
|
||||
* This has been changed from a loop that will end when the listener queue
|
||||
* is exhausted to one that will only check for one connection at a time.
|
||||
* I think it unlikely that we get many more than one connection in the
|
||||
* time between pulses (currently one second). However, just to be safe,
|
||||
* I have increased the length of the listener queue from 5 to 10
|
||||
* (see acceptCb() above). */
|
||||
if( !allPaused )
|
||||
tr_socketListForEach( s->bindSockets, &acceptCb, s );
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -187,7 +215,7 @@ sharedPulse( void * vshared )
|
|||
{
|
||||
tr_ninf( getKey( ), _( "Stopped" ) );
|
||||
tr_timerFree( &shared->pulseTimer );
|
||||
tr_netClose( shared->bindSocket );
|
||||
tr_socketListForEach( shared->bindSockets, &closeCb, shared );
|
||||
tr_natpmpClose( shared->natpmp );
|
||||
tr_upnpClose( shared->upnp );
|
||||
shared->session->shared = NULL;
|
||||
|
@ -202,6 +230,34 @@ sharedPulse( void * vshared )
|
|||
****
|
||||
***/
|
||||
|
||||
static tr_socketList *
|
||||
setupBindSockets( tr_port port )
|
||||
{
|
||||
/* Do we care if an address is in use? Probably not, since it will be
|
||||
* caught later. This will only set up the list of sockets to bind. */
|
||||
int s4, s6;
|
||||
tr_socketList * socks = NULL;
|
||||
s6 = tr_netBindTCP( &tr_in6addr_any, port, TRUE );
|
||||
if( s6 >= 0 || -s6 != EAFNOSUPPORT ) /* we support ipv6 */
|
||||
{
|
||||
socks = tr_socketListNew( &tr_in6addr_any );
|
||||
listen( s6, 1 );
|
||||
}
|
||||
s4 = tr_netBindTCP( &tr_inaddr_any, port, TRUE );
|
||||
if( s4 >= 0 ) /* we bound *with* the ipv6 socket bound (need both)
|
||||
* or only have ipv4 */
|
||||
{
|
||||
if( socks )
|
||||
tr_socketListAppend( socks, &tr_inaddr_any );
|
||||
else
|
||||
socks = tr_socketListNew( &tr_inaddr_any );
|
||||
tr_netClose( s4 );
|
||||
}
|
||||
if( s6 >= 0 )
|
||||
tr_netClose( s6 );
|
||||
return socks;
|
||||
}
|
||||
|
||||
tr_shared *
|
||||
tr_sharedInit( tr_session * session,
|
||||
tr_bool isEnabled,
|
||||
|
@ -211,8 +267,9 @@ tr_sharedInit( tr_session * session,
|
|||
|
||||
s->session = session;
|
||||
s->publicPort = publicPort;
|
||||
s->bindPort = -1;
|
||||
s->bindSocket = -1;
|
||||
s->shouldChange = TRUE;
|
||||
s->bindSockets = setupBindSockets( publicPort );
|
||||
s->shouldChange = TRUE;
|
||||
s->natpmp = tr_natpmpInit( );
|
||||
s->upnp = tr_upnpInit( );
|
||||
s->pulseTimer = tr_timerNew( session, sharedPulse, s, 1000 );
|
||||
|
@ -235,6 +292,7 @@ tr_sharedSetPort( tr_shared * s, tr_port port )
|
|||
tr_torrent * tor = NULL;
|
||||
|
||||
s->publicPort = port;
|
||||
s->shouldChange = TRUE;
|
||||
|
||||
while( ( tor = tr_torrentNext( s->session, tor ) ) )
|
||||
tr_torrentChangeMyPort( tor );
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define KEY_MAX_PEERS "max-peers"
|
||||
#define KEY_PAUSED "paused"
|
||||
#define KEY_PEERS "peers"
|
||||
#define KEY_PEERS6 "peers6"
|
||||
#define KEY_PRIORITY "priority"
|
||||
#define KEY_PROGRESS "progress"
|
||||
#define KEY_SPEEDLIMIT "speed-limit"
|
||||
|
@ -61,17 +62,22 @@ getResumeFilename( const tr_torrent * tor )
|
|||
****
|
||||
***/
|
||||
|
||||
/* TODO: resume peers6 */
|
||||
static void
|
||||
savePeers( tr_benc * dict,
|
||||
const tr_torrent * tor )
|
||||
{
|
||||
tr_pex * pex = NULL;
|
||||
const int count = tr_peerMgrGetPeers( tor->session->peerMgr,
|
||||
tor->info.hash, &pex );
|
||||
int count = tr_peerMgrGetPeers( tor->session->peerMgr,
|
||||
tor->info.hash, &pex, TR_AF_INET );
|
||||
|
||||
if( count > 0 )
|
||||
tr_bencDictAddRaw( dict, KEY_PEERS, pex, sizeof( tr_pex ) * count );
|
||||
|
||||
count = tr_peerMgrGetPeers( tor->session->peerMgr, tor->info.hash, &pex,
|
||||
TR_AF_INET6 );
|
||||
if( count > 0 )
|
||||
tr_bencDictAddRaw( dict, KEY_PEERS6, pex, sizeof( tr_pex ) * count );
|
||||
|
||||
tr_free( pex );
|
||||
}
|
||||
|
||||
|
@ -94,7 +100,22 @@ loadPeers( tr_benc * dict,
|
|||
tr_peerMgrAddPex( tor->session->peerMgr,
|
||||
tor->info.hash, TR_PEER_FROM_CACHE, &pex );
|
||||
}
|
||||
tr_tordbg( tor, "Loaded %d peers from resume file", count );
|
||||
tr_tordbg( tor, "Loaded %d IPv4 peers from resume file", count );
|
||||
ret = TR_FR_PEERS;
|
||||
}
|
||||
|
||||
if( tr_bencDictFindRaw( dict, KEY_PEERS6, &str, &len ) )
|
||||
{
|
||||
int i;
|
||||
const int count = len / sizeof( tr_pex );
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
tr_pex pex;
|
||||
memcpy( &pex, str + ( i * sizeof( tr_pex ) ), sizeof( tr_pex ) );
|
||||
tr_peerMgrAddPex( tor->session->peerMgr,
|
||||
tor->info.hash, TR_PEER_FROM_CACHE, &pex );
|
||||
}
|
||||
tr_tordbg( tor, "Loaded %d IPv6 peers from resume file", count );
|
||||
ret = TR_FR_PEERS;
|
||||
}
|
||||
|
||||
|
|
|
@ -222,9 +222,8 @@ onTrackerResponse( void * tracker UNUSED,
|
|||
case TR_TRACKER_PEERS:
|
||||
{
|
||||
size_t i, n;
|
||||
tr_pex * pex = tr_peerMgrCompactToPex( event->compact,
|
||||
event->compactLen,
|
||||
NULL, 0, &n );
|
||||
tr_pex * pex = tr_peerMgrArrayToPex( event->compact,
|
||||
event->compactLen, &n );
|
||||
if( event->allAreSeeds )
|
||||
tr_tordbg( tor, "Got %d seeds from tracker", (int)n );
|
||||
else
|
||||
|
|
|
@ -240,6 +240,68 @@ publishNewPeers( tr_tracker * t,
|
|||
tr_publisherPublish( t->publisher, t, &event );
|
||||
}
|
||||
|
||||
static void
|
||||
publishNewPeersCompact( tr_tracker * t,
|
||||
int allAreSeeds,
|
||||
void * compact,
|
||||
int compactLen )
|
||||
{
|
||||
int i;
|
||||
uint8_t *array, *walk, *compactWalk;
|
||||
const int peerCount = compactLen / 6;
|
||||
const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
|
||||
tr_address addr;
|
||||
tr_port port;
|
||||
|
||||
addr.type = TR_AF_INET;
|
||||
memset( &addr.addr, 0x00, sizeof( addr.addr ) );
|
||||
array = tr_new( uint8_t, arrayLen );
|
||||
for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; i++ )
|
||||
{
|
||||
memcpy( &addr.addr.addr4, compactWalk, 4 );
|
||||
memcpy( &port, compactWalk + 4, 2 );
|
||||
|
||||
memcpy( walk, &addr, sizeof( addr ) );
|
||||
memcpy( walk + sizeof( addr ), &port, 2 );
|
||||
|
||||
walk += sizeof( tr_address ) + 2;
|
||||
compactWalk += 6;
|
||||
}
|
||||
publishNewPeers( t, allAreSeeds, array, arrayLen );
|
||||
tr_free( array );
|
||||
}
|
||||
|
||||
static void
|
||||
publishNewPeersCompact6( tr_tracker * t,
|
||||
int allAreSeeds,
|
||||
void * compact,
|
||||
int compactLen )
|
||||
{
|
||||
int i;
|
||||
uint8_t *array, *walk, *compactWalk;
|
||||
const int peerCount = compactLen / 18;
|
||||
const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
|
||||
tr_address addr;
|
||||
tr_port port;
|
||||
|
||||
addr.type = TR_AF_INET6;
|
||||
memset( &addr.addr, 0x00, sizeof( addr.addr ) );
|
||||
array = tr_new( uint8_t, arrayLen );
|
||||
for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; i++ )
|
||||
{
|
||||
memcpy( &addr.addr.addr6, compactWalk, 16 );
|
||||
memcpy( &port, compactWalk + 16, 2 );
|
||||
|
||||
memcpy( walk, &addr, sizeof( addr ) );
|
||||
memcpy( walk + sizeof( addr ), &port, 2 );
|
||||
|
||||
walk += sizeof( tr_address ) + 2;
|
||||
compactWalk += 6;
|
||||
}
|
||||
publishNewPeers( t, allAreSeeds, array, arrayLen );
|
||||
tr_free( array );
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -276,21 +338,19 @@ updateAddresses( tr_tracker * t,
|
|||
return retry;
|
||||
}
|
||||
|
||||
/* Convert to compact form */
|
||||
static uint8_t *
|
||||
parseOldPeers( tr_benc * bePeers,
|
||||
size_t * byteCount )
|
||||
{
|
||||
/* TODO: IPv6 wtf */
|
||||
int i;
|
||||
uint8_t * compact, *walk;
|
||||
uint8_t * array, *walk;
|
||||
const int peerCount = bePeers->val.l.count;
|
||||
|
||||
assert( bePeers->type == TYPE_LIST );
|
||||
|
||||
compact = tr_new( uint8_t, peerCount * 6 );
|
||||
array = tr_new( uint8_t, peerCount * ( sizeof( tr_address ) + 2 ) );
|
||||
|
||||
for( i = 0, walk = compact; i < peerCount; ++i )
|
||||
for( i = 0, walk = array; i < peerCount; ++i )
|
||||
{
|
||||
const char * s;
|
||||
int64_t itmp;
|
||||
|
@ -302,24 +362,19 @@ parseOldPeers( tr_benc * bePeers,
|
|||
{
|
||||
if( tr_pton( s, &addr ) == NULL )
|
||||
continue;
|
||||
if( addr.type != TR_AF_INET )
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy( walk, &addr.addr.addr4.s_addr, 4 );
|
||||
walk += 4;
|
||||
|
||||
if( !tr_bencDictFindInt( peer, "port",
|
||||
&itmp ) || itmp < 0 || itmp > 0xffff )
|
||||
continue;
|
||||
|
||||
memcpy( walk, &addr, sizeof( tr_address ) );
|
||||
port = htons( itmp );
|
||||
memcpy( walk, &port, 2 );
|
||||
walk += 2;
|
||||
memcpy( walk + sizeof( tr_address ), &port, 2 );
|
||||
walk += sizeof( tr_address ) + 2;
|
||||
}
|
||||
|
||||
*byteCount = peerCount * 6;
|
||||
return compact;
|
||||
*byteCount = peerCount * sizeof( tr_address ) + 2;
|
||||
return array;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -432,15 +487,26 @@ onTrackerResponse( tr_session * session,
|
|||
|
||||
if( tmp->type == TYPE_STR ) /* "compact" extension */
|
||||
{
|
||||
publishNewPeers( t, allAreSeeds, tmp->val.s.s,
|
||||
publishNewPeersCompact( t, allAreSeeds, tmp->val.s.s,
|
||||
tmp->val.s.i );
|
||||
}
|
||||
else if( tmp->type == TYPE_LIST ) /* original protocol */
|
||||
{
|
||||
size_t byteCount = 0;
|
||||
uint8_t * compact = parseOldPeers( tmp, &byteCount );
|
||||
publishNewPeers( t, allAreSeeds, compact, byteCount );
|
||||
tr_free( compact );
|
||||
uint8_t * array = parseOldPeers( tmp, &byteCount );
|
||||
publishNewPeers( t, allAreSeeds, array, byteCount );
|
||||
tr_free( array );
|
||||
}
|
||||
}
|
||||
|
||||
if( ( tmp = tr_bencDictFind( &benc, "peers6" ) ) )
|
||||
{
|
||||
const int allAreSeeds = incomplete == 0;
|
||||
|
||||
if( tmp->type == TYPE_STR ) /* "compact" extension */
|
||||
{
|
||||
publishNewPeersCompact6( t, allAreSeeds, tmp->val.s.s,
|
||||
tmp->val.s.i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue