source: trunk/libtransmission/shared.c @ 3254

Last change on this file since 3254 was 3254, checked in by charles, 15 years ago

simplify libT locks now that it's (more-or-less) single-threaded. fix deadlocks. make tr_locks nestable.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.5 KB
Line 
1/******************************************************************************
2 * $Id: shared.c 3254 2007-10-01 15:17:15Z charles $
3 *
4 * Copyright (c) 2005-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdio.h>
29
30#include <sys/types.h>
31
32#include "transmission.h"
33#include "handshake.h"
34#include "natpmp.h"
35#include "net.h"
36#include "peer-io.h"
37#include "peer-mgr.h"
38#include "platform.h"
39#include "shared.h"
40#include "trevent.h"
41#include "upnp.h"
42#include "utils.h"
43
44struct tr_shared
45{
46    tr_handle    * h;
47    tr_timer     * pulseTimer;
48
49    /* Incoming connections */
50    int publicPort;
51    int bindPort;
52    int bindSocket;
53
54    /* NAT-PMP/UPnP */
55    tr_natpmp_t  * natpmp;
56    tr_upnp_t    * upnp;
57};
58
59/***********************************************************************
60 * Local prototypes
61 **********************************************************************/
62static int SharedLoop( void * );
63static void SetPublicPort( tr_shared *, int );
64static void AcceptPeers( tr_shared * );
65
66
67/***********************************************************************
68 * tr_sharedInit
69 ***********************************************************************
70 *
71 **********************************************************************/
72tr_shared * tr_sharedInit( tr_handle * h )
73{
74    tr_shared * s = calloc( 1, sizeof( tr_shared ) );
75
76    s->h          = h;
77    s->publicPort = -1;
78    s->bindPort   = -1;
79    s->bindSocket = -1;
80    s->natpmp     = tr_natpmpInit();
81    s->upnp       = tr_upnpInit();
82    s->pulseTimer   = tr_timerNew( h, SharedLoop, s, 250 );
83
84    return s;
85}
86
87/***********************************************************************
88 * tr_sharedClose
89 ***********************************************************************
90 *
91 **********************************************************************/
92void tr_sharedClose( tr_shared * s )
93{
94    tr_timerFree( &s->pulseTimer );
95
96    tr_netClose( s->bindSocket );
97    tr_natpmpClose( s->natpmp );
98    tr_upnpClose( s->upnp );
99    free( s );
100}
101
102/***********************************************************************
103 * tr_sharedSetPort
104 ***********************************************************************
105 *
106 **********************************************************************/
107void tr_sharedSetPort( tr_shared * s, int port )
108{
109#ifdef BEOS_NETSERVER
110    /* BeOS net_server seems to be unable to set incoming connections
111     * to non-blocking. Too bad. */
112    return;
113#endif
114
115    tr_globalLock( s->h );
116
117    if( port == s->bindPort )
118    {
119        tr_globalUnlock( s->h );
120        return;
121    }
122    s->bindPort = port;
123
124    /* Close the previous accept socket, if any */
125    if( s->bindSocket > -1 )
126    {
127        tr_netClose( s->bindSocket );
128    }
129
130    /* Create the new one */
131    s->bindSocket = tr_netBindTCP( port );
132
133    /* Notify the trackers */
134    SetPublicPort( s, port );
135
136    /* XXX should handle failure here in a better way */
137    if( s->bindSocket < 0 )
138    {
139        /* Remove the forwarding for the old port */
140        tr_natpmpRemoveForwarding( s->natpmp );
141        tr_upnpRemoveForwarding( s->upnp );
142    }
143    else
144    {
145        tr_inf( "Bound listening port %d", port );
146        listen( s->bindSocket, 5 );
147        /* Forward the new port */
148        tr_natpmpForwardPort( s->natpmp, port );
149        tr_upnpForwardPort( s->upnp, port );
150    }
151
152    tr_globalUnlock( s->h );
153}
154
155int
156tr_sharedGetPublicPort( const tr_shared * s )
157{
158    return s->publicPort;
159}
160
161/***********************************************************************
162 * tr_sharedTraversalEnable, tr_sharedTraversalStatus
163 ***********************************************************************
164 *
165 **********************************************************************/
166void tr_sharedTraversalEnable( tr_shared * s, int enable )
167{
168    if( enable )
169    {
170        tr_natpmpStart( s->natpmp );
171        tr_upnpStart( s->upnp );
172    }
173    else
174    {
175        tr_natpmpStop( s->natpmp );
176        tr_upnpStop( s->upnp );
177    }
178}
179
180int tr_sharedTraversalStatus( const tr_shared * s )
181{
182    const int statuses[] = {
183        TR_NAT_TRAVERSAL_MAPPED,
184        TR_NAT_TRAVERSAL_MAPPING,
185        TR_NAT_TRAVERSAL_UNMAPPING,
186        TR_NAT_TRAVERSAL_ERROR,
187        TR_NAT_TRAVERSAL_NOTFOUND,
188        TR_NAT_TRAVERSAL_DISABLED,
189        -1,
190    };
191    int natpmp, upnp, ii;
192
193    natpmp = tr_natpmpStatus( s->natpmp );
194    upnp = tr_upnpStatus( s->upnp );
195
196    for( ii = 0; 0 <= statuses[ii]; ii++ )
197    {
198        if( statuses[ii] == natpmp || statuses[ii] == upnp )
199        {
200            return statuses[ii];
201        }
202    }
203
204    assert( 0 );
205
206    return TR_NAT_TRAVERSAL_ERROR;
207
208}
209
210
211/***********************************************************************
212 * Local functions
213 **********************************************************************/
214
215/***********************************************************************
216 * SharedLoop
217 **********************************************************************/
218static int
219SharedLoop( void * vs )
220{
221    int newPort;
222    tr_shared * s = vs;
223
224    tr_globalLock( s->h );
225
226    /* NAT-PMP and UPnP pulses */
227    newPort = -1;
228    tr_natpmpPulse( s->natpmp, &newPort );
229    if( 0 < newPort && newPort != s->publicPort )
230        SetPublicPort( s, newPort );
231    tr_upnpPulse( s->upnp );
232
233    /* Handle incoming connections */
234    AcceptPeers( s );
235
236    tr_globalUnlock( s->h );
237
238    return TRUE;
239}
240
241/***********************************************************************
242 * SetPublicPort
243 **********************************************************************/
244static void SetPublicPort( tr_shared * s, int port )
245{
246    tr_handle * h = s->h;
247    tr_torrent * tor;
248
249    s->publicPort = port;
250
251    for( tor = h->torrentList; tor; tor = tor->next )
252        tr_torrentChangeMyPort( tor );
253}
254
255/***********************************************************************
256 * AcceptPeers
257 ***********************************************************************
258 * Check incoming connections and add the peers to our local list
259 **********************************************************************/
260
261static void
262AcceptPeers( tr_shared * s )
263{
264    for( ;; )
265    {
266        int socket;
267        uint16_t port;
268        struct in_addr addr;
269
270        if( s->bindSocket < 0 || !tr_peerMgrIsAcceptingConnections( s->h->peerMgr ) )
271            break;
272
273        socket = tr_netAccept( s->bindSocket, &addr, &port );
274        if( socket < 0 )
275            break;
276
277        tr_peerMgrAddIncoming( s->h->peerMgr, &addr, port, socket );
278    }
279}
Note: See TracBrowser for help on using the repository browser.