1
0
Fork 0
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:
Charles Kerr 2008-12-15 00:17:08 +00:00
parent da6b7ee137
commit 54be88dec3
11 changed files with 671 additions and 232 deletions

View file

@ -450,16 +450,19 @@ getSocketMax( struct tr_fd_s * gFd )
} }
int int
tr_fdSocketCreate( int type ) tr_fdSocketCreate( int domain, int type )
{ {
int s = -1; int s = -1;
tr_lockLock( gFd->lock ); tr_lockLock( gFd->lock );
if( gFd->socketCount < getSocketMax( gFd ) ) 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_err( _( "Couldn't create socket: %s" ),
tr_strerror( sockerrno ) ); tr_strerror( sockerrno ) );
s = -sockerrno;
}
if( s > -1 ) if( s > -1 )
++gFd->socketCount; ++gFd->socketCount;
@ -485,7 +488,7 @@ tr_fdSocketAccept( int b,
tr_lockLock( gFd->lock ); tr_lockLock( gFd->lock );
if( gFd->socketCount < getSocketMax( gFd ) ) if( gFd->socketCount < getSocketMax( gFd ) )
{ {
len = sizeof( struct sockaddr ); len = sizeof( struct sockaddr_storage );
s = accept( b, (struct sockaddr *) &sock, &len ); s = accept( b, (struct sockaddr *) &sock, &len );
} }
if( s > -1 ) if( s > -1 )
@ -503,8 +506,7 @@ tr_fdSocketAccept( int b,
{ {
struct sockaddr_in6 * sock6 = (struct sockaddr_in6 *)&sock; struct sockaddr_in6 * sock6 = (struct sockaddr_in6 *)&sock;
addr->type = TR_AF_INET6; addr->type = TR_AF_INET6;
memcpy( &addr->addr, &sock6->sin6_addr, addr->addr.addr6 = sock6->sin6_addr;
sizeof( struct sockaddr_in6 ) );
*port = sock6->sin6_port; *port = sock6->sin6_port;
} }
++gFd->socketCount; ++gFd->socketCount;

View file

@ -85,7 +85,7 @@ void tr_fdFileClose( const char * filename );
/*********************************************************************** /***********************************************************************
* Sockets * Sockets
**********************************************************************/ **********************************************************************/
int tr_fdSocketCreate( int type ); int tr_fdSocketCreate( int domain, int type );
int tr_fdSocketAccept( int b, int tr_fdSocketAccept( int b,
tr_address * addr, tr_address * addr,

View file

@ -26,6 +26,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <sys/types.h> #include <sys/types.h>
@ -107,7 +108,17 @@ tr_pton( const char * src, tr_address * dst )
return NULL; return NULL;
dst->type = TR_AF_INET6; dst->type = TR_AF_INET6;
return 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. * Compare two tr_address structures.
@ -139,6 +150,98 @@ tr_compareAddresses( const tr_address * a, const tr_address * b)
return retval; 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 * TCP sockets
**********************************************************************/ **********************************************************************/
@ -161,10 +264,12 @@ makeSocketNonBlocking( int fd )
{ {
if( evutil_make_socket_nonblocking( fd ) ) if( evutil_make_socket_nonblocking( fd ) )
{ {
int tmperrno;
tr_err( _( "Couldn't create socket: %s" ), tr_err( _( "Couldn't create socket: %s" ),
tr_strerror( sockerrno ) ); tr_strerror( sockerrno ) );
tmperrno = sockerrno;
tr_netClose( fd ); tr_netClose( fd );
fd = -1; fd = -tmperrno;
} }
} }
@ -172,9 +277,9 @@ makeSocketNonBlocking( int fd )
} }
static int static int
createSocket( int type ) createSocket( int domain, int type )
{ {
return makeSocketNonBlocking( tr_fdSocketCreate( type ) ); return makeSocketNonBlocking( tr_fdSocketCreate( domain, type ) );
} }
static void static void
@ -191,59 +296,65 @@ setSndBuf( tr_session * session UNUSED, int fd UNUSED )
#endif #endif
} }
static void static socklen_t
setup_sockaddr( const tr_address * addr, setup_sockaddr( const tr_address * addr,
tr_port port, tr_port port,
struct sockaddr_storage * sockaddr) struct sockaddr_storage * sockaddr)
{ {
struct sockaddr_in sock4; struct sockaddr_in sock4;
struct sockaddr_in6 sock6; struct sockaddr_in6 sock6;
if( addr->type == TR_AF_INET )
{
memset( &sock4, 0, sizeof( sock4 ) );
sock4.sin_family = AF_INET;
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;
sock6.sin6_flowinfo = 0;
sock6.sin6_addr = addr->addr.addr6;
memcpy( sockaddr, &sock6, sizeof( sock6 ) );
return sizeof( struct sockaddr_in6 );
}
}
if( addr->type == TR_AF_INET ) int
{ tr_netOpenTCP( tr_session * session,
memset( &sock4, 0, sizeof( sock4 ) ); const tr_address * addr,
sock4.sin_family = AF_INET; tr_port port )
sock4.sin_addr.s_addr = addr->addr.addr4.s_addr; {
sock4.sin_port = port; int s;
memcpy( sockaddr, &sock4, sizeof( sock4 ) ); struct sockaddr_storage sock;
} const int type = SOCK_STREAM;
else socklen_t addrlen;
{
memset( &sock6, 0, sizeof( sock6 ) );
sock6.sin6_family = AF_INET6;
sock6.sin6_port = port;
memcpy( &sock6.sin6_addr, &addr->addr, sizeof( struct in6_addr ) );
memcpy( sockaddr, &sock6, sizeof( sock6 ) );
}
}
int
tr_netOpenTCP( tr_session * session,
const tr_address * addr,
tr_port port )
{
int s;
struct sockaddr_storage sock;
const int type = SOCK_STREAM;
if( ( s = createSocket( type ) ) < 0 ) if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
return -1; type ) ) < 0 )
return s;
setSndBuf( session, s ); setSndBuf( session, s );
setup_sockaddr( addr, port, &sock ); addrlen = setup_sockaddr( addr, port, &sock );
if( ( connect( s, (struct sockaddr *) &sock, if( ( connect( s, (struct sockaddr *) &sock,
sizeof( struct sockaddr ) ) < 0 ) addrlen ) < 0 )
#ifdef WIN32 #ifdef WIN32
&& ( sockerrno != WSAEWOULDBLOCK ) && ( sockerrno != WSAEWOULDBLOCK )
#endif #endif
&& ( sockerrno != EINPROGRESS ) ) && ( sockerrno != EINPROGRESS ) )
{ {
int tmperrno;
tr_err( _( "Couldn't connect socket %d to %s, port %d (errno %d - %s)" ), 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 ) ); s, tr_ntop_non_ts( addr ), (int)port, sockerrno, tr_strerror( sockerrno ) );
tmperrno = sockerrno;
tr_netClose( s ); tr_netClose( s );
s = -1; s = -tmperrno;
} }
tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)", tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)",
@ -253,37 +364,42 @@ tr_netOpenTCP( tr_session * session,
} }
int int
tr_netBindTCP( const tr_address * addr, tr_port port ) tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
{ {
int s; int s;
struct sockaddr_storage sock; struct sockaddr_storage sock;
const int type = SOCK_STREAM; const int type = SOCK_STREAM;
int addrlen;
#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT ) #if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
int optval; int optval;
#endif #endif
if( ( s = createSocket( type ) ) < 0 ) if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
return -1; type ) ) < 0 )
return s;
#ifdef SO_REUSEADDR #ifdef SO_REUSEADDR
optval = 1; optval = 1;
setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) ); setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) );
#endif #endif
setup_sockaddr( addr, htons( port ), &sock ); addrlen = setup_sockaddr( addr, htons( port ), &sock );
if( bind( s, (struct sockaddr *) &sock, if( bind( s, (struct sockaddr *) &sock,
sizeof( struct sockaddr ) ) ) addrlen ) )
{ {
tr_err( _( "Couldn't bind port %d on %s: %s" ), port, int tmperrno;
tr_ntop_non_ts( addr ), tr_strerror( sockerrno ) ); 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 ); tr_netClose( s );
return -1; return -tmperrno;
} }
if( !suppressMsgs )
tr_dbg( "Bound socket %d to port %d on %s", tr_dbg( "Bound socket %d to port %d on %s",
s, port, tr_ntop_non_ts( addr ) ); s, port, tr_ntop_non_ts( addr ) );
return s; return s;
} }

