source: trunk/libtransmission/shared.c @ 3119

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

slightly less broken handling of cases where we can't bind to our listening port.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.8 KB
Line 
1/******************************************************************************
2 * $Id: shared.c 3119 2007-09-21 05:31:29Z 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_lock      * lock;
48    tr_timer     * pulseTimer;
49
50    /* Incoming connections */
51    int publicPort;
52    int bindPort;
53    int bindSocket;
54
55    /* NAT-PMP/UPnP */
56    tr_natpmp_t  * natpmp;
57    tr_upnp_t    * upnp;
58};
59
60/***********************************************************************
61 * Local prototypes
62 **********************************************************************/
63static int SharedLoop( void * );
64static void SetPublicPort( tr_shared *, int );
65static void AcceptPeers( tr_shared * );
66
67
68/***********************************************************************
69 * tr_sharedInit
70 ***********************************************************************
71 *
72 **********************************************************************/
73tr_shared * tr_sharedInit( tr_handle * h )
74{
75    tr_shared * s = calloc( 1, sizeof( tr_shared ) );
76
77    s->h          = h;
78    s->lock       = tr_lockNew( );
79    s->publicPort = -1;
80    s->bindPort   = -1;
81    s->bindSocket = -1;
82    s->natpmp     = tr_natpmpInit();
83    s->upnp       = tr_upnpInit();
84    s->pulseTimer   = tr_timerNew( h, SharedLoop, s, 250 );
85
86    return s;
87}
88
89/***********************************************************************
90 * tr_sharedClose
91 ***********************************************************************
92 *
93 **********************************************************************/
94void tr_sharedClose( tr_shared * s )
95{
96fprintf( stderr, "deleting pulse tag\n" );
97    tr_timerFree( &s->pulseTimer );
98
99    tr_netClose( s->bindSocket );
100    tr_lockFree( s->lock );
101    tr_natpmpClose( s->natpmp );
102    tr_upnpClose( s->upnp );
103    free( s );
104}
105
106/**
107***
108**/
109
110void tr_sharedLock( tr_shared * s )
111{
112    tr_lockLock( s->lock );
113}
114void tr_sharedUnlock( tr_shared * s )
115{
116    tr_lockUnlock( s->lock );
117}
118
119/***********************************************************************
120 * tr_sharedSetPort
121 ***********************************************************************
122 *
123 **********************************************************************/
124void tr_sharedSetPort( tr_shared * s, int port )
125{
126#ifdef BEOS_NETSERVER
127    /* BeOS net_server seems to be unable to set incoming connections
128     * to non-blocking. Too bad. */
129    return;
130#endif
131
132    tr_sharedLock( s );
133
134    if( port == s->bindPort )
135    {
136        tr_sharedUnlock( s );
137        return;
138    }
139    s->bindPort = port;
140
141    /* Close the previous accept socket, if any */
142    if( s->bindSocket > -1 )
143    {
144        tr_netClose( s->bindSocket );
145    }
146
147    /* Create the new one */
148    s->bindSocket = tr_netBindTCP( port );
149
150    /* Notify the trackers */
151    SetPublicPort( s, port );
152
153    /* XXX should handle failure here in a better way */
154    if( s->bindSocket < 0 )
155    {
156        /* Remove the forwarding for the old port */
157        tr_natpmpRemoveForwarding( s->natpmp );
158        tr_upnpRemoveForwarding( s->upnp );
159    }
160    else
161    {
162        tr_inf( "Bound listening port %d", port );
163        listen( s->bindSocket, 5 );
164        /* Forward the new port */
165        tr_natpmpForwardPort( s->natpmp, port );
166        tr_upnpForwardPort( s->upnp, port );
167    }
168
169    tr_sharedUnlock( s );
170}
171
172int tr_sharedGetPublicPort( tr_shared * s )
173{
174fprintf( stderr, "%s:%d tr_sharedGetPublicPort returning %d\n", __FILE__, __LINE__, (int)s->publicPort );
175    return s->publicPort;
176}
177
178/***********************************************************************
179 * tr_sharedTraversalEnable, tr_sharedTraversalStatus
180 ***********************************************************************
181 *
182 **********************************************************************/
183void tr_sharedTraversalEnable( tr_shared * s, int enable )
184{
185    if( enable )
186    {
187        tr_natpmpStart( s->natpmp );
188        tr_upnpStart( s->upnp );
189    }
190    else
191    {
192        tr_natpmpStop( s->natpmp );
193        tr_upnpStop( s->upnp );
194    }
195}
196
197int tr_sharedTraversalStatus( tr_shared * s )
198{
199    int statuses[] = {
200        TR_NAT_TRAVERSAL_MAPPED,
201        TR_NAT_TRAVERSAL_MAPPING,
202        TR_NAT_TRAVERSAL_UNMAPPING,
203        TR_NAT_TRAVERSAL_ERROR,
204        TR_NAT_TRAVERSAL_NOTFOUND,
205        TR_NAT_TRAVERSAL_DISABLED,
206        -1,
207    };
208    int natpmp, upnp, ii;
209
210    natpmp = tr_natpmpStatus( s->natpmp );
211    upnp = tr_upnpStatus( s->upnp );
212
213    for( ii = 0; 0 <= statuses[ii]; ii++ )
214    {
215        if( statuses[ii] == natpmp || statuses[ii] == upnp )
216        {
217            return statuses[ii];
218        }
219    }
220
221    assert( 0 );
222
223    return TR_NAT_TRAVERSAL_ERROR;
224
225}
226
227
228/***********************************************************************
229 * Local functions
230 **********************************************************************/
231
232/***********************************************************************
233 * SharedLoop
234 **********************************************************************/
235static int
236SharedLoop( void * vs )
237{
238    int newPort;
239    tr_shared * s = vs;
240
241    tr_sharedLock( s );
242
243    /* NAT-PMP and UPnP pulses */
244    newPort = -1;
245    tr_natpmpPulse( s->natpmp, &newPort );
246    if( 0 < newPort && newPort != s->publicPort )
247        SetPublicPort( s, newPort );
248    tr_upnpPulse( s->upnp );
249
250    /* Handle incoming connections */
251    AcceptPeers( s );
252
253    tr_sharedUnlock( s );
254
255    return TRUE;
256}
257
258/***********************************************************************
259 * SetPublicPort
260 **********************************************************************/
261static void SetPublicPort( tr_shared * s, int port )
262{
263    tr_handle * h = s->h;
264    tr_torrent * tor;
265
266    s->publicPort = port;
267
268    for( tor = h->torrentList; tor; tor = tor->next )
269        tr_torrentChangeMyPort( tor );
270}
271
272/***********************************************************************
273 * AcceptPeers
274 ***********************************************************************
275 * Check incoming connections and add the peers to our local list
276 **********************************************************************/
277
278static void
279AcceptPeers( tr_shared * s )
280{
281    for( ;; )
282    {
283        int socket;
284        struct in_addr addr;
285
286        if( s->bindSocket < 0 || !tr_peerMgrIsAcceptingConnections( s->h->peerMgr ) )
287            break;
288
289        socket = tr_netAccept( s->bindSocket, &addr, NULL );
290        if( socket < 0 )
291            break;
292
293        tr_peerMgrAddIncoming( s->h->peerMgr, &addr, socket );
294    }
295}
Note: See TracBrowser for help on using the repository browser.