Transmission: update from 2.42 to 2.50
[tomato.git] / release / src / router / transmission / libtransmission / port-forwarding.c
blob010529c538bc9cae556f8fe6f3f712ba357474a1
1 /*
2 * This file Copyright (C) Mnemosyne LLC
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.
10 * $Id: port-forwarding.c 13199 2012-02-04 01:28:15Z jordan $
13 #include <assert.h>
14 #include <stdio.h>
16 #include <sys/types.h>
18 #include <event2/event.h>
20 #include "transmission.h"
21 #include "natpmp_local.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"
30 static const char *
31 getKey( void ) { return _( "Port Forwarding" ); }
33 struct tr_shared
35 bool isEnabled;
36 bool isShuttingDown;
37 bool doPortCheck;
39 tr_port_forwarding natpmpStatus;
40 tr_port_forwarding upnpStatus;
42 tr_upnp * upnp;
43 tr_natpmp * natpmp;
44 tr_session * session;
46 struct event * timer;
49 /***
50 ****
51 ***/
53 static const char*
54 getNatStateStr( int state )
56 switch( state )
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 "???";
66 static void
67 natPulse( tr_shared * s, bool do_check )
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;
75 if( s->natpmp == NULL )
76 s->natpmp = tr_natpmpInit( );
77 if( s->upnp == NULL )
78 s->upnp = tr_upnpInit( );
80 oldStatus = tr_sharedTraversalStatus( s );
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;
86 s->upnpStatus = tr_upnpPulse( s->upnp, private_peer_port, is_enabled, do_check );
88 newStatus = tr_sharedTraversalStatus( s );
90 if( newStatus != oldStatus )
91 tr_ninf( getKey( ), _( "State changed from \"%1$s\" to \"%2$s\"" ),
92 getNatStateStr( oldStatus ),
93 getNatStateStr( newStatus ) );
96 static void
97 set_evtimer_from_status( tr_shared * s )
99 int sec=0, msec=0;
101 /* when to wake up again */
102 switch( tr_sharedTraversalStatus( s ) )
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;
111 case TR_PORT_ERROR:
112 /* some kind of an error. wait 60 seconds and retry */
113 sec = 60;
114 break;
116 default:
117 /* in progress. pulse frequently. */
118 msec = 333000;
119 break;
122 if( s->timer != NULL )
123 tr_timerAdd( s->timer, sec, msec );
126 static void
127 onTimer( int fd UNUSED, short what UNUSED, void * vshared )
129 tr_shared * s = vshared;
131 assert( s );
132 assert( s->timer );
134 /* do something */
135 natPulse( s, s->doPortCheck );
136 s->doPortCheck = false;
138 /* set up the timer for the next pulse */
139 set_evtimer_from_status( s );
142 /***
143 ****
144 ***/
146 tr_shared *
147 tr_sharedInit( tr_session * session )
149 tr_shared * s = tr_new0( tr_shared, 1 );
151 s->session = session;
152 s->isEnabled = false;
153 s->upnpStatus = TR_PORT_UNMAPPED;
154 s->natpmpStatus = TR_PORT_UNMAPPED;
156 #if 0
157 if( isEnabled )
159 s->timer = tr_new0( struct event, 1 );
160 evtimer_set( s->timer, onTimer, s );
161 tr_timerAdd( s->timer, 0, 333000 );
163 #endif
165 return s;
168 static void
169 stop_timer( tr_shared * s )
171 if( s->timer != NULL )
173 event_free( s->timer );
174 s->timer = NULL;
178 static void
179 stop_forwarding( tr_shared * s )
181 tr_ninf( getKey( ), "%s", _( "Stopped" ) );
182 natPulse( s, false );
184 tr_natpmpClose( s->natpmp );
185 s->natpmp = NULL;
186 s->natpmpStatus = TR_PORT_UNMAPPED;
188 tr_upnpClose( s->upnp );
189 s->upnp = NULL;
190 s->upnpStatus = TR_PORT_UNMAPPED;
192 stop_timer( s );
195 void
196 tr_sharedClose( tr_session * session )
198 tr_shared * s = session->shared;
200 s->isShuttingDown = true;
201 stop_forwarding( s );
202 s->session->shared = NULL;
203 tr_free( s );
206 static void
207 start_timer( tr_shared * s )
209 s->timer = evtimer_new( s->session->event_base, onTimer, s );
210 set_evtimer_from_status( s );
213 void
214 tr_sharedTraversalEnable( tr_shared * s, bool isEnabled )
216 if(( s->isEnabled = isEnabled ))
217 start_timer( s );
218 else
219 stop_forwarding( s );
222 void
223 tr_sharedPortChanged( tr_session * session )
225 tr_shared * s = session->shared;
227 if( s->isEnabled )
229 stop_timer( s );
230 natPulse( s, false );
231 start_timer( s );
235 bool
236 tr_sharedTraversalIsEnabled( const tr_shared * s )
238 return s->isEnabled;
242 tr_sharedTraversalStatus( const tr_shared * s )
244 return MAX( s->natpmpStatus, s->upnpStatus );