@@ -41,17 +41,17 @@ public class TunnelManager implements Tunnel.HostService {
41
41
public static final String SOCKS_SERVER_ADDRESS_EXTRA = "socksServerAddress" ;
42
42
43
43
private Service m_parentService = null ;
44
- private boolean m_firstStart = true ;
45
- private boolean m_signalledStop = false ;
46
44
private CountDownLatch m_tunnelThreadStopSignal ;
47
45
private Thread m_tunnelThread ;
48
46
private AtomicBoolean m_isStopping ;
49
47
private Tunnel m_tunnel = null ;
50
48
private String m_socksServerAddress ;
49
+ private AtomicBoolean m_isReconnecting ;
51
50
52
51
public TunnelManager (Service parentService ) {
53
52
m_parentService = parentService ;
54
53
m_isStopping = new AtomicBoolean (false );
54
+ m_isReconnecting = new AtomicBoolean (false );
55
55
m_tunnel = Tunnel .newTunnel (this );
56
56
}
57
57
@@ -108,30 +108,40 @@ public void onDestroy() {
108
108
// 1. VpnService doesn't respond to stopService calls
109
109
// 2. The UI will not block while waiting for stopService to return
110
110
public void signalStopService () {
111
- m_signalledStop = true ;
112
111
if (m_tunnelThreadStopSignal != null ) {
113
112
m_tunnelThreadStopSignal .countDown ();
114
113
}
115
114
}
116
115
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 ();
119
132
}
120
133
121
134
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 ();
135
145
}
136
146
137
147
private void runTunnel (String socksServerAddress , String dnsResolverAddress ) {
@@ -154,12 +164,20 @@ private void runTunnel(String socksServerAddress, String dnsResolverAddress) {
154
164
} catch (Tunnel .Exception e ) {
155
165
Log .e (LOG_TAG , String .format ("Start tunnel failed: %s" , e .getMessage ()));
156
166
} 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 );
163
181
}
164
182
}
165
183
@@ -201,6 +219,10 @@ public void onTunnelConnected() {
201
219
@ TargetApi (Build .VERSION_CODES .M )
202
220
public void onVpnEstablished () {
203
221
Log .i (LOG_TAG , "VPN established." );
222
+ startDnsResolverService ();
223
+ }
224
+
225
+ private void startDnsResolverService () {
204
226
Intent dnsResolverStart = new Intent (m_parentService , DnsResolverService .class );
205
227
dnsResolverStart .putExtra (SOCKS_SERVER_ADDRESS_EXTRA , m_socksServerAddress );
206
228
m_parentService .startService (dnsResolverStart );
0 commit comments