1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-01-30 19:03:04 +00:00

Update 2006-01-11

This commit is contained in:
Eric Petit 2006-01-12 19:12:58 +00:00
parent a1de0a4fa0
commit 07b9da73fc
11 changed files with 402 additions and 159 deletions

View file

@ -8,7 +8,7 @@ if ! $(DEFINES)
VERSION_MAJOR = 0 ;
VERSION_MINOR = 4 ;
# VERSION_STRING = $(VERSION_MAJOR).$(VERSION_MINOR) ;
VERSION_STRING = CVS-20051221 ;
VERSION_STRING = 0.5-cvs ;
DEFINES += VERSION_MAJOR=$(VERSION_MAJOR)
VERSION_MINOR=$(VERSION_MINOR)

View file

@ -89,11 +89,11 @@ typedef struct tr_completion_s tr_completion_t;
#include "bencode.h"
#include "metainfo.h"
#include "tracker.h"
#include "fdlimit.h"
#include "peer.h"
#include "net.h"
#include "inout.h"
#include "upload.h"
#include "fdlimit.h"
#include "clients.h"
struct tr_torrent_s
@ -140,8 +140,6 @@ struct tr_torrent_s
tr_io_t * io;
uint64_t stopDate;
int bindSocket;
int bindPort;
int peerCount;
tr_peer_t * peers[TR_MAX_PEER_COUNT];
@ -162,9 +160,17 @@ struct tr_handle_s
tr_fd_t * fdlimit;
int bindPort;
int bindSocket;
int acceptPeerCount;
tr_peer_t * acceptPeers[TR_MAX_PEER_COUNT];
char id[21];
char key[21];
volatile char acceptDie;
tr_thread_t acceptThread;
tr_lock_t acceptLock;
};
#endif

View file

@ -106,11 +106,13 @@ int tr_netOpen( struct in_addr addr, in_port_t port )
return s;
}
int tr_netBind( int * port )
int tr_netBind( int port )
{
int s, i;
int s;
struct sockaddr_in sock;
int minPort, maxPort;
#ifdef SO_REUSEADDR
int optval;
#endif
s = createSocket();
if( s < 0 )
@ -118,34 +120,25 @@ int tr_netBind( int * port )
return -1;
}
minPort = *port;
maxPort = minPort + 1000;
maxPort = MIN( maxPort, 65535 );
#ifdef SO_REUSEADDR
optval = 1;
setsockopt( s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) );
#endif
for( i = minPort; i <= maxPort; i++ )
{
memset( &sock, 0, sizeof( sock ) );
sock.sin_family = AF_INET;
sock.sin_addr.s_addr = INADDR_ANY;
sock.sin_port = htons( i );
if( !bind( s, (struct sockaddr *) &sock,
sizeof( struct sockaddr_in ) ) )
{
break;
}
}
if( i > maxPort )
memset( &sock, 0, sizeof( sock ) );
sock.sin_family = AF_INET;
sock.sin_addr.s_addr = INADDR_ANY;
sock.sin_port = htons( port );
if( bind( s, (struct sockaddr *) &sock,
sizeof( struct sockaddr_in ) ) )
{
tr_err( "Could not bind port %d", port );
tr_netClose( s );
tr_err( "Could not bind any port from %d to %d",
minPort, maxPort );
return -1;
}
tr_inf( "Binded port %d", i );
*port = i;
tr_inf( "Binded port %d", port );
listen( s, 5 );
return s;

View file

@ -22,7 +22,7 @@
int tr_netResolve ( char *, struct in_addr * );
int tr_netOpen ( struct in_addr addr, in_port_t port );
int tr_netBind ( int * );
int tr_netBind ( int );
int tr_netAccept ( int s, struct in_addr *, in_port_t * );
void tr_netClose ( int s );

View file

