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

Last change on this file since 12223 was 12223, checked in by jordan, 11 years ago

(trunk) copyediting: remove some unneeded #includes, and annotate some needed ones

  • Property svn:keywords set to Date Rev Author Id
File size: 5.2 KB
Line 
1/*
2 * This file Copyright (C) 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 12223 2011-03-24 21:49:42Z jordan $
11 */
12
13#include <assert.h>
14#include <stdio.h>
15
16#include <sys/types.h>
17
18#include <event2/event.h>
19
20#include "transmission.h"
21#include "natpmp.h"
22#include "net.h"
23#include "peer-io.h"
24#include "peer-mgr.h"
25#include "port-forwarding.h"
26#include "session.h"
27#include "torrent.h"
28#include "upnp.h"
29#include "utils.h"
30
31static const char *
32getKey( void ) { return _( "Port Forwarding" ); }
33
34struct tr_shared
35{
36    bool               isEnabled;
37    bool               isShuttingDown;
38    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, bool do_check )
69{
70    const tr_port private_peer_port = s->session->private_peer_port;
71    const int is_enabled = s->isEnabled && !s->isShuttingDown;
72    tr_port public_peer_port;
73    int oldStatus;
74    int newStatus;
75
76    if( s->natpmp == NULL )
77        s->natpmp = tr_natpmpInit( );
78    if( s->upnp == NULL )
79        s->upnp = tr_upnpInit( );
80
81    oldStatus = tr_sharedTraversalStatus( s );
82
83    s->natpmpStatus = tr_natpmpPulse( s->natpmp, private_peer_port, is_enabled, &public_peer_port );
84    if( s->natpmpStatus == TR_PORT_MAPPED )
85        s->session->public_peer_port = public_peer_port;
86
87    s->upnpStatus = tr_upnpPulse( s->upnp, private_peer_port, is_enabled, do_check );
88
89    newStatus = tr_sharedTraversalStatus( s );
90
91    if( newStatus != oldStatus )
92        tr_ninf( getKey( ), _( "State changed from \"%1$s\" to \"%2$s\"" ),
93                getNatStateStr( oldStatus ),
94                getNatStateStr( newStatus ) );
95}
96
97static void
98set_evtimer_from_status( tr_shared * s )
99{
100    int sec=0, msec=0;
101
102    /* when to wake up again */
103    switch( tr_sharedTraversalStatus( s ) )
104    {
105        case TR_PORT_MAPPED:
106            /* if we're mapped, everything is fine... check back in 20 minutes
107             * to renew the port forwarding if it's expired */
108            s->doPortCheck = true;
109            sec = 60 * 20;
110            break;
111
112        case TR_PORT_ERROR:
113            /* some kind of an error. wait 60 seconds and retry */
114            sec = 60;
115            break;
116
117        default:
118            /* in progress. pulse frequently. */
119            msec = 333000;
120            break;
121    }
122
123    if( s->timer != NULL )
124        tr_timerAdd( s->timer, sec, msec );
125}
126
127static void
128onTimer( int fd UNUSED, short what UNUSED, void * vshared )
129{
130    tr_shared * s = vshared;
131
132    assert( s );
133    assert( s->timer );
134
135    /* do something */
136    natPulse( s, s->doPortCheck );
137    s->doPortCheck = false;
138
139    /* set up the timer for the next pulse */
140    set_evtimer_from_status( s );
141}
142
143/***
144****
145***/
146
147tr_shared *
148tr_sharedInit( tr_session  * session )
149{
150    tr_shared * s = tr_new0( tr_shared, 1 );
151
152    s->session      = session;
153    s->isEnabled    = false;
154    s->upnpStatus   = TR_PORT_UNMAPPED;
155    s->natpmpStatus = TR_PORT_UNMAPPED;
156
157#if 0
158    if( isEnabled )
159    {
160        s->timer = tr_new0( struct event, 1 );
161        evtimer_set( s->timer, onTimer, s );
162        tr_timerAdd( s->timer, 0, 333000 );
163    }
164#endif
165
166    return s;
167}
168
169static void
170stop_timer( tr_shared * s )
171{
172    if( s->timer != NULL )
173    {
174        event_free( s->timer );
175        s->timer = NULL;
176    }
177}
178
179static void
180stop_forwarding( tr_shared * s )
181{
182    tr_ninf( getKey( ), "%s", _( "Stopped" ) );
183    natPulse( s, false );
184
185    tr_natpmpClose( s->natpmp );
186    s->natpmp = NULL;
187    s->natpmpStatus = TR_PORT_UNMAPPED;
188
189    tr_upnpClose( s->upnp );
190    s->upnp = NULL;
191    s->upnpStatus = TR_PORT_UNMAPPED;
192
193    stop_timer( s );
194}
195
196void
197tr_sharedClose( tr_session * session )
198{
199    tr_shared * s = session->shared;
200
201    s->isShuttingDown = true;
202    stop_forwarding( s );
203    s->session->shared = NULL;
204    tr_free( s );
205}
206
207static void
208start_timer( tr_shared * s )
209{
210    s->timer = evtimer_new( s->session->event_base, onTimer, s );
211    set_evtimer_from_status( s );
212}
213
214void
215tr_sharedTraversalEnable( tr_shared * s, bool isEnabled )
216{
217    if(( s->isEnabled = isEnabled ))
218        start_timer( s );
219    else
220        stop_forwarding( s );
221}
222
223void
224tr_sharedPortChanged( tr_session * session )
225{
226    tr_shared * s = session->shared;
227
228    if( s->isEnabled )
229    {
230        stop_timer( s );
231        natPulse( s, false );
232        start_timer( s );
233    }
234}
235
236bool
237tr_sharedTraversalIsEnabled( const tr_shared * s )
238{
239    return s->isEnabled;
240}
241
242int
243tr_sharedTraversalStatus( const tr_shared * s )
244{
245    return MAX( s->natpmpStatus, s->upnpStatus );
246}
Note: See TracBrowser for help on using the repository browser.