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 $
16 #include <sys/types.h>
18 #include <event2/event.h>
20 #include "transmission.h"
21 #include "natpmp_local.h"
24 #include "port-forwarding.h"
31 getKey( void ) { return _( "Port Forwarding" ); }
39 tr_port_forwarding natpmpStatus
;
40 tr_port_forwarding upnpStatus
;
54 getNatStateStr( int 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 "???";
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
;
75 if( s
->natpmp
== NULL
)
76 s
->natpmp
= tr_natpmpInit( );
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
) );
97 set_evtimer_from_status( tr_shared
* s
)
101 /* when to wake up again */
102 switch( tr_sharedTraversalStatus( s
) )
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;
112 /* some kind of an error. wait 60 seconds and retry */
117 /* in progress. pulse frequently. */
122 if( s
->timer
!= NULL
)
123 tr_timerAdd( s
->timer
, sec
, msec
);
127 onTimer( int fd UNUSED
, short what UNUSED
, void * vshared
)
129 tr_shared
* s
= vshared
;
135 natPulse( s
, s
->doPortCheck
);
136 s
->doPortCheck
= false;
138 /* set up the timer for the next pulse */
139 set_evtimer_from_status( s
);
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
;
159 s
->timer
= tr_new0( struct event
, 1 );
160 evtimer_set( s
->timer
, onTimer
, s
);
161 tr_timerAdd( s
->timer
, 0, 333000 );
169 stop_timer( tr_shared
* s
)
171 if( s
->timer
!= NULL
)
173 event_free( s
->timer
);
179 stop_forwarding( tr_shared
* s
)
181 tr_ninf( getKey( ), "%s", _( "Stopped" ) );
182 natPulse( s
, false );
184 tr_natpmpClose( s
->natpmp
);
186 s
->natpmpStatus
= TR_PORT_UNMAPPED
;
188 tr_upnpClose( s
->upnp
);
190 s
->upnpStatus
= TR_PORT_UNMAPPED
;
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
;
207 start_timer( tr_shared
* s
)
209 s
->timer
= evtimer_new( s
->session
->event_base
, onTimer
, s
);
210 set_evtimer_from_status( s
);
214 tr_sharedTraversalEnable( tr_shared
* s
, bool isEnabled
)
216 if(( s
->isEnabled
= isEnabled
))
219 stop_forwarding( s
);
223 tr_sharedPortChanged( tr_session
* session
)
225 tr_shared
* s
= session
->shared
;
230 natPulse( s
, false );
236 tr_sharedTraversalIsEnabled( const tr_shared
* s
)
242 tr_sharedTraversalStatus( const tr_shared
* s
)
244 return MAX( s
->natpmpStatus
, s
->upnpStatus
);