@ -123,32 +123,56 @@ void tr_peerAddOld( tr_torrent_t * tor, char * ip, int port )
/***********************************************************************
* tr_peerAddCompact
***********************************************************************
* Tries to add a peer. If 's' is a negative value, will use 'addr' and
* 'port' to connect to the peer. Otherwise, use the already connected
* socket 's'.
* Tries to add a peer, using 'addr' and 'port' to connect to the peer.
**********************************************************************/
void tr_peerAddCompact( tr_torrent_t * tor, struct in_addr addr,
in_port_t port, int s )
in_port_t port )
{
tr_peer_t * peer;
addWithAddr( tor, addr, port );
}
if( s < 0 )
{
addWithAddr( tor, addr, port );
return;
}
if( !( peer = peerInit( tor ) ) )
{
tr_netClose( s );
tr_fdSocketClosed( tor->fdlimit, 0 );
return;
}
/***********************************************************************
* tr_peerInit
***********************************************************************
* Initializes a new peer.
**********************************************************************/
tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s )
{
tr_peer_t * peer = peerInit();
peer->socket = s;
peer->addr = addr;
peer->port = port;
peer->status = PEER_STATUS_CONNECTING;
return peer;
}
void tr_peerAttach( tr_torrent_t * tor, tr_peer_t * peer )
{
peerAttach( tor, peer );
}
void tr_peerDestroy( tr_fd_t * fdlimit, tr_peer_t * peer )
{
if( peer->bitfield )
{
free( peer->bitfield );
}
if( peer->buf )
{
free( peer->buf );
}
if( peer->outMessages )
{
free( peer->outMessages );
}
if( peer->status > PEER_STATUS_IDLE )
{
tr_netClose( peer->socket );
tr_fdSocketClosed( fdlimit, 0 );
}
free( peer );
}
/***********************************************************************
@ -175,29 +199,76 @@ void tr_peerRem( tr_torrent_t * tor, int i )
{
tr_uploadChoked( tor->upload );
}
if( peer->bitfield )
{
free( peer->bitfield );
}
if( peer->buf )
{
free( peer->buf );
}
if( peer->outMessages )
{
free( peer->outMessages );
}
if( peer->status > PEER_STATUS_IDLE )
{
tr_netClose( peer->socket );
tr_fdSocketClosed( tor->fdlimit, 0 );
}
free( peer );
tr_peerDestroy( tor->fdlimit, peer );
tor->peerCount--;
memmove( &tor->peers[i], &tor->peers[i+1],
( tor->peerCount - i ) * sizeof( tr_peer_t * ) );
}
/***********************************************************************
* tr_peerRead
***********************************************************************
*
**********************************************************************/
int tr_peerRead( tr_torrent_t * tor, tr_peer_t * peer )
{
int ret;
/* Try to read */
for( ;; )
{
if( peer->size < 1 )
{
peer->size = 1024;
peer->buf = malloc( peer->size );
}
else if( peer->pos >= peer->size )
{
peer->size *= 2;
peer->buf = realloc( peer->buf, peer->size );
}
ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
peer->size - peer->pos );
if( ret & TR_NET_CLOSE )
{
peer_dbg( "connection closed" );
return 1;
}
else if( ret & TR_NET_BLOCK )
{
break;
}
peer->date = tr_date();
peer->pos += ret;
if( NULL != tor )
{
if( parseBuf( tor, peer, ret ) )
{
return 1;
}
}
else
{
if( parseBufHeader( peer ) )
{
return 1;
}
}
}
return 0;
}
/***********************************************************************
* tr_peerHash
***********************************************************************
*
**********************************************************************/
uint8_t * tr_peerHash( tr_peer_t * peer )
{
return parseBufHash( peer );
}
/***********************************************************************
* tr_peerPulse
***********************************************************************
@ -234,25 +305,6 @@ void tr_peerPulse( tr_torrent_t * tor )
{
return;
}
/* Check for incoming connections */
if( tor->bindSocket > -1 &&
tor->peerCount < TR_MAX_PEER_COUNT &&
!tr_fdSocketWillCreate( tor->fdlimit, 0 ) )
{
int s;
struct in_addr addr;
in_port_t port;
s = tr_netAccept( tor->bindSocket, &addr, &port );
if( s > -1 )
{
tr_peerAddCompact( tor, addr, port, s );
}
else
{
tr_fdSocketClosed( tor->fdlimit, 0 );
}
}
/* Shuffle peers */
if( tor->peerCount > 1 )
@ -274,36 +326,9 @@ void tr_peerPulse( tr_torrent_t * tor )
continue;
}
/* Try to read */
for( ;; )
if( tr_peerRead( tor, tor->peers[i] ) )
{
if( peer->size < 1 )
{
peer->size = 1024;
peer->buf = malloc( peer->size );
}
else if( peer->pos >= peer->size )
{
peer->size *= 2;
peer->buf = realloc( peer->buf, peer->size );
}
ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
peer->size - peer->pos );
if( ret & TR_NET_CLOSE )
{
peer_dbg( "connection closed" );
goto dropPeer;
}
else if( ret & TR_NET_BLOCK )
{
break;
}
peer->date = tr_date();
peer->pos += ret;
if( parseBuf( tor, peer, ret ) )
{
goto dropPeer;
}
goto dropPeer;
}
if( peer->status < PEER_STATUS_CONNECTED )

