source: trunk/libtransmission/shared.c @ 3121

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

fix recursive crash when stopping a torrent, reported by plantain. silence a few more console messages.

  • Property svn:keywords set to Date Rev Author Id
File size: 7.7 KB
Line 
1/******************************************************************************
2 * $Id: shared.c 3121 2007-09-21 14:20:55Z 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
173tr_sharedGetPublicPort( const tr_shared * s )
174{
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( const tr_shared * s )
198{
199    const 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.