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

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

(trunk libT) #2982 "changing port number doesn't actually change until program restart" -- fixed in trunk for 1.90

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