View file

@ -26,9 +26,13 @@
typedef struct tr_peer_s tr_peer_t;
void tr_peerAddOld ( tr_torrent_t *, char *, int );
void tr_peerAddCompact ( tr_torrent_t *, struct in_addr,
in_port_t, int );
void tr_peerAddCompact ( tr_torrent_t *, struct in_addr, in_port_t );
tr_peer_t * tr_peerInit ( struct in_addr, in_port_t, int );
void tr_peerAttach ( tr_torrent_t *, tr_peer_t * );
void tr_peerDestroy ( tr_fd_t *, tr_peer_t * );
void tr_peerRem ( tr_torrent_t *, int );
int tr_peerRead ( tr_torrent_t *, tr_peer_t * );
uint8_t * tr_peerHash ( tr_peer_t * );
void tr_peerPulse ( tr_torrent_t * );
int tr_peerIsConnected ( tr_peer_t * );
int tr_peerIsUploading ( tr_peer_t * );

View file

@ -396,6 +396,48 @@ static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
return 1;
}
static inline int parseBufHeader( tr_peer_t * peer )
{
uint8_t * p = peer->buf;
if( 4 > peer->pos )
{
return 0;
}
if( p[0] != 19 || memcmp( &p[1], "Bit", 3 ) )
{
/* Don't wait until we get 68 bytes, this is wrong
already */
peer_dbg( "GET handshake, invalid" );
tr_netSend( peer->socket, (uint8_t *) "Nice try...\r\n", 13 );
return 1;
}
if( peer->pos < 68 )
{
return 0;
}
if( memcmp( &p[4], "Torrent protocol", 16 ) )
{
peer_dbg( "GET handshake, invalid" );
return 1;
}
return 0;
}
static uint8_t * parseBufHash( tr_peer_t * peer )
{
if( 48 > peer->pos )
{
return NULL;
}
else
{
return peer->buf + 28;
}
}
static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer,
int newBytes )
{
@ -412,23 +454,8 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer,
{
char * client;
if( p[0] != 19 || memcmp( &p[1], "Bit", 3 ) )
if( parseBufHeader( peer ) )
{
/* Don't wait until we get 68 bytes, this is wrong
already */
peer_dbg( "GET handshake, invalid" );
tr_netSend( peer->socket, (uint8_t *) "Nice try...\r\n", 13 );
return 1;
}
if( peer->pos < 68 )
{
break;
}
if( memcmp( &p[4], "Torrent protocol", 16 ) )
{
peer_dbg( "GET handshake, invalid" );
return 1;
}

View file

@ -25,29 +25,40 @@ static void updateInterest( tr_torrent_t * tor, tr_peer_t * peer );
/***********************************************************************
* peerInit
***********************************************************************
* Returns NULL if we reached the maximum authorized number of peers.
* Otherwise, allocates a new tr_peer_t, add it to the peers list and
* returns a pointer to it.
* Allocates a new tr_peer_t and returns a pointer to it.
**********************************************************************/
static tr_peer_t * peerInit( tr_torrent_t * tor )
static tr_peer_t * peerInit()
{
tr_peer_t * peer;
if( tor->peerCount >= TR_MAX_PEER_COUNT )
{
return NULL;
}
peer = calloc( sizeof( tr_peer_t ), 1 );
peer->amChoking = 1;
peer->peerChoking = 1;
peer->date = tr_date();
peer->keepAlive = peer->date;
tor->peers[tor->peerCount++] = peer;
return peer;
}
/***********************************************************************
* peerAttach
***********************************************************************
* Deallocates the tr_peer_t and returns 0 if we reached the maximum
* authorized number of peers. Otherwise, adds the tr_peer_t to the
* peers list.
**********************************************************************/
static int peerAttach( tr_torrent_t * tor, tr_peer_t * peer )
{
if( tor->peerCount >= TR_MAX_PEER_COUNT )
{
tr_peerDestroy( tor->fdlimit, peer );
return 0;
}
tor->peers[tor->peerCount++] = peer;
return 1;
}
static int peerCmp( tr_peer_t * peer1, tr_peer_t * peer2 )
{
/* Wait until we got the peers' ids */
@ -83,7 +94,8 @@ static void addWithAddr( tr_torrent_t * tor, struct in_addr addr,
}
}
if( !( peer = peerInit( tor ) ) )
peer = peerInit();
if( !peerAttach( tor, peer ) )
{
return;
}

View file

@ -49,6 +49,8 @@ struct tr_tracker_s
uint8_t * buf;
int size;
int pos;
int bindPort;
};
static void sendQuery ( tr_tracker_t * tc );
@ -71,6 +73,8 @@ tr_tracker_t * tr_trackerInit( tr_handle_t * h, tr_torrent_t * tor )
tc->size = 1024;
tc->buf = malloc( tc->size );
tc->bindPort = h->bindPort;
return tc;
}
@ -117,6 +121,12 @@ static int shouldConnect( tr_tracker_t * tc )
return 0;
}
void tr_trackerChangePort( tr_tracker_t * tc, int port )
{
/* XXX this doesn't always work, should send stopped then started events */
tc->bindPort = port;
}
int tr_trackerPulse( tr_tracker_t * tc )
{
tr_torrent_t * tor = tc->tor;
@ -264,7 +274,7 @@ static void sendQuery( tr_tracker_t * tc )
"User-Agent: Transmission/%d.%d\r\n"
"Connection: close\r\n\r\n",
inf->trackerAnnounce, tor->hashString, tc->id,
tor->bindPort, tor->uploaded[9], tor->downloaded[9],
tc->bindPort, tor->uploaded[9], tor->downloaded[9],
left, tor->key, event, inf->trackerAddress,
VERSION_MAJOR, VERSION_MINOR );
@ -450,7 +460,7 @@ static void recvAnswer( tr_tracker_t * tc )
memcpy( &addr, &bePeers->val.s.s[6*i], 4 );
memcpy( &port, &bePeers->val.s.s[6*i+4], 2 );
tr_peerAddCompact( tor, addr, port, -1 );
tr_peerAddCompact( tor, addr, port );
}
if( bePeers->val.s.i / 6 >= 50 )

