Skip to content
Snippets Groups Projects
Unverified Commit a0f22ec3 authored by akwizgran's avatar akwizgran
Browse files

Refactored connection status variables into inner class.

parent f58ee132
No related branches found
No related tags found
No related merge requests found
......@@ -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;
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment