@@ -41,17 +41,17 @@ public class TunnelManager implements Tunnel.HostService {
4141 public static final String SOCKS_SERVER_ADDRESS_EXTRA = "socksServerAddress" ;
4242
4343 private Service m_parentService = null ;
44- private boolean m_firstStart = true ;
45- private boolean m_signalledStop = false ;
4644 private CountDownLatch m_tunnelThreadStopSignal ;
4745 private Thread m_tunnelThread ;
4846 private AtomicBoolean m_isStopping ;
4947 private Tunnel m_tunnel = null ;
5048 private String m_socksServerAddress ;
49+ private AtomicBoolean m_isReconnecting ;
5150
5251 public TunnelManager (Service parentService ) {
5352 m_parentService = parentService ;
5453 m_isStopping = new AtomicBoolean (false );
54+ m_isReconnecting = new AtomicBoolean (false );
5555 m_tunnel = Tunnel .newTunnel (this );
5656 }
5757
@@ -108,30 +108,40 @@ public void onDestroy() {
108108 // 1. VpnService doesn't respond to stopService calls
109109 // 2. The UI will not block while waiting for stopService to return
110110 public void signalStopService () {
111- m_signalledStop = true ;
112111 if (m_tunnelThreadStopSignal != null ) {
113112 m_tunnelThreadStopSignal .countDown ();
114113 }
115114 }
116115
117- public boolean signalledStop () {
118- return m_signalledStop ;
116+ // Stops the tunnel thread and restarts it with |socksServerAddress|.
117+ public void restartTunnel (final String socksServerAddress ) {
118+ Log .i (LOG_TAG , "Restarting tunnel." );
119+ if (socksServerAddress == null ||
120+ socksServerAddress .equals (m_socksServerAddress )) {
121+ // Don't reconnect if the socks server address hasn't changed.
122+ return ;
123+ }
124+ m_socksServerAddress = socksServerAddress ;
125+ m_isReconnecting .set (true );
126+
127+ // Signaling stop to the tunnel thread with the reconnect flag set causes
128+ // the thread to stop the tunnel (but not the VPN or the service) and send
129+ // the new SOCKS server address to the DNS resolver before exiting itself.
130+ // When the DNS broadcasts its local address, the tunnel will restart.
131+ signalStopService ();
119132 }
120133
121134 private void startTunnel (final String dnsResolverAddress ) {
122- if (m_firstStart ) {
123- m_firstStart = false ;
124- m_tunnelThreadStopSignal = new CountDownLatch (1 );
125- m_tunnelThread =
126- new Thread (
127- new Runnable () {
128- @ Override
129- public void run () {
130- runTunnel (m_socksServerAddress , dnsResolverAddress );
131- }
132- });
133- m_tunnelThread .start ();
134- }
135+ m_tunnelThreadStopSignal = new CountDownLatch (1 );
136+ m_tunnelThread =
137+ new Thread (
138+ new Runnable () {
139+ @ Override
140+ public void run () {
141+ runTunnel (m_socksServerAddress , dnsResolverAddress );
142+ }
143+ });
144+ m_tunnelThread .start ();
135145 }
136146
137147 private void runTunnel (String socksServerAddress , String dnsResolverAddress ) {
@@ -154,12 +164,20 @@ private void runTunnel(String socksServerAddress, String dnsResolverAddress) {
154164 } catch (Tunnel .Exception e ) {
155165 Log .e (LOG_TAG , String .format ("Start tunnel failed: %s" , e .getMessage ()));
156166 } finally {
157- Log .i (LOG_TAG , "Stopping tunnel..." );
158- m_tunnel .stop ();
159-
160- // Stop service
161- m_parentService .stopForeground (true );
162- m_parentService .stopSelf ();
167+ if (m_isReconnecting .get ()) {
168+ // Stop tunneling only, not VPN, if reconnecting.
169+ Log .i (LOG_TAG , "Stopping tunnel." );
170+ m_tunnel .stopTunneling ();
171+ // Start the DNS resolver service with the new SOCKS server address.
172+ startDnsResolverService ();
173+ } else {
174+ // Stop VPN tunnel and service only if not reconnecting.
175+ Log .i (LOG_TAG , "Stopping VPN and tunnel." );
176+ m_tunnel .stop ();
177+ m_parentService .stopForeground (true );
178+ m_parentService .stopSelf ();
179+ }
180+ m_isReconnecting .set (false );
163181 }
164182 }
165183
@@ -201,6 +219,10 @@ public void onTunnelConnected() {
201219 @ TargetApi (Build .VERSION_CODES .M )
202220 public void onVpnEstablished () {
203221 Log .i (LOG_TAG , "VPN established." );
222+ startDnsResolverService ();
223+ }
224+
225+ private void startDnsResolverService () {
204226 Intent dnsResolverStart = new Intent (m_parentService , DnsResolverService .class );
205227 dnsResolverStart .putExtra (SOCKS_SERVER_ADDRESS_EXTRA , m_socksServerAddress );
206228 m_parentService .startService (dnsResolverStart );
0 commit comments