source: trunk/libtransmission/port-forwarding.c @ 5913

Last change on this file since 5913 was 5913, checked in by charles, 14 years ago

sine we now have two public ports (peer and rpc), rename "publicPort" as "peerPort"

  • Property svn:keywords set to Date Rev Author Id
File size: 6.1 KB
Line 
1/******************************************************************************
2 * $Id: port-forwarding.c 5913 2008-05-23 16:18:58Z charles $
3 *
4 * Copyright (c) 2005-2008 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 <errno.h>
26#include <string.h>
27#include <stdio.h>
28
29#include <sys/types.h>
30
31#include "transmission.h"
32#include "natpmp.h"
33#include "net.h"
34#include "peer-mgr.h"
35#include "port-forwarding.h"
36#include "torrent.h"
37#include "trevent.h"
38#include "upnp.h"
39#include "utils.h"
40
41static const char * getKey( void ) { return _( "Port Forwarding" ); }
42
43struct tr_shared
44{
45    unsigned int isEnabled      : 1;
46    unsigned int isShuttingDown : 1;
47
48    tr_port_forwarding natpmpStatus;
49    tr_port_forwarding upnpStatus;
50
51    int bindPort;
52    int bindSocket;
53    int publicPort;
54
55    tr_handle * h;
56    tr_timer  * pulseTimer;
57
58    tr_upnp    * upnp;
59    tr_natpmp  * natpmp;
60};
61
62/***
63****
64***/
65
66static const char*
67getNatStateStr( int state )
68{
69    switch( state )
70    {
71        /* we're in the process of trying to set up port forwarding */
72        case TR_PORT_MAPPING:   return _( "Starting" );
73        /* we've successfully forwarded the port */
74        case TR_PORT_MAPPED:    return _( "Forwarded" );
75        /* we're cancelling the port forwarding */
76        case TR_PORT_UNMAPPING: return _( "Stopping" );
77        /* the port isn't forwarded */
78        case TR_PORT_UNMAPPED:  return _( "Not forwarded" );
79        case TR_PORT_ERROR:     return "???";
80    }
81
82    return "notfound";
83}
84
85static void
86natPulse( tr_shared * s )
87{
88    const int port = s->publicPort;
89    const int isEnabled = s->isEnabled && !s->isShuttingDown;
90    int oldStatus;
91    int newStatus;
92   
93    oldStatus = tr_sharedTraversalStatus( s );
94    s->natpmpStatus = tr_natpmpPulse( s->natpmp, port, isEnabled );
95    s->upnpStatus = tr_upnpPulse( s->upnp, port, isEnabled );
96    newStatus = tr_sharedTraversalStatus( s );
97
98    if( newStatus != oldStatus )
99        tr_ninf( getKey(), _( "State changed from \"%s\" to \"%s\"" ),
100                 getNatStateStr(oldStatus),
101                 getNatStateStr(newStatus) );
102}
103
104static void
105incomingPeersPulse( tr_shared * s )
106{
107    if( s->bindSocket >= 0 && ( s->bindPort != s->publicPort ) )
108    {
109        tr_ninf( getKey(), _( "Closing port %d" ), s->bindPort );
110        tr_netClose( s->bindSocket );
111        s->bindSocket = -1;
112    }
113
114    if( ( s->publicPort > 0 ) && ( s->bindPort != s->publicPort ) )
115    {
116        int socket;
117        errno = 0;
118        socket = tr_netBindTCP( s->publicPort );
119        if( socket >= 0 ) {
120            tr_ninf( getKey(), _( "Opened port %d to listen for incoming peer connections" ), s->publicPort );
121            s->bindPort = s->publicPort;
122            s->bindSocket = socket;
123            listen( s->bindSocket, 5 );
124        } else {
125            tr_nerr( getKey(), _( "Couldn't open port %d to listen for incoming peer connections (errno %d - %s)" ),
126                     s->publicPort, errno, tr_strerror(errno) );
127            s->bindPort = -1;
128            s->bindSocket = -1;
129        }
130    }
131   
132    for( ;; ) /* check for new incoming peer connections */   
133    {
134        int socket;
135        uint16_t port;
136        struct in_addr addr;
137
138        if( s->bindSocket < 0 )
139            break;
140
141        socket = tr_netAccept( s->bindSocket, &addr, &port );
142        if( socket < 0 )
143            break;
144
145        tr_peerMgrAddIncoming( s->h->peerMgr, &addr, port, socket );
146    }
147}
148
149static int
150sharedPulse( void * vshared )
151{
152    int keepPulsing = 1;
153    tr_shared * shared = vshared;
154
155    natPulse( shared );
156
157    if( !shared->isShuttingDown )
158    {
159        incomingPeersPulse( shared );
160    }
161    else
162    {
163        tr_ninf( getKey(), _( "Stopped" ) );
164        tr_timerFree( &shared->pulseTimer );
165        tr_netClose( shared->bindSocket );
166        tr_natpmpClose( shared->natpmp );
167        tr_upnpClose( shared->upnp );
168        shared->h->shared = NULL;
169        tr_free( shared );
170        keepPulsing = 0;
171    }
172
173    return keepPulsing;
174}
175
176/***
177****
178***/
179
180tr_shared *
181tr_sharedInit( tr_handle * h, int isEnabled, int publicPort )
182{
183    tr_shared * s = tr_new0( tr_shared, 1 );
184
185    s->h            = h;
186    s->publicPort   = publicPort;
187    s->bindPort     = -1;
188    s->bindSocket   = -1;
189    s->natpmp       = tr_natpmpInit();
190    s->upnp         = tr_upnpInit();
191    s->pulseTimer   = tr_timerNew( h, sharedPulse, s, 1000 );
192    s->isEnabled    = isEnabled ? 1 : 0;
193    s->upnpStatus   = TR_PORT_UNMAPPED;
194    s->natpmpStatus = TR_PORT_UNMAPPED;
195
196    return s;
197}
198
199void
200tr_sharedShuttingDown( tr_shared * s )
201{
202    s->isShuttingDown = 1;
203}
204
205void
206tr_sharedSetPort( tr_shared * s, int port )
207{
208    tr_torrent * tor = NULL;
209
210    s->publicPort = port;
211
212    while(( tor = tr_torrentNext( s->h, tor )))
213        tr_torrentChangeMyPort( tor );
214}
215
216int
217tr_sharedGetPeerPort( const tr_shared * s )
218{
219    return s->publicPort;
220}
221
222void
223tr_sharedTraversalEnable( tr_shared * s, int isEnabled )
224{
225    s->isEnabled = isEnabled;
226}
227
228int
229tr_sharedTraversalIsEnabled( const tr_shared * s )
230{
231    return s->isEnabled;
232}
233
234int
235tr_sharedTraversalStatus( const tr_shared * s )
236{
237    return MAX( s->natpmpStatus, s->upnpStatus );
238}
Note: See TracBrowser for help on using the repository browser.