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

Last change on this file since 11588 was 11588, checked in by charles, 11 years ago

(trunk libT) #3836 "libevent2 support" -- finish moving to the libevent2 API mode. don't include the backwards-compatable API headers.

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