View file

@ -55,30 +55,51 @@
struct tr_session; struct tr_session;
#define TR_AF_INET 0 #define TR_AF_INET 0
#define TR_AF_INET6 1 #define TR_AF_INET6 1
typedef struct tr_address { typedef struct tr_address {
unsigned short type : 1; uint8_t type;
union { union {
/* The order here is important for tr_in{,6}addr_any initialization, /* The order here is important for tr_in{,6}addr_any initialization,
* since we can't use C99 designated initializers */ * since we can't use C99 designated initializers */
struct in6_addr addr6; struct in6_addr addr6;
struct in_addr addr4; struct in_addr addr4;
} addr; } addr;
} tr_address; } tr_address;
extern const tr_address tr_inaddr_any; extern const tr_address tr_inaddr_any;
extern const tr_address tr_in6addr_any; extern const tr_address tr_in6addr_any;
const char *tr_ntop( const tr_address * src, const char *tr_ntop( const tr_address * src,
char * dst, char * dst,
int size ); int size );
const char *tr_ntop_non_ts( const tr_address * src ); const char *tr_ntop_non_ts( const tr_address * src );
tr_address *tr_pton( const char * src, tr_address *tr_pton( const char * src,
tr_address * dst ); tr_address * dst );
int tr_compareAddresses( const tr_address * a, int tr_compareAddresses( const tr_address * a,
const tr_address * b); 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 * Sockets
@ -88,7 +109,8 @@ int tr_netOpenTCP( struct tr_handle * session,
tr_port port ); tr_port port );
int tr_netBindTCP( const tr_address * addr, int tr_netBindTCP( const tr_address * addr,
tr_port port ); tr_port port,
tr_bool suppressMsgs );
int tr_netAccept( struct tr_handle * session, int tr_netAccept( struct tr_handle * session,
int bound, int bound,

View file

@ -1346,7 +1346,7 @@ tr_peerMgrAddPex( tr_peerMgr * manager,
t = getExistingTorrent( manager, torrentHash ); t = getExistingTorrent( manager, torrentHash );
if( !tr_sessionIsAddressBlocked( t->manager->session, &pex->addr ) ) if( !tr_sessionIsAddressBlocked( t->manager->session, &pex->addr ) )
ensureAtomExists( t, &pex->addr, pex->port, pex->flags, from ); ensureAtomExists( t, &pex->addr, pex->port, pex->flags, from );
managerUnlock( manager ); managerUnlock( manager );
} }
@ -1375,6 +1375,53 @@ tr_peerMgrCompactToPex( const void * compact,
return pex; 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;
}
/** /**
*** ***
**/ **/
@ -1434,11 +1481,13 @@ peerPrefersCrypto( const tr_peer * peer )
} }
int int
tr_peerMgrGetPeers( tr_peerMgr * manager, tr_peerMgrGetPeers( tr_peerMgr * manager,
const uint8_t * torrentHash, const uint8_t * torrentHash,
tr_pex ** setme_pex ) tr_pex ** setme_pex,
uint8_t af)
{ {
int peerCount = 0; int peerCount = 0;
int peersReturning = 0;
const Torrent * t; const Torrent * t;
managerLock( manager ); managerLock( manager );
@ -1452,30 +1501,36 @@ tr_peerMgrGetPeers( tr_peerMgr * manager,
{ {
int i; int i;
const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount ); 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 * pex = tr_new( tr_pex, peerCount );
tr_pex * walk = pex; tr_pex * walk = pex;
for( i=0; i<peerCount; ++i, ++walk ) for( i=0; i<peerCount; ++i, ++walk )
{ {
const tr_peer * peer = peers[i]; const tr_peer * peer = peers[i];
const struct peer_atom * atom = getExistingAtom( t, &peer->addr ); if( peer->addr.type == af )
{
walk->addr = peer->addr; const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
walk->port = peer->port; memcpy( &walk->addr, &peer->addr, sizeof( walk->addr ) );
walk->flags = 0; walk->port = peer->port;
if( peerPrefersCrypto( peer ) ) walk->flags = 0;
walk->flags |= ADDED_F_ENCRYPTION_FLAG; if( peerPrefersCrypto( peer ) )
if( ( atom->uploadOnly == UPLOAD_ONLY_YES ) || ( peer->progress >= 1.0 ) ) walk->flags |= ADDED_F_ENCRYPTION_FLAG;
walk->flags |= ADDED_F_SEED_FLAG; if( ( atom->uploadOnly == UPLOAD_ONLY_YES ) ||
( peer->progress >= 1.0 ) )
walk->flags |= ADDED_F_SEED_FLAG;
peersReturning++;
}
} }
assert( ( walk - pex ) == peerCount ); assert( ( walk - pex ) == peerCount );
qsort( pex, peerCount, sizeof( tr_pex ), tr_pexCompare ); qsort( pex, peersReturning, sizeof( tr_pex ), tr_pexCompare );
*setme_pex = pex; *setme_pex = pex;
} }
managerUnlock( manager ); managerUnlock( manager );
return peerCount; return peersReturning;
} }
static int reconnectPulse( void * vtorrent ); static int reconnectPulse( void * vtorrent );
@ -1785,9 +1840,13 @@ tr_peerMgrPeerStats( const tr_peerMgr * manager,
const tr_peer * peer = peers[i]; const tr_peer * peer = peers[i];
const struct peer_atom * atom = getExistingAtom( t, &peer->addr ); const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
tr_peer_stat * stat = ret + i; tr_peer_stat * stat = ret + i;
tr_address norm_addr;
tr_ntop( &peer->addr, stat->addr, sizeof(stat->addr) ); memcpy( &norm_addr, &peer->addr, sizeof( tr_address ) );
tr_strlcpy( stat->client, (peer->client ? peer->client : ""), sizeof(stat->client) ); 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->port = ntohs( peer->port );
stat->from = atom->from; stat->from = atom->from;
stat->progress = peer->progress; stat->progress = peer->progress;

View file

@ -67,6 +67,16 @@ tr_pex * tr_peerMgrCompactToPex( const void * compact,
size_t added_f_len, size_t added_f_len,
size_t * setme_pex_count ); 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, void tr_peerMgrAddPex( tr_peerMgr * manager,
const uint8_t * torrentHash, const uint8_t * torrentHash,
uint8_t from, uint8_t from,
@ -79,7 +89,8 @@ void tr_peerMgrSetBlame( tr_peerMgr * manager,
int tr_peerMgrGetPeers( tr_peerMgr * manager, int tr_peerMgrGetPeers( tr_peerMgr * manager,
const uint8_t * torrentHash, const uint8_t * torrentHash,
tr_pex ** setme_pex ); tr_pex ** setme_pex,
uint8_t af);
void tr_peerMgrStartTorrent( tr_peerMgr * manager, void tr_peerMgrStartTorrent( tr_peerMgr * manager,
const uint8_t * torrentHash ); const uint8_t * torrentHash );

View file

@ -282,6 +282,7 @@ struct tr_peermsgs
uint8_t state; uint8_t state;
uint8_t ut_pex_id; uint8_t ut_pex_id;
uint16_t pexCount; uint16_t pexCount;
uint16_t pexCount6;
uint16_t minActiveRequests; uint16_t minActiveRequests;
uint16_t maxActiveRequests; uint16_t maxActiveRequests;
@ -308,6 +309,7 @@ struct tr_peermsgs
tr_timer * pexTimer; tr_timer * pexTimer;
tr_pex * pex; tr_pex * pex;
tr_pex * pex6;
time_t clientSentPexAt; time_t clientSentPexAt;
time_t clientSentAnythingAt; time_t clientSentAnythingAt;
@ -1181,19 +1183,40 @@ parseUtPex( tr_peermsgs * msgs, int msglen, struct evbuffer * inbuf )
tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp, msglen ); tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp, msglen );
if( tr_torrentAllowsPex( tor ) if( tr_torrentAllowsPex( tor )
&& (( loaded = !tr_bencLoad( tmp, msglen, &val, NULL ))) && ( ( loaded = !tr_bencLoad( tmp, msglen, &val, NULL ) ) ) )
&& tr_bencDictFindRaw( &val, "added", &added, &added_len ))
{ {
const uint8_t * added_f = NULL; if( tr_bencDictFindRaw( &val, "added", &added, &added_len ) )
tr_pex * pex; {
size_t i, n; const uint8_t * added_f = NULL;
size_t added_f_len = 0; tr_pex * pex;
tr_bencDictFindRaw( &val, "added.f", &added_f, &added_f_len ); size_t i, n;
pex = tr_peerMgrCompactToPex( added, added_len, added_f, added_f_len, &n ); size_t added_f_len = 0;
for( i=0; i<n; ++i ) tr_bencDictFindRaw( &val, "added.f", &added_f, &added_f_len );
tr_peerMgrAddPex( msgs->session->peerMgr, tor->info.hash, pex =
TR_PEER_FROM_PEX, pex + i ); tr_peerMgrCompactToPex( added, added_len, added_f, added_f_len,
tr_free( pex ); &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 ) if( loaded )
@ -2005,17 +2028,21 @@ pexElementCb( void * vpex,
diffs->elements[diffs->elementCount++] = *pex; diffs->elements[diffs->elementCount++] = *pex;
} }
/* TODO: ipv6 pex */
static void static void
sendPex( tr_peermsgs * msgs ) sendPex( tr_peermsgs * msgs )
{ {
if( msgs->peerSupportsPex && tr_torrentAllowsPex( msgs->torrent ) ) if( msgs->peerSupportsPex && tr_torrentAllowsPex( msgs->torrent ) )
{ {
PexDiffs diffs; PexDiffs diffs;
PexDiffs diffs6;
tr_pex * newPex = NULL; tr_pex * newPex = NULL;
tr_pex * newPex6 = NULL;
const int newCount = tr_peerMgrGetPeers( msgs->session->peerMgr, const int newCount = tr_peerMgrGetPeers( msgs->session->peerMgr,
msgs->torrent->info.hash, 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 */ /* build the diffs */
diffs.added = tr_new( tr_pex, newCount ); diffs.added = tr_new( tr_pex, newCount );
@ -2028,14 +2055,28 @@ sendPex( tr_peermsgs * msgs )
newPex, newCount, newPex, newCount,
tr_pexCompare, sizeof( tr_pex ), tr_pexCompare, sizeof( tr_pex ),
pexDroppedCb, pexAddedCb, pexElementCb, &diffs ); 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( dbgmsg(
msgs, msgs,
"pex: old peer count %d, new peer count %d, added %d, removed %d", "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( diffs.elements );
tr_free( diffs6.elements );
} }
else else
{ {
@ -2050,13 +2091,18 @@ sendPex( tr_peermsgs * msgs )
tr_free( msgs->pex ); tr_free( msgs->pex );
msgs->pex = diffs.elements; msgs->pex = diffs.elements;
msgs->pexCount = diffs.elementCount; msgs->pexCount = diffs.elementCount;
tr_free( msgs->pex6 );
msgs->pex6 = diffs6.elements;
msgs->pexCount6 = diffs6.elementCount;
/* build the pex payload */ /* build the pex payload */
tr_bencInitDict( &val, 3 ); tr_bencInitDict( &val, 3 ); /* ipv6 support: left as 3:
* speed vs. likelihood? */
/* "added" */ /* "added" */
tmp = walk = tr_new( uint8_t, diffs.addedCount * 6 ); 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].addr.addr, 4 ); walk += 4;
memcpy( walk, &diffs.added[i].port, 2 ); walk += 2; memcpy( walk, &diffs.added[i].port, 2 ); walk += 2;
} }
@ -2074,13 +2120,48 @@ sendPex( tr_peermsgs * msgs )
/* "dropped" */ /* "dropped" */
tmp = walk = tr_new( uint8_t, diffs.droppedCount * 6 ); 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].addr.addr, 4 ); walk += 4;
memcpy( walk, &diffs.dropped[i].port, 2 ); walk += 2; memcpy( walk, &diffs.dropped[i].port, 2 ); walk += 2;
} }
assert( ( walk - tmp ) == diffs.droppedCount * 6 ); assert( ( walk - tmp ) == diffs.droppedCount * 6 );
tr_bencDictAddRaw( &val, "dropped", tmp, walk - tmp ); tr_bencDictAddRaw( &val, "dropped", tmp, walk - tmp );
tr_free( 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 */ /* write the pex message */
benc = tr_bencSave( &val, &bencLen ); benc = tr_bencSave( &val, &bencLen );
@ -2099,6 +2180,9 @@ sendPex( tr_peermsgs * msgs )
tr_free( diffs.added ); tr_free( diffs.added );
tr_free( diffs.dropped ); tr_free( diffs.dropped );
tr_free( newPex ); tr_free( newPex );
tr_free( diffs6.added );
tr_free( diffs6.dropped );
tr_free( newPex6 );
msgs->clientSentPexAt = time( NULL ); msgs->clientSentPexAt = time( NULL );
} }
@ -2175,6 +2259,7 @@ tr_peerMsgsFree( tr_peermsgs* msgs )
evbuffer_free( msgs->incoming.block ); evbuffer_free( msgs->incoming.block );
evbuffer_free( msgs->outMessages ); evbuffer_free( msgs->outMessages );
tr_free( msgs->pex6 );
tr_free( msgs->pex ); tr_free( msgs->pex );
memset( msgs, ~0, sizeof( tr_peermsgs ) ); memset( msgs, ~0, sizeof( tr_peermsgs ) );

View file

@ -38,9 +38,9 @@ struct tr_shared
tr_port_forwarding natpmpStatus; tr_port_forwarding natpmpStatus;
tr_port_forwarding upnpStatus; tr_port_forwarding upnpStatus;
int bindPort; tr_bool shouldChange;
int bindSocket; tr_socketList * bindSockets;
int publicPort; tr_port publicPort;
tr_timer * pulseTimer; tr_timer * pulseTimer;
@ -84,10 +84,10 @@ getNatStateStr( int state )
static void static void
natPulse( tr_shared * s ) natPulse( tr_shared * s )
{ {
const int port = s->publicPort; const tr_port port = s->publicPort;
const int isEnabled = s->isEnabled && !s->isShuttingDown; const int isEnabled = s->isEnabled && !s->isShuttingDown;
int oldStatus; int oldStatus;
int newStatus; int newStatus;
oldStatus = tr_sharedTraversalStatus( s ); oldStatus = tr_sharedTraversalStatus( s );
s->natpmpStatus = tr_natpmpPulse( s->natpmp, port, isEnabled ); s->natpmpStatus = tr_natpmpPulse( s->natpmp, port, isEnabled );
@ -100,75 +100,103 @@ natPulse( tr_shared * s )
getNatStateStr( newStatus ) ); getNatStateStr( newStatus ) );
} }
/*
* Callbacks for socket list
*/
static void
closeCb( int * const socket,
tr_address * const addr,
void * const userData )
{
tr_shared * s = ( tr_shared * )userData;
if( *socket >= 0 )
{
tr_ninf( getKey( ), _( "Closing port %d on %s" ), s->publicPort,
tr_ntop_non_ts( addr ) );
tr_netClose( *socket );
}
}
static void
acceptCb( int * const socket,
tr_address * const addr,
void * const userData )
{
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 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 on %s to listen for incoming peer connections (errno %d - %s)" ),
s->publicPort, tr_ntop_non_ts( addr ), errno, tr_strerror( errno ) );
}
}
static void static void
incomingPeersPulse( tr_shared * s ) incomingPeersPulse( tr_shared * s )
{ {
tr_bool allPaused; int allPaused;
tr_torrent * tor; tr_torrent * tor;
if( s->bindSocket >= 0 && ( s->bindPort != s->publicPort ) ) if( s->shouldChange )
{ {
tr_ninf( getKey( ), _( "Closing port %d" ), s->bindPort ); tr_socketListForEach( s->bindSockets, &closeCb, s );
tr_netClose( s->bindSocket ); s->shouldChange = FALSE;
s->bindSocket = -1; if( s->publicPort > 0 )
tr_socketListForEach( s->bindSockets, &bindCb, s );
} }
if( ( s->publicPort > 0 ) && ( s->bindPort != s->publicPort ) ) /* see if any torrents aren't paused */
allPaused = 1;
tor = NULL;
while( ( tor = tr_torrentNext( s->session, tor ) ) )
{ {
int socket; if( TR_STATUS_IS_ACTIVE( tr_torrentGetActivity( tor ) ) )
errno = 0;
socket = tr_netBindTCP( &tr_inaddr_any, s->publicPort );
if( socket >= 0 )
{ {
tr_ninf( getKey( ), allPaused = 0;
_( break;
"Opened port %d to listen for incoming peer connections" ),
s->publicPort );
s->bindPort = s->publicPort;
s->bindSocket = socket;
listen( s->bindSocket, 5 );
}
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;
} }
} }
/* see if any torrents aren't paused */ /* if we have any running torrents, check for new incoming peer connections */
allPaused = 1; /* (jhujhiti):
tor = NULL; * This has been changed from a loop that will end when the listener queue
while(( tor = tr_torrentNext( s->session, tor ))) { * is exhausted to one that will only check for one connection at a time.
if( TR_STATUS_IS_ACTIVE( tr_torrentGetActivity( tor ))) { * I think it unlikely that we get many more than one connection in the
allPaused = 0; * time between pulses (currently one second). However, just to be safe,
break; * I have increased the length of the listener queue from 5 to 10
} * (see acceptCb() above). */
} if( !allPaused )
tr_socketListForEach( s->bindSockets, &acceptCb, s );
/* 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 );
}
} }
static int static int
@ -187,7 +215,7 @@ sharedPulse( void * vshared )
{ {
tr_ninf( getKey( ), _( "Stopped" ) ); tr_ninf( getKey( ), _( "Stopped" ) );
tr_timerFree( &shared->pulseTimer ); tr_timerFree( &shared->pulseTimer );
tr_netClose( shared->bindSocket ); tr_socketListForEach( shared->bindSockets, &closeCb, shared );
tr_natpmpClose( shared->natpmp ); tr_natpmpClose( shared->natpmp );
tr_upnpClose( shared->upnp ); tr_upnpClose( shared->upnp );
shared->session->shared = NULL; 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_shared *
tr_sharedInit( tr_session * session, tr_sharedInit( tr_session * session,
tr_bool isEnabled, tr_bool isEnabled,
@ -211,8 +267,9 @@ tr_sharedInit( tr_session * session,
s->session = session; s->session = session;
s->publicPort = publicPort; s->publicPort = publicPort;
s->bindPort = -1; s->shouldChange = TRUE;
s->bindSocket = -1; s->bindSockets = setupBindSockets( publicPort );
s->shouldChange = TRUE;
s->natpmp = tr_natpmpInit( ); s->natpmp = tr_natpmpInit( );
s->upnp = tr_upnpInit( ); s->upnp = tr_upnpInit( );
s->pulseTimer = tr_timerNew( session, sharedPulse, s, 1000 ); s->pulseTimer = tr_timerNew( session, sharedPulse, s, 1000 );
@ -234,7 +291,8 @@ tr_sharedSetPort( tr_shared * s, tr_port port )
{ {
tr_torrent * tor = NULL; tr_torrent * tor = NULL;
s->publicPort = port; s->publicPort = port;
s->shouldChange = TRUE;
while( ( tor = tr_torrentNext( s->session, tor ) ) ) while( ( tor = tr_torrentNext( s->session, tor ) ) )
tr_torrentChangeMyPort( tor ); tr_torrentChangeMyPort( tor );

View file

@ -34,6 +34,7 @@
#define KEY_MAX_PEERS "max-peers" #define KEY_MAX_PEERS "max-peers"
#define KEY_PAUSED "paused" #define KEY_PAUSED "paused"
#define KEY_PEERS "peers" #define KEY_PEERS "peers"
#define KEY_PEERS6 "peers6"
#define KEY_PRIORITY "priority" #define KEY_PRIORITY "priority"
#define KEY_PROGRESS "progress" #define KEY_PROGRESS "progress"
#define KEY_SPEEDLIMIT "speed-limit" #define KEY_SPEEDLIMIT "speed-limit"
@ -61,17 +62,22 @@ getResumeFilename( const tr_torrent * tor )
**** ****
***/ ***/
/* TODO: resume peers6 */
static void static void
savePeers( tr_benc * dict, savePeers( tr_benc * dict,
const tr_torrent * tor ) const tr_torrent * tor )
{ {
tr_pex * pex = NULL; tr_pex * pex = NULL;
const int count = tr_peerMgrGetPeers( tor->session->peerMgr, int count = tr_peerMgrGetPeers( tor->session->peerMgr,
tor->info.hash, &pex ); tor->info.hash, &pex, TR_AF_INET );
if( count > 0 ) if( count > 0 )
tr_bencDictAddRaw( dict, KEY_PEERS, pex, sizeof( tr_pex ) * count ); 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 ); tr_free( pex );
} }
@ -94,7 +100,22 @@ loadPeers( tr_benc * dict,
tr_peerMgrAddPex( tor->session->peerMgr, tr_peerMgrAddPex( tor->session->peerMgr,
tor->info.hash, TR_PEER_FROM_CACHE, &pex ); 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; ret = TR_FR_PEERS;
} }

