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

Last change on this file since 7392 was 7392, checked in by charles, 12 years ago

(trunk libT) fix type error reported by JhuJhiti?

  • Property svn:keywords set to Date Rev Author Id
File size: 6.2 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: port-forwarding.c 7392 2008-12-14 22:48:11Z charles $
11 */
12
13#include <errno.h>
14#include <string.h>
15#include <stdio.h>
16
17#include <sys/types.h>
18
19#include "transmission.h"
20#include "natpmp.h"
21#include "net.h"
22#include "peer-io.h"
23#include "peer-mgr.h"
24#include "port-forwarding.h"
25#include "torrent.h"
26#include "trevent.h"
27#include "upnp.h"
28#include "utils.h"
29
30static const char *
31getKey( void ) { return _( "Port Forwarding" ); }
32
33struct tr_shared
34{
35    tr_bool               isEnabled;
36    tr_bool               isShuttingDown;
37
38    tr_port_forwarding    natpmpStatus;
39    tr_port_forwarding    upnpStatus;
40
41    int                   bindPort;
42    int                   bindSocket;
43    int                   publicPort;
44
45    tr_timer            * pulseTimer;
46
47    tr_upnp             * upnp;
48    tr_natpmp           * natpmp;
49    tr_session          * session;
50};
51
52/***
53****
54***/
55
56static const char*
57getNatStateStr( int state )
58{
59    switch( state )
60    {
61        /* we're in the process of trying to set up port forwarding */
62        case TR_PORT_MAPPING:
63            return _( "Starting" );
64
65        /* we've successfully forwarded the port */
66        case TR_PORT_MAPPED:
67            return _( "Forwarded" );
68
69        /* we're cancelling the port forwarding */
70        case TR_PORT_UNMAPPING:
71            return _( "Stopping" );
72
73        /* the port isn't forwarded */
74        case TR_PORT_UNMAPPED:
75            return _( "Not forwarded" );
76
77        case TR_PORT_ERROR:
78            return "???";
79    }
80
81    return "notfound";
82}
83
84static void
85natPulse( tr_shared * s )
86{
87    const int port = s->publicPort;
88    const int isEnabled = s->isEnabled && !s->isShuttingDown;
89    int       oldStatus;
90    int       newStatus;
91
92    oldStatus = tr_sharedTraversalStatus( s );
93    s->natpmpStatus = tr_natpmpPulse( s->natpmp, port, isEnabled );
94    s->upnpStatus = tr_upnpPulse( s->upnp, port, isEnabled );
95    newStatus = tr_sharedTraversalStatus( s );
96
97    if( newStatus != oldStatus )
98        tr_ninf( getKey( ), _( "State changed from \"%1$s\" to \"%2$s\"" ),
99                getNatStateStr( oldStatus ),
100                getNatStateStr( newStatus ) );
101}
102
103static void
104incomingPeersPulse( tr_shared * s )
105{
106    tr_bool allPaused;
107    tr_torrent * tor;
108
109    if( s->bindSocket >= 0 && ( s->bindPort != s->publicPort ) )
110    {
111        tr_ninf( getKey( ), _( "Closing port %d" ), s->bindPort );
112        tr_netClose( s->bindSocket );
113        s->bindSocket = -1;
114    }
115
116    if( ( s->publicPort > 0 ) && ( s->bindPort != s->publicPort ) )
117    {
118        int socket;
119        errno = 0;
120        socket = tr_netBindTCP( &tr_inaddr_any, s->publicPort );
121        if( socket >= 0 )
122        {
123            tr_ninf( getKey( ),
124                     _(
125                         "Opened port %d to listen for incoming peer connections" ),
126                     s->publicPort );
127            s->bindPort = s->publicPort;
128            s->bindSocket = socket;
129            listen( s->bindSocket, 5 );
130        }
131        else
132        {
133            tr_nerr( getKey( ),
134                    _(
135                        "Couldn't open port %d to listen for incoming peer connections (errno %d - %s)" ),
136                    s->publicPort, errno, tr_strerror( errno ) );
137            s->bindPort = -1;
138            s->bindSocket = -1;
139        }
140    }
141
142    /* see if any torrents aren't paused */ 
143    allPaused = 1; 
144    tor = NULL; 
145    while(( tor = tr_torrentNext( s->session, tor ))) { 
146        if( TR_STATUS_IS_ACTIVE( tr_torrentGetActivity( tor ))) { 
147            allPaused = 0; 
148            break; 
149        } 
150    } 
151
152    /* if we have any running torrents, check for new incoming peer connections */ 
153    while( !allPaused ) 
154    {
155        int         socket;
156        tr_port     port;
157        tr_address  addr;
158
159        if( s->bindSocket < 0 )
160            break;
161
162        socket = tr_netAccept( s->session, s->bindSocket, &addr, &port );
163        if( socket < 0 )
164            break;
165
166        tr_deepLog( __FILE__, __LINE__, NULL,
167                   "New INCOMING connection %d (%s)",
168                   socket, tr_peerIoAddrStr( &addr, port ) );
169
170        tr_peerMgrAddIncoming( s->session->peerMgr, &addr, port, socket );
171    }
172}
173
174static int
175sharedPulse( void * vshared )
176{
177    tr_bool keepPulsing = 1;
178    tr_shared * shared = vshared;
179
180    natPulse( shared );
181
182    if( !shared->isShuttingDown )
183    {
184        incomingPeersPulse( shared );
185    }
186    else
187    {
188        tr_ninf( getKey( ), _( "Stopped" ) );
189        tr_timerFree( &shared->pulseTimer );
190        tr_netClose( shared->bindSocket );
191        tr_natpmpClose( shared->natpmp );
192        tr_upnpClose( shared->upnp );
193        shared->session->shared = NULL;
194        tr_free( shared );
195        keepPulsing = 0;
196    }
197
198    return keepPulsing;
199}
200
201/***
202****
203***/
204
205tr_shared *
206tr_sharedInit( tr_session  * session,
207               tr_bool       isEnabled,
208               tr_port       publicPort )
209{
210    tr_shared * s = tr_new0( tr_shared, 1 );
211
212    s->session      = session;
213    s->publicPort   = publicPort;
214    s->bindPort     = -1;
215    s->bindSocket   = -1;
216    s->natpmp       = tr_natpmpInit( );
217    s->upnp         = tr_upnpInit( );
218    s->pulseTimer   = tr_timerNew( session, sharedPulse, s, 1000 );
219    s->isEnabled    = isEnabled;
220    s->upnpStatus   = TR_PORT_UNMAPPED;
221    s->natpmpStatus = TR_PORT_UNMAPPED;
222
223    return s;
224}
225
226void
227tr_sharedShuttingDown( tr_shared * s )
228{
229    s->isShuttingDown = 1;
230}
231
232void
233tr_sharedSetPort( tr_shared * s, tr_port  port )
234{
235    tr_torrent * tor = NULL;
236
237    s->publicPort = port;
238
239    while( ( tor = tr_torrentNext( s->session, tor ) ) )
240        tr_torrentChangeMyPort( tor );
241}
242
243tr_port
244tr_sharedGetPeerPort( const tr_shared * s )
245{
246    return s->publicPort;
247}
248
249void
250tr_sharedTraversalEnable( tr_shared * s, tr_bool isEnabled )
251{
252    s->isEnabled = isEnabled;
253}
254
255tr_bool
256tr_sharedTraversalIsEnabled( const tr_shared * s )
257{
258    return s->isEnabled;
259}
260
261int
262tr_sharedTraversalStatus( const tr_shared * s )
263{
264    return MAX( s->natpmpStatus, s->upnpStatus );
265}
266
Note: See TracBrowser for help on using the repository browser.