From 7a6401c7b4ca1201841c3e98aeda03f060aba912 Mon Sep 17 00:00:00 2001 From: Eric Petit Date: Fri, 19 Jan 2007 04:42:31 +0000 Subject: [PATCH] Split transmission.c: everything related to the accept/upnp/choking thread was moved to shared.c --- Transmission.xcodeproj/project.pbxproj | 8 + cli/transmissioncli.c | 11 +- gtk/dialogs.c | 5 +- gtk/main.c | 2 +- libtransmission/internal.h | 16 +- libtransmission/metainfo.h | 2 + libtransmission/peer.h | 2 + libtransmission/shared.c | 413 +++++++++++++++++++++++++ libtransmission/shared.h | 71 +++++ libtransmission/transmission.c | 248 +-------------- libtransmission/transmission.h | 3 +- macosx/Controller.m | 2 +- macosx/PrefsController.m | 5 +- mk/lib.mk | 4 +- 14 files changed, 523 insertions(+), 269 deletions(-) create mode 100644 libtransmission/shared.c create mode 100644 libtransmission/shared.h diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 92a12de17..de34f22de 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -54,6 +54,8 @@ 4D8CEF91095870E00063BAEA /* Network.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D8CEF90095870E00063BAEA /* Network.png */; }; 4D9A2BF009E16D21002D0FF9 /* libtransmission.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D18389709DEC0030047D688 /* libtransmission.a */; }; 4D9A2BF909E16D4F002D0FF9 /* libcrypto.0.9.7.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D2617F709DECE3D00D08EFA /* libcrypto.0.9.7.dylib */; }; + 4D9A55700B607ED80086C2A4 /* shared.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D9A556E0B607ED80086C2A4 /* shared.c */; }; + 4D9A55710B607ED80086C2A4 /* shared.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D9A556F0B607ED80086C2A4 /* shared.h */; }; 4DA6FDBA0911233800450CB1 /* PauseOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDB80911233800450CB1 /* PauseOn.png */; }; 4DA6FDBB0911233800450CB1 /* PauseOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDB90911233800450CB1 /* PauseOff.png */; }; 4DA6FDC5091141AD00450CB1 /* ResumeOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDC3091141AD00450CB1 /* ResumeOff.png */; }; @@ -251,6 +253,8 @@ 4D6DAAC5090CE00500F43C22 /* RevealOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = RevealOn.png; path = macosx/Images/RevealOn.png; sourceTree = ""; }; 4D752E920913C949008EAAD4 /* Preferences.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Preferences.png; path = macosx/Images/Preferences.png; sourceTree = ""; }; 4D8CEF90095870E00063BAEA /* Network.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Network.png; path = macosx/Images/Network.png; sourceTree = ""; }; + 4D9A556E0B607ED80086C2A4 /* shared.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = shared.c; path = libtransmission/shared.c; sourceTree = ""; }; + 4D9A556F0B607ED80086C2A4 /* shared.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = shared.h; path = libtransmission/shared.h; sourceTree = ""; }; 4DA6FDB80911233800450CB1 /* PauseOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PauseOn.png; path = macosx/Images/PauseOn.png; sourceTree = ""; }; 4DA6FDB90911233800450CB1 /* PauseOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PauseOff.png; path = macosx/Images/PauseOff.png; sourceTree = ""; }; 4DA6FDC3091141AD00450CB1 /* ResumeOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeOff.png; path = macosx/Images/ResumeOff.png; sourceTree = ""; }; @@ -639,6 +643,8 @@ 4DAB87C20ABE1F730081CF7E /* natpmp.c */, 4DAB87C30ABE1F730081CF7E /* http.h */, 4DAB87C40ABE1F730081CF7E /* http.c */, + 4D9A556F0B607ED80086C2A4 /* shared.h */, + 4D9A556E0B607ED80086C2A4 /* shared.c */, ); name = libtransmission; sourceTree = ""; @@ -700,6 +706,7 @@ 4DAB87C70ABE1F730081CF7E /* upnp.h in Headers */, 4DAB87C90ABE1F730081CF7E /* natpmp.h in Headers */, 4DAB87CB0ABE1F730081CF7E /* http.h in Headers */, + 4D9A55710B607ED80086C2A4 /* shared.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -897,6 +904,7 @@ 4DAB87C80ABE1F730081CF7E /* upnp.c in Sources */, 4DAB87CA0ABE1F730081CF7E /* natpmp.c in Sources */, 4DAB87CC0ABE1F730081CF7E /* http.c in Sources */, + 4D9A55700B607ED80086C2A4 /* shared.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/cli/transmissioncli.c b/cli/transmissioncli.c index 9ee0d3358..ba4db25e0 100644 --- a/cli/transmissioncli.c +++ b/cli/transmissioncli.c @@ -176,14 +176,7 @@ int main( int argc, char ** argv ) tr_setGlobalUploadLimit( h, uploadLimit ); tr_setGlobalDownloadLimit( h, downloadLimit ); - if( natTraversal ) - { - tr_natTraversalEnable( h ); - } - else - { - tr_natTraversalDisable( h ); - } + tr_natTraversalEnable( h, natTraversal ); tr_torrentSetFolder( tor, "." ); tr_torrentStart( tor ); @@ -244,7 +237,7 @@ int main( int argc, char ** argv ) fprintf( stderr, "\n" ); /* Try for 5 seconds to delete any port mappings for nat traversal */ - tr_natTraversalDisable( h ); + tr_natTraversalEnable( h, 0 ); for( i = 0; i < 10; i++ ) { nat = tr_natTraversalStatus( h ); diff --git a/gtk/dialogs.c b/gtk/dialogs.c index 9cef6508f..774914dfc 100644 --- a/gtk/dialogs.c +++ b/gtk/dialogs.c @@ -441,10 +441,7 @@ applyprefs(TrBackend *back) { /* enable/disable NAT traversal */ boolval = (NULL == (pref = cf_getpref(PREF_NAT)) ? DEF_NAT : strbool(pref)); - if( boolval ) - tr_natTraversalEnable(tr); - else - tr_natTraversalDisable(tr); + tr_natTraversalEnable(tr, boolval); } void diff --git a/gtk/main.c b/gtk/main.c index 1bb420adc..e5bdd2153 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -517,7 +517,7 @@ winclose(GtkWidget *widget SHUTUP, GdkEvent *event SHUTUP, gpointer gdata) { tr_backend_stop_torrents(data->back); /* shut down nat traversal */ - tr_natTraversalDisable(tr_backend_handle(data->back)); + tr_natTraversalEnable(tr_backend_handle(data->back), 0); /* set things up to wait for torrents to stop */ edata = g_new0(struct exitdata, 1); diff --git a/libtransmission/internal.h b/libtransmission/internal.h index 65d9107bc..62197a125 100644 --- a/libtransmission/internal.h +++ b/libtransmission/internal.h @@ -118,6 +118,7 @@ static inline void tr_htonl( uint32_t a, uint8_t * p ) #define TR_MAX_PEER_COUNT 60 typedef struct tr_completion_s tr_completion_t; +typedef struct tr_shared_s tr_shared_t; typedef enum { TR_NET_OK, TR_NET_ERROR, TR_NET_WAIT } tr_tristate_t; @@ -201,25 +202,14 @@ struct tr_handle_s int torrentCount; tr_torrent_t * torrentList; + int bindPort; int uploadLimit; int downloadLimit; tr_fd_t * fdlimit; - tr_choking_t * choking; - tr_natpmp_t * natpmp; - tr_upnp_t * upnp; - - int bindPort; - int bindSocket; - - int acceptPeerCount; - tr_peer_t * acceptPeers[TR_MAX_PEER_COUNT]; + tr_shared_t * shared; char id[21]; char key[21]; - - volatile char acceptDie; - tr_thread_t acceptThread; - tr_lock_t acceptLock; }; #endif diff --git a/libtransmission/metainfo.h b/libtransmission/metainfo.h index f8a248d24..a7c62b8c4 100644 --- a/libtransmission/metainfo.h +++ b/libtransmission/metainfo.h @@ -25,6 +25,8 @@ #ifndef TR_METAINFO_H #define TR_METAINFO_H 1 +#include "transmission.h" + int tr_metainfoParse( tr_info_t *, const char * path, const char * savedHash, int saveCopy ); void tr_metainfoFree( tr_info_t * inf ); diff --git a/libtransmission/peer.h b/libtransmission/peer.h index e674e87e6..f048c04e5 100644 --- a/libtransmission/peer.h +++ b/libtransmission/peer.h @@ -25,6 +25,8 @@ #ifndef TR_PEER_H #define TR_PEER_H 1 +#include "transmission.h" + typedef struct tr_peer_s tr_peer_t; void tr_peerAddOld ( tr_torrent_t *, char *, int ); diff --git a/libtransmission/shared.c b/libtransmission/shared.c new file mode 100644 index 000000000..f614cd019 --- /dev/null +++ b/libtransmission/shared.c @@ -0,0 +1,413 @@ +/****************************************************************************** + * $Id$ + * + * Copyright (c) 2005-2007 Transmission authors and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#include "shared.h" +#include "peer.h" + +/* Maximum number of peers that we keep in our local list */ +#define MAX_PEER_COUNT 42 + +struct tr_shared_s +{ + tr_handle_t * h; + volatile int die; + tr_thread_t thread; + tr_lock_t lock; + + /* Incoming connections */ + int bindPort; + int bindSocket; + int peerCount; + tr_peer_t * peers[MAX_PEER_COUNT]; + + /* NAT-PMP/UPnP */ + tr_natpmp_t * natpmp; + tr_upnp_t * upnp; + + /* Choking */ + tr_choking_t * choking; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void SharedLoop( void * ); +static void AcceptPeers( tr_shared_t * ); +static void ReadPeers( tr_shared_t * ); +static void DispatchPeers( tr_shared_t * ); + + +/*********************************************************************** + * tr_sharedInit + *********************************************************************** + * + **********************************************************************/ +tr_shared_t * tr_sharedInit( tr_handle_t * h ) +{ + tr_shared_t * s = calloc( 1, sizeof( tr_shared_t ) ); + + s->h = h; + tr_lockInit( &s->lock ); + + s->bindPort = -1; + s->bindSocket = -1; + s->natpmp = tr_natpmpInit( h->fdlimit ); + s->upnp = tr_upnpInit( h->fdlimit ); + s->choking = tr_chokingInit( h ); + + /* Launch the thread */ + s->die = 0; + tr_threadCreate( &s->thread, SharedLoop, s, "shared" ); + + return s; +} + +/*********************************************************************** + * tr_sharedClose + *********************************************************************** + * + **********************************************************************/ +void tr_sharedClose( tr_shared_t * s ) +{ + tr_handle_t * h = s->h; + int ii; + + /* Stop the thread */ + s->die = 1; + tr_threadJoin( &s->thread ); + + /* Clean up */ + for( ii = 0; ii < s->peerCount; ii++ ) + { + tr_peerDestroy( h->fdlimit, s->peers[ii] ); + } + if( s->bindSocket > -1 ) + { + tr_netClose( s->bindSocket ); + tr_fdSocketClosed( h->fdlimit, 0 ); + } + tr_lockClose( &s->lock ); + tr_natpmpClose( s->natpmp ); + tr_upnpClose( s->upnp ); + tr_chokingClose( s->choking ); +} + +/*********************************************************************** + * tr_sharedLock, tr_sharedUnlock + *********************************************************************** + * + **********************************************************************/ +void tr_sharedLock( tr_shared_t * s ) +{ + tr_lockLock( &s->lock ); +} +void tr_sharedUnlock( tr_shared_t * s ) +{ + tr_lockUnlock( &s->lock ); +} + +/*********************************************************************** + * tr_sharedSetPort + *********************************************************************** + * + **********************************************************************/ +void tr_sharedSetPort( tr_shared_t * s, int port ) +{ + tr_handle_t * h = s->h; + tr_torrent_t * tor; + +#ifdef BEOS_NETSERVER + /* BeOS net_server seems to be unable to set incoming connections + * to non-blocking. Too bad. */ + return; +#endif + + tr_sharedLock( s ); + + if( port == s->bindPort ) + { + tr_sharedUnlock( s ); + return; + } + s->bindPort = port; + + /* Close the previous accept socket, if any */ + if( s->bindSocket > -1 ) + { + tr_netClose( s->bindSocket ); + tr_fdSocketClosed( h->fdlimit, 0 ); + } + + /* Create the new one */ + if( !tr_fdSocketWillCreate( h->fdlimit, 0 ) ) + { + /* XXX should handle failure here in a better way */ + s->bindSocket = tr_netBindTCP( port ); + if( 0 > s->bindSocket ) + { + tr_fdSocketClosed( h->fdlimit, 0 ); + } + else + { + tr_inf( "Bound listening port %d", port ); + listen( s->bindSocket, 5 ); + } + } + + /* Notify the trackers */ + for( tor = h->torrentList; tor; tor = tor->next ) + { + tr_lockLock( &tor->lock ); + if( NULL != tor->tracker ) + { + tr_trackerChangePort( tor->tracker, port ); + } + tr_lockUnlock( &tor->lock ); + } + + /* Forward the new port */ + tr_natpmpForwardPort( s->natpmp, port ); + tr_upnpForwardPort( s->upnp, port ); + + tr_sharedUnlock( s ); +} + +/*********************************************************************** + * tr_sharedTraversalEnable, tr_natTraversalStatus + *********************************************************************** + * + **********************************************************************/ +void tr_sharedTraversalEnable( tr_shared_t * s, int enable ) +{ + if( enable ) + { + tr_natpmpStart( s->natpmp ); + tr_upnpStart( s->upnp ); + } + else + { + tr_natpmpStop( s->natpmp ); + tr_upnpStop( s->upnp ); + } +} + +int tr_sharedTraversalStatus( tr_shared_t * s ) +{ + int statuses[] = { + TR_NAT_TRAVERSAL_MAPPED, + TR_NAT_TRAVERSAL_MAPPING, + TR_NAT_TRAVERSAL_UNMAPPING, + TR_NAT_TRAVERSAL_ERROR, + TR_NAT_TRAVERSAL_NOTFOUND, + TR_NAT_TRAVERSAL_DISABLED, + -1, + }; + int natpmp, upnp, ii; + + natpmp = tr_natpmpStatus( s->natpmp ); + upnp = tr_upnpStatus( s->upnp ); + + for( ii = 0; 0 <= statuses[ii]; ii++ ) + { + if( statuses[ii] == natpmp || statuses[ii] == upnp ) + { + return statuses[ii]; + } + } + + assert( 0 ); + + return TR_NAT_TRAVERSAL_ERROR; + +} + +/*********************************************************************** + * tr_sharedSetLimit + **********************************************************************/ +void tr_sharedSetLimit( tr_shared_t * s, int limit ) +{ + tr_chokingSetLimit( s->choking, limit ); +} + + +/*********************************************************************** + * Local functions + **********************************************************************/ + +/*********************************************************************** + * SharedLoop + **********************************************************************/ +static void SharedLoop( void * _s ) +{ + tr_shared_t * s = _s; + uint64_t date1, date2, lastchoke = 0; + + tr_sharedLock( s ); + + while( !s->die ) + { + date1 = tr_date(); + + /* NAT-PMP and UPnP pulses */ + tr_natpmpPulse( s->natpmp ); + tr_upnpPulse( s->upnp ); + + /* Handle incoming connections */ + AcceptPeers( s ); + ReadPeers( s ); + DispatchPeers( s ); + + /* Update choking every second */ + if( date1 > lastchoke + 1000 ) + { + tr_chokingPulse( s->choking ); + lastchoke = date1; + } + + /* Wait up to 20 ms */ + date2 = tr_date(); + if( date2 < date1 + 20 ) + { + tr_sharedUnlock( s ); + tr_wait( date1 + 20 - date2 ); + tr_sharedLock( s ); + } + } + + tr_sharedUnlock( s ); +} + +/*********************************************************************** + * AcceptPeers + *********************************************************************** + * Check incoming connections and add the peers to our local list + **********************************************************************/ +static void AcceptPeers( tr_shared_t * s ) +{ + tr_handle_t * h = s->h; + int socket; + in_port_t port; + struct in_addr addr; + + for( ;; ) + { + if( s->bindSocket < 0 || s->peerCount >= MAX_PEER_COUNT || + tr_fdSocketWillCreate( h->fdlimit, 0 ) ) + { + break;; + } + + socket = tr_netAccept( s->bindSocket, &addr, &port ); + if( socket < 0 ) + { + tr_fdSocketClosed( h->fdlimit, 0 ); + break; + } + s->peers[s->peerCount++] = tr_peerInit( addr, port, socket ); + } +} + +/*********************************************************************** + * ReadPeers + *********************************************************************** + * Try to read handshakes + **********************************************************************/ +static void ReadPeers( tr_shared_t * s ) +{ + tr_handle_t * h = s->h; + int ii; + + for( ii = 0; ii < s->peerCount; ) + { + if( tr_peerRead( NULL, s->peers[ii] ) ) + { + tr_peerDestroy( h->fdlimit, s->peers[ii] ); + s->peerCount--; + memmove( &s->peers[ii], &s->peers[ii+1], + ( s->peerCount - ii ) * sizeof( tr_peer_t * ) ); + continue; + } + ii++; + } +} + +/*********************************************************************** + * DispatchPeers + *********************************************************************** + * If we got a handshake, try to find the torrent for this peer + **********************************************************************/ +static void DispatchPeers( tr_shared_t * s ) +{ + tr_handle_t * h = s->h; + tr_torrent_t * tor; + uint8_t * hash; + int ii; + uint64_t now = tr_date(); + + for( ii = 0; ii < s->peerCount; ) + { + hash = tr_peerHash( s->peers[ii] ); + + if( !hash && now > tr_peerDate( s->peers[ii] ) + 10000 ) + { + /* 10 seconds and no handshake, drop it */ + tr_peerDestroy( h->fdlimit, s->peers[ii] ); + goto removePeer; + } + if( hash ) + { + for( tor = h->torrentList; tor; tor = tor->next ) + { + tr_lockLock( &tor->lock ); + if( tor->status & TR_STATUS_INACTIVE ) + { + tr_lockUnlock( &tor->lock ); + continue; + } + + if( 0 == memcmp( tor->info.hash, hash, + SHA_DIGEST_LENGTH ) ) + { + /* Found it! */ + tr_peerAttach( tor, s->peers[ii] ); + tr_lockUnlock( &tor->lock ); + goto removePeer; + } + tr_lockUnlock( &tor->lock ); + } + + /* Couldn't find a torrent, we probably removed it */ + tr_peerDestroy( h->fdlimit, s->peers[ii] ); + goto removePeer; + } + ii++; + continue; + +removePeer: + s->peerCount--; + memmove( &s->peers[ii], &s->peers[ii+1], + ( s->peerCount - ii ) * sizeof( tr_peer_t * ) ); + } +} + diff --git a/libtransmission/shared.h b/libtransmission/shared.h new file mode 100644 index 000000000..f487943b8 --- /dev/null +++ b/libtransmission/shared.h @@ -0,0 +1,71 @@ +/****************************************************************************** + * $Id$ + * + * Copyright (c) 2005-2007 Transmission authors and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + +#ifndef SHARED_H +#define SHARED_H 1 + +#include "transmission.h" + +/*********************************************************************** + * tr_sharedInit, tr_sharedClose + *********************************************************************** + * Starts / stops a thread to handle running things that are shared + * among the torrents: NAT-PMP/UPnP, incoming connections, peer choking + **********************************************************************/ +tr_shared_t * tr_sharedInit ( tr_handle_t * ); +void tr_sharedClose ( tr_shared_t * ); + +/*********************************************************************** + * tr_sharedLock, tr_sharedUnlock + *********************************************************************** + * Gets / releases exclusive access to ressources used by the shared + * thread + **********************************************************************/ +void tr_sharedLock ( tr_shared_t * ); +void tr_sharedUnlock ( tr_shared_t * ); + +/*********************************************************************** + * tr_sharedSetPort + *********************************************************************** + * Changes the port for incoming connections + **********************************************************************/ +void tr_sharedSetPort ( tr_shared_t *, int port ); + +/*********************************************************************** + * tr_sharedTraversalEnable, tr_natTraversalStatus + *********************************************************************** + * + **********************************************************************/ +void tr_sharedTraversalEnable ( tr_shared_t *, int enable ); +int tr_sharedTraversalStatus ( tr_shared_t * ); + +/*********************************************************************** + * tr_sharedSetLimit + *********************************************************************** + * + **********************************************************************/ +void tr_sharedSetLimit ( tr_shared_t *, int limit ); + +#endif + diff --git a/libtransmission/transmission.c b/libtransmission/transmission.c index 425f5039a..6fedb59bf 100644 --- a/libtransmission/transmission.c +++ b/libtransmission/transmission.c @@ -23,6 +23,7 @@ *****************************************************************************/ #include "transmission.h" +#include "shared.h" /*********************************************************************** * Local prototypes @@ -31,8 +32,6 @@ static tr_torrent_t * torrentRealInit( tr_handle_t *, tr_torrent_t * tor, int flags, int * error ); static void torrentReallyStop( tr_torrent_t * ); static void downloadLoop( void * ); -static void acceptLoop( void * ); -static void acceptStop( tr_handle_t * h ); /*********************************************************************** * tr_init @@ -73,17 +72,8 @@ tr_handle_t * tr_init() h->uploadLimit = -1; h->downloadLimit = -1; - h->fdlimit = tr_fdInit(); - h->choking = tr_chokingInit( h ); - h->natpmp = tr_natpmpInit( h->fdlimit ); - h->upnp = tr_upnpInit( h->fdlimit ); - - h->bindPort = -1; - h->bindSocket = -1; - - h->acceptDie = 0; - tr_lockInit( &h->acceptLock ); - tr_threadCreate( &h->acceptThread, acceptLoop, h, "accept" ); + h->fdlimit = tr_fdInit(); + h->shared = tr_sharedInit( h ); return h; } @@ -95,106 +85,24 @@ tr_handle_t * tr_init() **********************************************************************/ void tr_setBindPort( tr_handle_t * h, int port ) { - int sock = -1; - tr_torrent_t * tor; - - 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_netBindTCP( port ); - if( 0 > sock) - { - tr_fdSocketClosed( h->fdlimit, 0 ); - } - else - { - tr_inf( "Bound listening port %d", port ); - listen( sock, 5 ); - } - } -#else - return; -#endif - - tr_lockLock( &h->acceptLock ); - h->bindPort = port; - - for( tor = h->torrentList; tor; tor = tor->next ) - { - tr_lockLock( &tor->lock ); - if( NULL != tor->tracker ) - { - tr_trackerChangePort( tor->tracker, port ); - } - tr_lockUnlock( &tor->lock ); - } - - if( h->bindSocket > -1 ) - { - tr_netClose( h->bindSocket ); - tr_fdSocketClosed( h->fdlimit, 0 ); - } - - h->bindSocket = sock; - - tr_natpmpForwardPort( h->natpmp, port ); - tr_upnpForwardPort( h->upnp, port ); - - tr_lockUnlock( &h->acceptLock ); + tr_sharedSetPort( h->shared, port ); } -void tr_natTraversalEnable( tr_handle_t * h ) +void tr_natTraversalEnable( tr_handle_t * h, int enable ) { - tr_natpmpStart( h->natpmp ); - tr_upnpStart( h->upnp ); -} - -void tr_natTraversalDisable( tr_handle_t * h ) -{ - tr_natpmpStop( h->natpmp ); - tr_upnpStop( h->upnp ); + tr_sharedTraversalEnable( h->shared, enable ); } int tr_natTraversalStatus( tr_handle_t * h ) { - int statuses[] = { - TR_NAT_TRAVERSAL_MAPPED, - TR_NAT_TRAVERSAL_MAPPING, - TR_NAT_TRAVERSAL_UNMAPPING, - TR_NAT_TRAVERSAL_ERROR, - TR_NAT_TRAVERSAL_NOTFOUND, - TR_NAT_TRAVERSAL_DISABLED, - -1, - }; - int natpmp, upnp, ii; - - natpmp = tr_natpmpStatus( h->natpmp ); - upnp = tr_upnpStatus( h->upnp ); - - for( ii = 0; 0 <= statuses[ii]; ii++ ) - { - if( statuses[ii] == natpmp || statuses[ii] == upnp ) - { - return statuses[ii]; - } - } - - assert( 0 ); - - return TR_NAT_TRAVERSAL_ERROR; + return tr_sharedTraversalStatus( h->shared ); } void tr_setGlobalUploadLimit( tr_handle_t * h, int limit ) { h->uploadLimit = limit; - tr_chokingSetLimit( h->choking, limit ); + tr_sharedSetLimit( h->shared, limit ); } void tr_setGlobalDownloadLimit( tr_handle_t * h, int limit ) @@ -322,7 +230,7 @@ static tr_torrent_t * torrentRealInit( tr_handle_t * h, tr_torrent_t * tor, tor->swarmspeed = tr_rcInit(); /* We have a new torrent */ - tr_lockLock( &h->acceptLock ); + tr_sharedLock( h->shared ); tor->prev = NULL; tor->next = h->torrentList; if( tor->next ) @@ -331,7 +239,7 @@ static tr_torrent_t * torrentRealInit( tr_handle_t * h, tr_torrent_t * tor, } h->torrentList = tor; (h->torrentCount)++; - tr_lockUnlock( &h->acceptLock ); + tr_sharedUnlock( h->shared ); if( 0 > h->bindPort ) { @@ -709,7 +617,7 @@ void tr_torrentClose( tr_handle_t * h, tr_torrent_t * tor ) torrentReallyStop( tor ); } - tr_lockLock( &h->acceptLock ); + tr_sharedLock( h->shared ); h->torrentCount--; @@ -741,15 +649,12 @@ void tr_torrentClose( tr_handle_t * h, tr_torrent_t * tor ) } free( tor ); - tr_lockUnlock( &h->acceptLock ); + tr_sharedUnlock( h->shared ); } void tr_close( tr_handle_t * h ) { - acceptStop( h ); - tr_natpmpClose( h->natpmp ); - tr_upnpClose( h->upnp ); - tr_chokingClose( h->choking ); + tr_sharedClose( h->shared ); tr_fdClose( h->fdlimit ); free( h ); @@ -822,130 +727,3 @@ static void downloadLoop( void * _tor ) tor->status = TR_STATUS_STOPPED; } -/*********************************************************************** - * acceptLoop - **********************************************************************/ -static void acceptLoop( void * _h ) -{ - tr_handle_t * h = _h; - uint64_t date1, date2, lastchoke = 0; - int ii; - uint8_t * hash; - tr_torrent_t * tor; - - tr_lockLock( &h->acceptLock ); - - while( !h->acceptDie ) - { - date1 = tr_date(); - - /* do NAT-PMP and UPnP pulses here since there's nowhere better */ - tr_natpmpPulse( h->natpmp ); - tr_upnpPulse( h->upnp ); - - /* 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( tor = h->torrentList; tor; tor = tor->next ) - { - tr_lockLock( &tor->lock ); - if( tor->status & TR_STATUS_INACTIVE ) - { - tr_lockUnlock( &tor->lock ); - continue; - } - - if( 0 == memcmp( tor->info.hash, hash, - SHA_DIGEST_LENGTH ) ) - { - tr_peerAttach( tor, h->acceptPeers[ii] ); - tr_lockUnlock( &tor->lock ); - goto removePeer; - } - tr_lockUnlock( &tor->lock ); - } - tr_peerDestroy( h->fdlimit, h->acceptPeers[ii] ); - goto removePeer; - } - if( date1 > tr_peerDate( h->acceptPeers[ii] ) + 10000 ) - { - /* Give them 10 seconds to send the handshake */ - 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 * ) ); - } - - if( date1 > lastchoke + 2000 ) - { - tr_chokingPulse( h->choking ); - lastchoke = date1; - } - - /* 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 ); -} - -/*********************************************************************** - * 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 ); - - 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 ); - } -} diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index a606bef1a..cf19aa0c5 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -128,8 +128,7 @@ void tr_setBindPort( tr_handle_t *, int ); *********************************************************************** * Enable or disable NAT traversal using NAT-PMP or UPnP IGD. **********************************************************************/ -void tr_natTraversalEnable( tr_handle_t * ); -void tr_natTraversalDisable( tr_handle_t * ); +void tr_natTraversalEnable( tr_handle_t *, int enable ); /*********************************************************************** * tr_natTraversalStatus diff --git a/macosx/Controller.m b/macosx/Controller.m index d4ede2686..da31185f8 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -460,7 +460,7 @@ static void sleepCallBack(void * controller, io_service_t y, natural_t messageTy [fTorrents makeObjectsPerformSelector: @selector(stopTransferForQuit)]; //disable NAT traversal - tr_natTraversalDisable(fLib); + tr_natTraversalEnable(fLib, 0); //remember window states and close all windows [fDefaults setBool: [[fInfoController window] isVisible] forKey: @"InfoVisible"]; diff --git a/macosx/PrefsController.m b/macosx/PrefsController.m index 839308035..0fa862b01 100644 --- a/macosx/PrefsController.m +++ b/macosx/PrefsController.m @@ -75,8 +75,7 @@ tr_setBindPort(fHandle, bindPort); //set NAT - if ([fDefaults boolForKey: @"NatTraversal"]) - tr_natTraversalEnable(fHandle); + tr_natTraversalEnable(fHandle, [fDefaults boolForKey: @"NatTraversal"]); //actually set bandwidth limits [self applySpeedSettings: nil]; @@ -294,7 +293,7 @@ - (void) setNat: (id) sender { - [fDefaults boolForKey: @"NatTraversal"] ? tr_natTraversalEnable(fHandle) : tr_natTraversalDisable(fHandle); + tr_natTraversalEnable(fHandle, [fDefaults boolForKey: @"NatTraversal"]); [self updateNatStatus]; } diff --git a/mk/lib.mk b/mk/lib.mk index 0bb6dc56d..5810171b0 100644 --- a/mk/lib.mk +++ b/mk/lib.mk @@ -5,7 +5,9 @@ include ../mk/common.mk SRCS = transmission.c bencode.c net.c tracker.c peer.c inout.c \ metainfo.c sha1.c utils.c fdlimit.c clients.c completion.c \ - platform.c ratecontrol.c choking.c natpmp.c upnp.c http.c xml.c + platform.c ratecontrol.c choking.c natpmp.c upnp.c http.c xml.c \ + shared.c + OBJS = $(SRCS:%.c=%.o) CFLAGS += -D__TRANSMISSION__