source: trunk/libtransmission/shared.c @ 3171

Last change on this file since 3171 was 3171, checked in by charles, 15 years ago
  • record the ports of incoming sockets. we might need them later if we want to disconnect and reconnect.
  • for portability, use libevent API for some socket upkeep
  • Property svn:keywords set to Date Rev Author Id
File size: 7.7 KB
Line 
1/******************************************************************************
2 * $Id: shared.c 3171 2007-09-25 23:10:34Z 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{
96    tr_timerFree( &s->pulseTimer );
97
98    tr_netClose( s->bindSocket );
99    tr_lockFree( s->lock );
100    tr_natpmpClose( s->natpmp );
101    tr_upnpClose( s->upnp );
102    free( s );
103}
104
105/**
106***
107**/
108
109void tr_sharedLock( tr_shared * s )
110{
111    tr_lockLock( s->lock );
112}
113void tr_sharedUnlock( tr_shared * s )
114{
115    tr_lockUnlock( s->lock );
116}
117
118/***********************************************************************
119 * tr_sharedSetPort
120 ***********************************************************************
121 *
122 **********************************************************************/
123void tr_sharedSetPort( tr_shared * s, int port )
124{
125#ifdef BEOS_NETSERVER
126    /* BeOS net_server seems to be unable to set incoming connections
127     * to non-blocking. Too bad. */
128    return;
129#endif
130
131    tr_sharedLock( s );
132
133    if( port == s->bindPort )
134    {
135        tr_sharedUnlock( s );
136        return;
137    }
138    s->bindPort = port;
139
140    /* Close the previous accept socket, if any */
141    if( s->bindSocket > -1 )
142    {
143        tr_netClose( s->bindSocket );
144    }
145
146    /* Create the new one */
147    s->bindSocket = tr_netBindTCP( port );
148
149    /* Notify the trackers */
150    SetPublicPort( s, port );
151
152    /* XXX should handle failure here in a better way */
153    if( s->bindSocket < 0 )
154    {
155        /* Remove the forwarding for the old port */
156        tr_natpmpRemoveForwarding( s->natpmp );
157        tr_upnpRemoveForwarding( s->upnp );
158    }
159    else
160    {
161        tr_inf( "Bound listening port %d", port );
162        listen( s->bindSocket, 5 );
163        /* Forward the new port */
164        tr_natpmpForwardPort( s->natpmp, port );
165        tr_upnpForwardPort( s->upnp, port );
166    }
167
168    tr_sharedUnlock( s );
169}
170
171int
172tr_sharedGetPublicPort( const tr_shared * s )
173{
174    return s->publicPort;
175}
176
177/***********************************************************************
178 * tr_sharedTraversalEnable, tr_sharedTraversalStatus
179 ***********************************************************************
180 *
181 **********************************************************************/
182void tr_sharedTraversalEnable( tr_shared * s, int enable )
183{
184    if( enable )
185    {
186        tr_natpmpStart( s->natpmp );
187        tr_upnpStart( s->upnp );
188    }
189    else
190    {
191        tr_natpmpStop( s->natpmp );
192        tr_upnpStop( s->upnp );
193    }
194}
195
196int tr_sharedTraversalStatus( const tr_shared * s )
197{
198    const int statuses[] = {
199        TR_NAT_TRAVERSAL_MAPPED,
200        TR_NAT_TRAVERSAL_MAPPING,
201        TR_NAT_TRAVERSAL_UNMAPPING,
202        TR_NAT_TRAVERSAL_ERROR,
203        TR_NAT_TRAVERSAL_NOTFOUND,
204        TR_NAT_TRAVERSAL_DISABLED,
205        -1,
206    };
207    int natpmp, upnp, ii;
208
209    natpmp = tr_natpmpStatus( s->natpmp );
210    upnp = tr_upnpStatus( s->upnp );
211
212    for( ii = 0; 0 <= statuses[ii]; ii++ )
213    {
214        if( statuses[ii] == natpmp || statuses[ii] == upnp )
215        {
216            return statuses[ii];
217        }
218    }
219
220    assert( 0 );
221
222    return TR_NAT_TRAVERSAL_ERROR;
223
224}
225
226
227/***********************************************************************
228 * Local functions
229 **********************************************************************/
230
231/***********************************************************************
232 * SharedLoop
233 **********************************************************************/
234static int
235SharedLoop( void * vs )
236{
237    int newPort;
238    tr_shared * s = vs;
239
240    tr_sharedLock( s );
241
242    /* NAT-PMP and UPnP pulses */
243    newPort = -1;
244    tr_natpmpPulse( s->natpmp, &newPort );
245    if( 0 < newPort && newPort != s->publicPort )
246        SetPublicPort( s, newPort );
247    tr_upnpPulse( s->upnp );
248
249    /* Handle incoming connections */
250    AcceptPeers( s );
251
252    tr_sharedUnlock( s );
253
254    return TRUE;
255}
256
257/***********************************************************************
258 * SetPublicPort
259 **********************************************************************/
260static void SetPublicPort( tr_shared * s, int port )
261{
262    tr_handle * h = s->h;
263    tr_torrent * tor;
264
265    s->publicPort = port;
266
267    for( tor = h->torrentList; tor; tor = tor->next )
268        tr_torrentChangeMyPort( tor );
269}
270
271/***********************************************************************
272 * AcceptPeers
273 ***********************************************************************
274 * Check incoming connections and add the peers to our local list
275 **********************************************************************/
276
277static void
278AcceptPeers( tr_shared * s )
279{
280    for( ;; )
281    {
282        int socket;
283        uint16_t port;
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, &port );
290        if( socket < 0 )
291            break;
292
293        tr_peerMgrAddIncoming( s->h->peerMgr, &addr, port, socket );
294    }
295}
Note: See TracBrowser for help on using the repository browser.