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

Last change on this file since 12228 was 12228, checked in by jordan, 12 years ago

(trunk libT) still fiddling around with #includes -- this time removing unncecessary libT includes from libT .c files

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