Refactored connection status variables into inner class.

This commit is contained in:
akwizgran
2016-04-22 17:55:04 +01:00
parent f58ee13244
commit a0f22ec3d1

View File

@@ -50,8 +50,6 @@ import java.util.List;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.zip.ZipInputStream;
@@ -60,15 +58,13 @@ import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.POWER_SERVICE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_NO_CONNECTIVITY;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
class TorPlugin implements DuplexPlugin, EventHandler,
EventListener {
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
static final TransportId ID = new TransportId("tor");
@@ -93,18 +89,12 @@ class TorPlugin implements DuplexPlugin, EventHandler,
private final DuplexPluginCallback callback;
private final String architecture;
private final int maxLatency, maxIdleTime, pollingInterval, socketTimeout;
private final ConnectionStatus connectionStatus;
private final File torDirectory, torFile, geoIpFile, configFile, doneFile;
private final File cookieFile, hostnameFile;
private final AtomicBoolean circuitBuilt;
private final AtomicInteger descriptorsPublished;
private final PowerManager.WakeLock wakeLock;
private volatile boolean running = false, networkEnabled = false;
private volatile boolean bootstrapped = false;
private volatile boolean connectedToWifi = false;
private volatile boolean online = false;
private volatile long descriptorsPublishedTime = Long.MAX_VALUE;
private volatile boolean running = false;
private volatile ServerSocket socket = null;
private volatile Socket controlSocket = null;
private volatile TorControlConnection controlConnection = null;
@@ -127,6 +117,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
if (maxIdleTime > Integer.MAX_VALUE / 2)
socketTimeout = Integer.MAX_VALUE;
else socketTimeout = maxIdleTime * 2;
connectionStatus = new ConnectionStatus(pollingInterval);
torDirectory = appContext.getDir("tor", MODE_PRIVATE);
torFile = new File(torDirectory, "tor");
geoIpFile = new File(torDirectory, "geoip");
@@ -134,8 +125,6 @@ class TorPlugin implements DuplexPlugin, EventHandler,
doneFile = new File(torDirectory, "done");
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
hostnameFile = new File(torDirectory, "hs/hostname");
circuitBuilt = new AtomicBoolean(false);
descriptorsPublished = new AtomicInteger(0);
Object o = appContext.getSystemService(POWER_SERVICE);
PowerManager pm = (PowerManager) o;
wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "TorPlugin");
@@ -237,7 +226,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
String phase = controlConnection.getInfo("status/bootstrap-phase");
if (phase != null && phase.contains("PROGRESS=100")) {
LOG.info("Tor has already bootstrapped");
bootstrapped = true;
connectionStatus.setBootstrapped();
sendCrashReports();
}
}
@@ -495,13 +484,8 @@ class TorPlugin implements DuplexPlugin, EventHandler,
private void enableNetwork(boolean enable) throws IOException {
if (!running) return;
if (networkEnabled == enable) return;
if (LOG.isLoggable(INFO)) LOG.info("Enabling network: " + enable);
if (enable) wakeLock.acquire();
circuitBuilt.set(false);
descriptorsPublished.set(0);
descriptorsPublishedTime = Long.MAX_VALUE;
networkEnabled = enable;
connectionStatus.enableNetwork(enable);
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
if (!enable) {
callback.transportDisabled();
@@ -532,7 +516,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
}
public boolean isRunning() {
return running && networkEnabled && bootstrapped && circuitBuilt.get();
return running && connectionStatus.isConnected();
}
public boolean shouldPoll() {
@@ -545,16 +529,13 @@ class TorPlugin implements DuplexPlugin, EventHandler,
public void poll(Collection<ContactId> connected) {
if (!isRunning()) return;
if (descriptorsPublished.get() >= MIN_DESCRIPTORS_PUBLISHED) {
long now = clock.currentTimeMillis();
if (now - descriptorsPublishedTime >= 2 * pollingInterval) {
LOG.info("Hidden service descriptor published, not polling");
return;
}
if (connectionStatus.shouldPoll(clock.currentTimeMillis())) {
// TODO: Pass properties to connectAndCallBack()
for (ContactId c : callback.getRemoteProperties().keySet())
if (!connected.contains(c)) connectAndCallBack(c);
} else {
LOG.info("Hidden service descriptor published, not polling");
}
// TODO: Pass properties to connectAndCallBack()
for (ContactId c : callback.getRemoteProperties().keySet())
if (!connected.contains(c)) connectAndCallBack(c);
}
private void connectAndCallBack(final ContactId c) {
@@ -616,7 +597,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
}
public void circuitStatus(String status, String id, String path) {
if (status.equals("BUILT") && !circuitBuilt.getAndSet(true)) {
if (status.equals("BUILT") && connectionStatus.setCircuitBuilt()) {
LOG.info("First circuit built");
if (isRunning()) callback.transportEnabled();
}
@@ -638,20 +619,15 @@ class TorPlugin implements DuplexPlugin, EventHandler,
public void message(String severity, String msg) {
if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
bootstrapped = true;
connectionStatus.setBootstrapped();
sendCrashReports();
if (isRunning()) callback.transportEnabled();
}
}
public void unrecognized(String type, String msg) {
if (type.equals("HS_DESC") && msg.startsWith("UPLOADED")) {
int descriptors = descriptorsPublished.incrementAndGet();
if (descriptors == MIN_DESCRIPTORS_PUBLISHED) {
LOG.info("Hidden service descriptor published");
descriptorsPublishedTime = clock.currentTimeMillis();
}
}
if (type.equals("HS_DESC") && msg.startsWith("UPLOADED"))
connectionStatus.descriptorPublished(clock.currentTimeMillis());
}
private static class WriteObserver extends FileObserver {
@@ -673,7 +649,7 @@ class TorPlugin implements DuplexPlugin, EventHandler,
public void eventOccurred(Event e) {
if (e instanceof SettingsUpdatedEvent) {
if (((SettingsUpdatedEvent) e).getNamespace().equals("tor")) {
// Wifi setting may have been updated
LOG.info("Tor settings updated");
updateConnectionStatus();
}
}
@@ -684,17 +660,23 @@ class TorPlugin implements DuplexPlugin, EventHandler,
public void run() {
if (!running) return;
Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
ConnectivityManager cm = (ConnectivityManager) o;
NetworkInfo net = cm.getActiveNetworkInfo();
boolean online = net != null && net.isConnected();
boolean wifi = online && net.getType() == TYPE_WIFI;
String country = locationUtils.getCurrentCountry();
if (LOG.isLoggable(INFO)) {
LOG.info("Online: " + online);
if ("".equals(country)) LOG.info("Country code unknown");
else LOG.info("Country code: " + country);
}
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
country);
Settings s = callback.getSettings();
boolean useMobileData = s.getBoolean("torOverMobile", true);
if (LOG.isLoggable(INFO)) {
LOG.info("Online: " + online + ", wifi: " + wifi);
if ("".equals(country)) LOG.info("Country code unknown");
else LOG.info("Country code: " + country);
}
try {
if (!online) {
LOG.info("Disabling network, device is offline");
@@ -702,10 +684,11 @@ class TorPlugin implements DuplexPlugin, EventHandler,
} else if (blocked) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else if (!useMobileData & !connectedToWifi) {
} else if (!wifi && !useMobileData) {
LOG.info("Disabling network due to data setting");
enableNetwork(false);
} else {
LOG.info("Enabling network");
enableNetwork(true);
}
} catch (IOException e) {
@@ -723,16 +706,55 @@ class TorPlugin implements DuplexPlugin, EventHandler,
if (!running) return;
if (CONNECTIVITY_ACTION.equals(i.getAction())) {
LOG.info("Detected connectivity change");
online = !i.getBooleanExtra(EXTRA_NO_CONNECTIVITY, false);
// Some devices fail to set EXTRA_NO_CONNECTIVITY, double check
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
ConnectivityManager cm = (ConnectivityManager) o;
NetworkInfo net = cm.getActiveNetworkInfo();
if (net == null || !net.isConnected()) online = false;
connectedToWifi = (net != null && net.getType() == TYPE_WIFI
&& net.isConnected());
updateConnectionStatus();
}
}
}
private static class ConnectionStatus {
private final int pollingInterval;
// All of the following are locking: this
private boolean networkEnabled = false;
private boolean bootstrapped = false, circuitBuilt = false;
private int descriptorsPublished = 0;
private long descriptorsPublishedTime = Long.MAX_VALUE;
private ConnectionStatus(int pollingInterval) {
this.pollingInterval = pollingInterval;
}
private synchronized void setBootstrapped() {
bootstrapped = true;
}
private synchronized boolean setCircuitBuilt() {
boolean firstCircuit = !circuitBuilt;
circuitBuilt = true;
return firstCircuit;
}
private synchronized void descriptorPublished(long now) {
descriptorsPublished++;
if (descriptorsPublished == MIN_DESCRIPTORS_PUBLISHED)
descriptorsPublishedTime = now;
}
private synchronized void enableNetwork(boolean enable) {
networkEnabled = enable;
circuitBuilt = false;
descriptorsPublished = 0;
descriptorsPublishedTime = Long.MAX_VALUE;
}
private synchronized boolean isConnected() {
return networkEnabled && bootstrapped && circuitBuilt;
}
private synchronized boolean shouldPoll(long now) {
return descriptorsPublished < MIN_DESCRIPTORS_PUBLISHED
|| now - descriptorsPublishedTime < 2 * pollingInterval;
}
}
}