View file

@ -26,6 +26,7 @@
typedef struct tr_tracker_s tr_tracker_t;
tr_tracker_t * tr_trackerInit ( tr_handle_t *, tr_torrent_t * );
void tr_trackerChangePort( tr_tracker_t *, int );
int tr_trackerPulse ( tr_tracker_t * );
void tr_trackerCompleted ( tr_tracker_t * );
void tr_trackerStopped ( tr_tracker_t * );

View file

@ -29,6 +29,8 @@ static void torrentReallyStop( tr_handle_t * h, int t );
static void downloadLoop( void * );
static float rateDownload( tr_torrent_t * );
static float rateUpload( tr_torrent_t * );
static void acceptLoop( void * );
static void acceptStop( tr_handle_t * h );
/***********************************************************************
* tr_init
@ -67,6 +69,22 @@ tr_handle_t * tr_init()
h->fdlimit = tr_fdInit();
h->bindPort = TR_DEFAULT_PORT;
h->bindSocket = -1;
#ifndef BEOS_NETSERVER
/* BeOS net_server seems to be unable to set incoming connections to
non-blocking. Too bad. */
if( !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
{
/* XXX should handle failure here in a better way */
h->bindSocket = tr_netBind( h->bindPort );
}
#endif
h->acceptDie = 0;
tr_lockInit( &h->acceptLock );
tr_threadCreate( &h->acceptThread, acceptLoop, h );
return h;
}
@ -78,8 +96,46 @@ tr_handle_t * tr_init()
**********************************************************************/
void tr_setBindPort( tr_handle_t * h, int port )
{
/* FIXME multithread safety */
int ii, sock;
if( h->bindPort == port )
return;
#ifndef BEOS_NETSERVER
/* BeOS net_server seems to be unable to set incoming connections to
non-blocking. Too bad. */
if( !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
{
/* XXX should handle failure here in a better way */
sock = tr_netBind( port );
}
#else
return;
#endif
tr_lockLock( &h->acceptLock );
h->bindPort = port;
for( ii = 0; ii < h->torrentCount; ii++ )
{
tr_lockLock( &h->torrents[ii]->lock );
if( NULL != h->torrents[ii]->tracker )
{
tr_trackerChangePort( h->torrents[ii]->tracker, port );
}
tr_lockUnlock( &h->torrents[ii]->lock );
}
if( h->bindSocket > -1 )
{
tr_netClose( h->bindSocket );
tr_fdSocketClosed( h->fdlimit, 0 );
}
h->bindSocket = sock;
tr_lockUnlock( &h->acceptLock );
}
/***********************************************************************
@ -196,8 +252,10 @@ int tr_torrentInit( tr_handle_t * h, const char * path )
tor->fdlimit = h->fdlimit;
/* We have a new torrent */
tr_lockLock( &h->acceptLock );
h->torrents[h->torrentCount] = tor;
(h->torrentCount)++;
tr_lockUnlock( &h->acceptLock );
return 0;
}
@ -241,15 +299,6 @@ void tr_torrentStart( tr_handle_t * h, int t )
tor->status = TR_STATUS_CHECK;
tor->tracker = tr_trackerInit( h, tor );
tor->bindPort = h->bindPort;
#ifndef BEOS_NETSERVER
/* BeOS net_server seems to be unable to set incoming connections to
non-blocking. Too bad. */
if( !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
{
tor->bindSocket = tr_netBind( &tor->bindPort );
}
#endif
now = tr_date();
for( i = 0; i < 10; i++ )
@ -291,11 +340,6 @@ static void torrentReallyStop( tr_handle_t * h, int t )
{
tr_peerRem( tor, 0 );
}
if( tor->bindSocket > -1 )
{
tr_netClose( tor->bindSocket );
tr_fdSocketClosed( h->fdlimit, 0 );
}
memset( tor->downloaded, 0, sizeof( tor->downloaded ) );
memset( tor->uploaded, 0, sizeof( tor->uploaded ) );
@ -445,6 +489,8 @@ void tr_torrentClose( tr_handle_t * h, int t )
torrentReallyStop( h, t );
}
tr_lockLock( &h->acceptLock );
h->torrentCount--;
tr_lockClose( &tor->lock );
@ -460,10 +506,13 @@ void tr_torrentClose( tr_handle_t * h, int t )
memmove( &h->torrents[t], &h->torrents[t+1],
( h->torrentCount - t ) * sizeof( void * ) );
tr_lockUnlock( &h->acceptLock );
}
void tr_close( tr_handle_t * h )
{
acceptStop( h );
tr_fdClose( h->fdlimit );
tr_uploadClose( h->upload );
free( h );
@ -567,3 +616,119 @@ static float rateUpload( tr_torrent_t * tor )
{
return rateGeneric( tor->dates, tor->uploaded );
}
/***********************************************************************
* acceptLoop
**********************************************************************/
static void acceptLoop( void * _h )
{
tr_handle_t * h = _h;
uint64_t date1, date2;
int ii, jj;
uint8_t * hash;
tr_dbg( "Accept thread started" );
#ifdef SYS_BEOS
/* This is required because on BeOS, SIGINT is sent to each thread,
which kills them not nicely */
signal( SIGINT, SIG_IGN );
#endif
tr_lockLock( &h->acceptLock );
while( !h->acceptDie )
{
date1 = tr_date();
/* Check for incoming connections */
if( h->bindSocket > -1 &&
h->acceptPeerCount < TR_MAX_PEER_COUNT &&
!tr_fdSocketWillCreate( h->fdlimit, 0 ) )
{
int s;
struct in_addr addr;
in_port_t port;
s = tr_netAccept( h->bindSocket, &addr, &port );
if( s > -1 )
{
h->acceptPeers[h->acceptPeerCount++] = tr_peerInit( addr, port, s );
}
else
{
tr_fdSocketClosed( h->fdlimit, 0 );
}
}
for( ii = 0; ii < h->acceptPeerCount; )
{
if( tr_peerRead( NULL, h->acceptPeers[ii] ) )
{
tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
goto removePeer;
}
if( NULL != ( hash = tr_peerHash( h->acceptPeers[ii] ) ) )
{
for( jj = 0; jj < h->torrentCount; jj++ )
{
tr_lockLock( &h->torrents[jj]->lock );
if( 0 == memcmp( h->torrents[jj]->info.hash, hash,
SHA_DIGEST_LENGTH ) )
{
tr_peerAttach( h->torrents[jj], h->acceptPeers[ii] );
tr_lockUnlock( &h->torrents[jj]->lock );
goto removePeer;
}
tr_lockUnlock( &h->torrents[jj]->lock );
}
tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
goto removePeer;
}
ii++;
continue;
removePeer:
h->acceptPeerCount--;
memmove( &h->acceptPeers[ii], &h->acceptPeers[ii+1],
( h->acceptPeerCount - ii ) * sizeof( tr_peer_t * ) );
}
/* Wait up to 20 ms */
date2 = tr_date();
if( date2 < date1 + 20 )
{
tr_lockUnlock( &h->acceptLock );
tr_wait( date1 + 20 - date2 );
tr_lockLock( &h->acceptLock );
}
}
tr_lockUnlock( &h->acceptLock );
tr_dbg( "Accept thread exited" );
}
/***********************************************************************
* acceptStop
***********************************************************************
* Joins the accept thread and frees/closes everything related to it.
**********************************************************************/
static void acceptStop( tr_handle_t * h )
{
int ii;
h->acceptDie = 1;
tr_threadJoin( &h->acceptThread );
tr_lockClose( &h->acceptLock );
tr_dbg( "Accept thread joined" );
for( ii = 0; ii < h->acceptPeerCount; ii++ )
{
tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] );
}
if( h->bindSocket > -1 )
{
tr_netClose( h->bindSocket );
tr_fdSocketClosed( h->fdlimit, 0 );
}
}