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

Last change on this file since 9387 was 9387, checked in by charles, 13 years ago

(trunk) trunk's just been too stable lately. #2119: reload settings.json on SIGHUP

  • Property svn:keywords set to Date Rev Author Id
File size: 4.8 KB
Line 
1/*
2 * This file Copyright (C) 2008-2009 Charles Kerr <charles@transmissionbt.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 9387 2009-10-23 03:41:36Z 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 "session.h"
26#include "torrent.h"
27#include "trevent.h"
28#include "upnp.h"
29#include "utils.h"
30
31static const char *
32getKey( void ) { return _( "Port Forwarding" ); }
33
34struct tr_shared
35{
36    tr_bool               isEnabled;
37    tr_bool               isShuttingDown;
38    tr_bool               doPortCheck;
39
40    tr_port_forwarding    natpmpStatus;
41    tr_port_forwarding    upnpStatus;
42
43    tr_upnp             * upnp;
44    tr_natpmp           * natpmp;
45    tr_session          * session;
46
47    struct event        * timer;
48};
49
50/***
51****
52***/
53
54static const char*
55getNatStateStr( int state )
56{
57    switch( state )
58    {
59        case TR_PORT_MAPPING:   return _( "Starting" );
60        case TR_PORT_MAPPED:    return _( "Forwarded" );
61        case TR_PORT_UNMAPPING: return _( "Stopping" );
62        case TR_PORT_UNMAPPED:  return _( "Not forwarded" );
63        default:                return "???";
64    }
65}
66
67static void
68natPulse( tr_shared * s, tr_bool doPortCheck )
69{
70    const tr_port port = s->session->peerPort;
71    const int isEnabled = s->isEnabled && !s->isShuttingDown;
72    int oldStatus;
73    int newStatus;
74
75    if( s->natpmp == NULL )
76        s->natpmp = tr_natpmpInit( );
77    if( s->upnp == NULL )
78        s->upnp = tr_upnpInit( );
79
80    oldStatus = tr_sharedTraversalStatus( s );
81    s->natpmpStatus = tr_natpmpPulse( s->natpmp, port, isEnabled );
82    s->upnpStatus = tr_upnpPulse( s->upnp, port, isEnabled, doPortCheck );
83    newStatus = tr_sharedTraversalStatus( s );
84
85    if( newStatus != oldStatus )
86        tr_ninf( getKey( ), _( "State changed from \"%1$s\" to \"%2$s\"" ),
87                getNatStateStr( oldStatus ),
88                getNatStateStr( newStatus ) );
89}
90
91static void
92onTimer( int fd UNUSED, short what UNUSED, void * vshared )
93{
94    int sec=0, msec=0;
95    tr_shared * s = vshared;
96
97    assert( s );
98    assert( s->timer );
99
100    /* do something */
101    natPulse( s, s->doPortCheck );
102    s->doPortCheck = FALSE;
103
104    /* when to wake up again */
105    switch( tr_sharedTraversalStatus( s ) )
106    {
107        case TR_PORT_MAPPED:
108            /* if we're mapped, everything is fine... check back in 20 minutes
109             * to renew the port forwarding if it's expired */
110            s->doPortCheck = TRUE;
111            sec = 60 * 20;
112            break;
113
114        case TR_PORT_ERROR:
115            /* some kind of an error.  wait 60 seconds and retry */
116            sec = 60;
117            break;
118
119        default:
120            /* in progress.  pulse frequently. */
121            msec = 333000;
122            break;
123    }
124
125    tr_timerAdd( s->timer, sec, msec );
126}
127
128/***
129****
130***/
131
132tr_shared *
133tr_sharedInit( tr_session  * session )
134{
135    tr_shared * s = tr_new0( tr_shared, 1 );
136
137    s->session      = session;
138    s->isEnabled    = FALSE;
139    s->upnpStatus   = TR_PORT_UNMAPPED;
140    s->natpmpStatus = TR_PORT_UNMAPPED;
141
142#if 0
143    if( isEnabled )
144    {
145        s->timer = tr_new0( struct event, 1 );
146        evtimer_set( s->timer, onTimer, s );
147        tr_timerAdd( s->timer, 0, 333000 );
148    }
149#endif
150
151    return s;
152}
153
154static void
155stop_timer( tr_shared * s )
156{
157    if( s->timer != NULL )
158    {
159        evtimer_del( s->timer );
160        tr_free( s->timer );
161        s->timer = NULL;
162    }
163}
164
165static void
166stop_forwarding( tr_shared * s )
167{
168    tr_ninf( getKey( ), "%s", _( "Stopped" ) );
169    natPulse( s, FALSE );
170    tr_natpmpClose( s->natpmp );
171    s->natpmp = NULL;
172    tr_upnpClose( s->upnp );
173    s->upnp = NULL;
174    stop_timer( s );
175}
176
177void
178tr_sharedClose( tr_session * session )
179{
180    tr_shared * s = session->shared;
181
182    s->isShuttingDown = TRUE;
183    stop_forwarding( s );
184    s->session->shared = NULL;
185    tr_free( s );
186}
187
188static void
189start_timer( tr_shared * s )
190{
191    s->timer = tr_new0( struct event, 1 );
192    evtimer_set( s->timer, onTimer, s );
193    onTimer( 0, 0, s );
194}
195
196void
197tr_sharedTraversalEnable( tr_shared * s, tr_bool isEnabled )
198{
199    if(( s->isEnabled = isEnabled ))
200        start_timer( s );
201    else
202        stop_forwarding( s );
203}
204
205void
206tr_sharedPortChanged( tr_session * session )
207{
208    tr_shared * s = session->shared;
209
210    if( s->isEnabled )
211    {
212        stop_timer( s );
213        start_timer( s );
214    }
215}
216
217tr_bool
218tr_sharedTraversalIsEnabled( const tr_shared * s )
219{
220    return s->isEnabled;
221}
222
223int
224tr_sharedTraversalStatus( const tr_shared * s )
225{
226    return MAX( s->natpmpStatus, s->upnpStatus );
227}
Note: See TracBrowser for help on using the repository browser.