View file

@ -222,10 +222,9 @@ onTrackerResponse( void * tracker UNUSED,
case TR_TRACKER_PEERS: case TR_TRACKER_PEERS:
{ {
size_t i, n; size_t i, n;
tr_pex * pex = tr_peerMgrCompactToPex( event->compact, tr_pex * pex = tr_peerMgrArrayToPex( event->compact,
event->compactLen, event->compactLen, &n );
NULL, 0, &n ); if( event->allAreSeeds )
if( event->allAreSeeds )
tr_tordbg( tor, "Got %d seeds from tracker", (int)n ); tr_tordbg( tor, "Got %d seeds from tracker", (int)n );
else else
tr_torinf( tor, _( "Got %d peers from tracker" ), (int)n ); tr_torinf( tor, _( "Got %d peers from tracker" ), (int)n );

View file

@ -240,6 +240,68 @@ publishNewPeers( tr_tracker * t,
tr_publisherPublish( t->publisher, t, &event ); 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,50 +338,43 @@ updateAddresses( tr_tracker * t,
return retry; return retry;
} }
/* Convert to compact form */
static uint8_t * static uint8_t *
parseOldPeers( tr_benc * bePeers, parseOldPeers( tr_benc * bePeers,
size_t * byteCount ) size_t * byteCount )
{ {
/* TODO: IPv6 wtf */
int i; int i;
uint8_t * compact, *walk; uint8_t * array, *walk;
const int peerCount = bePeers->val.l.count; const int peerCount = bePeers->val.l.count;
assert( bePeers->type == TYPE_LIST ); 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; const char * s;
int64_t itmp; int64_t itmp;
tr_address addr; tr_address addr;
tr_port port; tr_port port;
tr_benc * peer = &bePeers->val.l.vals[i]; tr_benc * peer = &bePeers->val.l.vals[i];
if( tr_bencDictFindStr( peer, "ip", &s ) )
{
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_bencDictFindStr( peer, "ip", &s ) )
{
if( tr_pton( s, &addr ) == NULL )
continue;
}
if( !tr_bencDictFindInt( peer, "port", if( !tr_bencDictFindInt( peer, "port",
&itmp ) || itmp < 0 || itmp > 0xffff ) &itmp ) || itmp < 0 || itmp > 0xffff )
continue; continue;
memcpy( walk, &addr, sizeof( tr_address ) );
port = htons( itmp ); port = htons( itmp );
memcpy( walk, &port, 2 ); memcpy( walk + sizeof( tr_address ), &port, 2 );
walk += 2; walk += sizeof( tr_address ) + 2;
} }
*byteCount = peerCount * 6; *byteCount = peerCount * sizeof( tr_address ) + 2;
return compact; return array;
} }
static void static void
@ -432,15 +487,26 @@ onTrackerResponse( tr_session * session,
if( tmp->type == TYPE_STR ) /* "compact" extension */ 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 ); tmp->val.s.i );
} }
else if( tmp->type == TYPE_LIST ) /* original protocol */ else if( tmp->type == TYPE_LIST ) /* original protocol */
{ {
size_t byteCount = 0; size_t byteCount = 0;
uint8_t * compact = parseOldPeers( tmp, &byteCount ); uint8_t * array = parseOldPeers( tmp, &byteCount );
publishNewPeers( t, allAreSeeds, compact, byteCount ); publishNewPeers( t, allAreSeeds, array, byteCount );
tr_free( compact ); 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 );
} }
} }
} }