From ded17922137062b4988c79f94d0a30206c95b230 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 14 Jan 2020 09:51:03 +0000 Subject: [PATCH 01/19] Avoid NPE if there's no TelephonyManager. --- .../org/briarproject/bramble/system/AndroidLocationUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidLocationUtils.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidLocationUtils.java index 226064d6f..21d2075c1 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidLocationUtils.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidLocationUtils.java @@ -61,12 +61,12 @@ class AndroidLocationUtils implements LocationUtils { private String getCountryFromPhoneNetwork() { Object o = appContext.getSystemService(TELEPHONY_SERVICE); TelephonyManager tm = (TelephonyManager) o; - return tm.getNetworkCountryIso(); + return tm == null ? "" : tm.getNetworkCountryIso(); } private String getCountryFromSimCard() { Object o = appContext.getSystemService(TELEPHONY_SERVICE); TelephonyManager tm = (TelephonyManager) o; - return tm.getSimCountryIso(); + return tm == null ? "" : tm.getSimCountryIso(); } } From 5d6ed1a724ca23d4d83cb823e574e5f2d9742b03 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 14 Jan 2020 12:18:24 +0000 Subject: [PATCH 02/19] Provide more information about plugin states. --- .../plugin/tcp/AndroidLanTcpPlugin.java | 20 ++- .../bramble/plugin/tor/AndroidTorPlugin.java | 2 +- .../bramble/api/plugin/Plugin.java | 32 ++++- .../bramble/api/plugin/PluginCallback.java | 10 +- .../bramble/plugin/PluginManagerImpl.java | 34 +++-- .../plugin/bluetooth/BluetoothPlugin.java | 111 +++++++++++---- .../bramble/plugin/file/FilePlugin.java | 5 +- .../bramble/plugin/tcp/LanTcpPlugin.java | 22 +-- .../bramble/plugin/tcp/TcpPlugin.java | 114 +++++++++++----- .../bramble/plugin/tor/TorPlugin.java | 126 ++++++++++++------ .../bramble/plugin/tcp/LanTcpPluginTest.java | 8 +- .../bramble/plugin/modem/ModemPlugin.java | 71 ++++++++-- .../navdrawer/NavDrawerControllerImpl.java | 3 +- 13 files changed, 398 insertions(+), 160 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java index ef6cb8efa..00ea54c03 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java @@ -33,6 +33,8 @@ import static android.os.Build.VERSION.SDK_INT; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; @NotNullByDefault class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { @@ -79,16 +81,11 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { @Override public void start() { if (used.getAndSet(true)) throw new IllegalStateException(); - running = true; + state.setStarted(); + callback.pluginStateChanged(getState()); updateConnectionStatus(); } - @Override - public void stop() { - running = false; - tryToClose(socket); - } - @Override protected Socket createSocket() throws IOException { return socketFactory.createSocket(); @@ -143,7 +140,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { private void updateConnectionStatus() { connectionStatusExecutor.execute(() -> { - if (!running) return; + State state = getState(); + if (state != AVAILABLE && state != UNAVAILABLE) return; Collection addrs = getLocalIpAddresses(); if (addrs.contains(WIFI_AP_ADDRESS)) { LOG.info("Providing wifi hotspot"); @@ -152,15 +150,15 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { // make outgoing connections on API 21+ if another network // has internet access socketFactory = SocketFactory.getDefault(); - if (socket == null || socket.isClosed()) bind(); + if (state == UNAVAILABLE) bind(); } else if (addrs.isEmpty()) { LOG.info("Not connected to wifi"); socketFactory = SocketFactory.getDefault(); - tryToClose(socket); + // TODO: Check that socket was closed when interface went down } else { LOG.info("Connected to wifi"); socketFactory = getSocketFactory(); - if (socket == null || socket.isClosed()) bind(); + if (state == UNAVAILABLE) bind(); } }); } diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java index f36773615..10ac8e788 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java @@ -74,7 +74,7 @@ class AndroidTorPlugin extends TorPlugin { @Override protected void enableNetwork(boolean enable) throws IOException { - if (!running) return; + if (!state.isRunning()) return; if (enable) wakeLock.acquire(); super.enableNetwork(enable); if (!enable) wakeLock.release(); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java index 84872dfed..b26a37159 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java @@ -9,6 +9,34 @@ import java.util.Collection; @NotNullByDefault public interface Plugin { + enum State { + + /** + * The plugin has not been started, has been stopped, or is disabled by + * settings. + */ + DISABLED, + + /** + * The plugin has been started, has not been stopped, is enabled by + * settings, but can't yet tell whether it can make or receive + * connections. + */ + ENABLING, + + /** + * The plugin has been started, has not been stopped, is enabled by + * settings, and can make or receive connections. + */ + AVAILABLE, + + /** + * The plugin has been started, has not been stopped, is enabled by + * settings, but can't make or receive connections + */ + UNAVAILABLE + } + /** * Returns the plugin's transport identifier. */ @@ -35,9 +63,9 @@ public interface Plugin { void stop() throws PluginException; /** - * Returns true if the plugin is running. + * Returns the current state of the plugin. */ - boolean isRunning(); + State getState(); /** * Returns true if the plugin should be polled periodically to attempt to diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java index b9cbd450b..ed057a958 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.api.plugin; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Plugin.State; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.settings.Settings; @@ -32,12 +33,7 @@ public interface PluginCallback extends ConnectionHandler { void mergeLocalProperties(TransportProperties p); /** - * Signals that the transport is enabled. + * Signals that the transport's state may have changed. */ - void transportEnabled(); - - /** - * Signals that the transport is disabled. - */ - void transportDisabled(); + void pluginStateChanged(State state); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java index d4d69ca56..b64fa054c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java @@ -8,6 +8,7 @@ import org.briarproject.bramble.api.lifecycle.ServiceException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.ConnectionManager; import org.briarproject.bramble.api.plugin.Plugin; +import org.briarproject.bramble.api.plugin.Plugin.State; import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.PluginConfig; import org.briarproject.bramble.api.plugin.PluginException; @@ -36,6 +37,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; import javax.annotation.concurrent.ThreadSafe; @@ -45,6 +47,8 @@ import static java.util.logging.Level.FINE; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; @@ -250,6 +254,8 @@ class PluginManagerImpl implements PluginManager, Service { private class Callback implements PluginCallback { private final TransportId id; + private final AtomicReference state = + new AtomicReference<>(DISABLED); private final AtomicBoolean enabled = new AtomicBoolean(false); private Callback(TransportId id) { @@ -295,15 +301,25 @@ class PluginManagerImpl implements PluginManager, Service { } @Override - public void transportEnabled() { - if (!enabled.getAndSet(true)) - eventBus.broadcast(new TransportEnabledEvent(id)); - } - - @Override - public void transportDisabled() { - if (enabled.getAndSet(false)) - eventBus.broadcast(new TransportDisabledEvent(id)); + public void pluginStateChanged(State newState) { + State oldState = state.getAndSet(newState); + if (newState != oldState) { + if (LOG.isLoggable(INFO)) { + LOG.info(id + " changed from state " + oldState + + " to " + newState); + } + if (newState == AVAILABLE) { + if (!enabled.getAndSet(true)) + eventBus.broadcast(new TransportEnabledEvent(id)); + } else { + if (enabled.getAndSet(false)) + eventBus.broadcast(new TransportDisabledEvent(id)); + } + } else { + // TODO: Remove + if (LOG.isLoggable(INFO)) + LOG.info(id + " stayed in state " + oldState); + } } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index 0dec35bc5..8df0d40f6 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -10,6 +10,7 @@ import org.briarproject.bramble.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent; import org.briarproject.bramble.api.keyagreement.event.KeyAgreementStoppedListeningEvent; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.ConnectionHandler; @@ -36,6 +37,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; @@ -46,6 +49,9 @@ import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENA import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID; import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; +import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -68,9 +74,10 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { private final int maxLatency; private final AtomicBoolean used = new AtomicBoolean(false); - private volatile boolean running = false, contactConnections = false; + protected final PluginState state = new PluginState(); + + private volatile boolean contactConnections = false; private volatile String contactConnectionsUuid = null; - private volatile SS socket = null; abstract void initialiseAdapter() throws IOException; @@ -120,13 +127,16 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { // We may not have been able to get the local address before ioExecutor.execute(this::updateProperties); if (shouldAllowContactConnections()) bind(); + callback.pluginStateChanged(getState()); } void onAdapterDisabled() { LOG.info("Bluetooth disabled"); - tryToClose(socket); + // TODO: Is this needed, or will the socket be closed automatically? + SS ss = state.clearServerSocket(); + tryToClose(ss); connectionLimiter.allConnectionsClosed(); - callback.transportDisabled(); + callback.pluginStateChanged(getState()); } @Override @@ -154,7 +164,8 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { throw new PluginException(e); } updateProperties(); - running = true; + state.setStarted(); + callback.pluginStateChanged(getState()); loadSettings(callback.getSettings()); if (shouldAllowContactConnections()) { if (isAdapterEnabled()) bind(); @@ -172,7 +183,8 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { private void bind() { ioExecutor.execute(() -> { - if (!isRunning() || !shouldAllowContactConnections()) return; + if (!shouldAllowContactConnections() || getState() != AVAILABLE) + return; // Bind a server socket to accept connections from contacts SS ss; try { @@ -181,14 +193,15 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { logException(LOG, WARNING, e); return; } - if (!isRunning() || !shouldAllowContactConnections()) { + if (!shouldAllowContactConnections() || + !state.setServerSocket(ss)) { + LOG.info("Closing redundant server socket"); tryToClose(ss); return; } - socket = ss; backoff.reset(); - callback.transportEnabled(); - acceptContactConnections(); + callback.pluginStateChanged(getState()); + acceptContactConnections(ss); }); } @@ -217,34 +230,36 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { if (changed) callback.mergeLocalProperties(p); } - private void acceptContactConnections() { + private void acceptContactConnections(SS ss) { while (true) { DuplexTransportConnection conn; try { - conn = acceptConnection(socket); + conn = acceptConnection(ss); } catch (IOException e) { // This is expected when the socket is closed - if (LOG.isLoggable(INFO)) LOG.info(e.toString()); + // TODO: Check that this is logged at shutdown/when BT disabled + LOG.info("Server socket closed"); + state.clearServerSocket(); return; } + LOG.info("Connection received"); backoff.reset(); if (connectionLimiter.contactConnectionOpened(conn)) callback.handleConnection(conn); - if (!running) return; } } @Override public void stop() { - running = false; - tryToClose(socket); - callback.transportDisabled(); + SS ss = state.setStopped(); + callback.pluginStateChanged(getState()); + tryToClose(ss); disableAdapterIfEnabledByUs(); } @Override - public boolean isRunning() { - return running && isAdapterEnabled(); + public State getState() { + return state.getState(); } @Override @@ -260,7 +275,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public void poll(Collection> properties) { - if (!isRunning() || !shouldAllowContactConnections()) return; + if (!shouldAllowContactConnections() || getState() != AVAILABLE) return; backoff.increment(); for (Pair p : properties) { connect(p.getFirst(), p.getSecond()); @@ -273,7 +288,8 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { String uuid = p.get(PROP_UUID); if (isNullOrEmpty(uuid)) return; ioExecutor.execute(() -> { - if (!isRunning() || !shouldAllowContactConnections()) return; + if (!shouldAllowContactConnections() || getState() != AVAILABLE) + return; if (!connectionLimiter.canOpenContactConnection()) return; DuplexTransportConnection d = createConnection(p); if (d != null) { @@ -317,7 +333,8 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public DuplexTransportConnection createConnection(TransportProperties p) { - if (!isRunning() || !shouldAllowContactConnections()) return null; + if (!shouldAllowContactConnections() || getState() != AVAILABLE) + return null; if (!connectionLimiter.canOpenContactConnection()) return null; String address = p.get(PROP_ADDRESS); if (isNullOrEmpty(address)) return null; @@ -336,7 +353,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public KeyAgreementListener createKeyAgreementListener(byte[] commitment) { - if (!isRunning()) return null; + if (getState() != AVAILABLE) return null; // No truncation necessary because COMMIT_LENGTH = 16 String uuid = UUID.nameUUIDFromBytes(commitment).toString(); if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid); @@ -348,7 +365,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { logException(LOG, WARNING, e); return null; } - if (!isRunning()) { + if (getState() != AVAILABLE) { tryToClose(ss); return null; } @@ -362,7 +379,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public DuplexTransportConnection createKeyAgreementConnection( byte[] commitment, BdfList descriptor) { - if (!isRunning()) return null; + if (getState() != AVAILABLE) return null; // No truncation necessary because COMMIT_LENGTH = 16 String uuid = UUID.nameUUIDFromBytes(commitment).toString(); DuplexTransportConnection conn; @@ -428,8 +445,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { boolean isAllowed = shouldAllowContactConnections(); if (wasAllowed && !isAllowed) { LOG.info("Contact connections disabled"); - tryToClose(socket); - callback.transportDisabled(); + tryToClose(state.clearServerSocket()); disableAdapterIfEnabledByUs(); } else if (!wasAllowed && isAllowed) { LOG.info("Contact connections enabled"); @@ -460,4 +476,45 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { tryToClose(ss); } } + + @ThreadSafe + @NotNullByDefault + protected class PluginState { + + @GuardedBy("this") + private boolean started = false, stopped = false; + @GuardedBy("this") + @Nullable + private SS serverSocket = null; + + synchronized void setStarted() { + started = true; + } + + @Nullable + synchronized SS setStopped() { + stopped = true; + SS ss = serverSocket; + serverSocket = null; + return ss; + } + + synchronized boolean setServerSocket(SS ss) { + if (stopped || serverSocket != null) return false; + serverSocket = ss; + return true; + } + + @Nullable + synchronized SS clearServerSocket() { + SS ss = serverSocket; + serverSocket = null; + return ss; + } + + synchronized State getState() { + if (!started || stopped) return DISABLED; + return isAdapterEnabled() ? AVAILABLE : UNAVAILABLE; + } + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/FilePlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/FilePlugin.java index 0d4f56618..d846fd2ae 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/FilePlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/FilePlugin.java @@ -16,6 +16,7 @@ import java.util.logging.Logger; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.plugin.FileConstants.PROP_PATH; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -45,7 +46,7 @@ abstract class FilePlugin implements SimplexPlugin { @Override public TransportConnectionReader createReader(TransportProperties p) { - if (!isRunning()) return null; + if (getState() != AVAILABLE) return null; String path = p.get(PROP_PATH); if (isNullOrEmpty(path)) return null; try { @@ -60,7 +61,7 @@ abstract class FilePlugin implements SimplexPlugin { @Override public TransportConnectionWriter createWriter(TransportProperties p) { - if (!isRunning()) return null; + if (getState() != AVAILABLE) return null; String path = p.get(PROP_PATH); if (isNullOrEmpty(path)) return null; try { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java index 78ea1a7cd..c7a7d2e4b 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java @@ -11,7 +11,6 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.settings.Settings; -import org.briarproject.bramble.util.IoUtils; import java.io.IOException; import java.net.Inet4Address; @@ -19,7 +18,6 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; -import java.net.SocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Comparator; @@ -38,6 +36,7 @@ import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID; import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS; import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS; import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED; +import static org.briarproject.bramble.util.IoUtils.tryToClose; import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; import static org.briarproject.bramble.util.StringUtils.join; @@ -149,8 +148,9 @@ class LanTcpPlugin extends TcpPlugin { if (remote.getPort() == 0) return false; if (!isAcceptableAddress(remote.getAddress())) return false; // Try to determine whether the address is on the same LAN as us - if (socket == null) return false; - byte[] localIp = socket.getInetAddress().getAddress(); + ServerSocket ss = state.getServerSocket(); + if (ss == null) return false; + byte[] localIp = ss.getInetAddress().getAddress(); byte[] remoteIp = remote.getAddress().getAddress(); return addressesAreOnSameLan(localIp, remoteIp); } @@ -209,10 +209,10 @@ class LanTcpPlugin extends TcpPlugin { } catch (IOException e) { if (LOG.isLoggable(INFO)) LOG.info("Failed to bind " + scrubSocketAddress(addr)); - tryToClose(ss); + tryToClose(ss, LOG, WARNING); } } - if (ss == null || !ss.isBound()) { + if (ss == null) { LOG.info("Could not bind server socket for key agreement"); return null; } @@ -228,7 +228,8 @@ class LanTcpPlugin extends TcpPlugin { @Override public DuplexTransportConnection createKeyAgreementConnection( byte[] commitment, BdfList descriptor) { - if (!isRunning()) return null; + ServerSocket ss = state.getServerSocket(); + if (ss == null) return null; InetSocketAddress remote; try { remote = parseSocketAddress(descriptor); @@ -238,10 +239,9 @@ class LanTcpPlugin extends TcpPlugin { } if (!isConnectable(remote)) { if (LOG.isLoggable(INFO)) { - SocketAddress local = socket.getLocalSocketAddress(); LOG.info(scrubSocketAddress(remote) + " is not connectable from " + - scrubSocketAddress(local)); + scrubSocketAddress(ss.getLocalSocketAddress())); } return null; } @@ -249,7 +249,7 @@ class LanTcpPlugin extends TcpPlugin { if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + scrubSocketAddress(remote)); Socket s = createSocket(); - s.bind(new InetSocketAddress(socket.getInetAddress(), 0)); + s.bind(new InetSocketAddress(ss.getInetAddress(), 0)); s.connect(remote); s.setSoTimeout(socketTimeout); if (LOG.isLoggable(INFO)) @@ -296,7 +296,7 @@ class LanTcpPlugin extends TcpPlugin { @Override public void close() { - IoUtils.tryToClose(ss, LOG, WARNING); + tryToClose(ss, LOG, WARNING); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java index 4ca15d0b9..85bd9e468 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java @@ -5,6 +5,7 @@ import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.ConnectionHandler; @@ -14,7 +15,6 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.rendezvous.KeyMaterialSource; import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint; -import org.briarproject.bramble.util.IoUtils; import java.io.IOException; import java.net.InetAddress; @@ -22,7 +22,6 @@ import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.Socket; -import java.net.SocketAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; @@ -35,6 +34,8 @@ import java.util.logging.Logger; import java.util.regex.Pattern; import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; import static java.net.NetworkInterface.getNetworkInterfaces; import static java.util.Collections.emptyList; @@ -42,6 +43,10 @@ import static java.util.Collections.list; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; +import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; +import static org.briarproject.bramble.util.IoUtils.tryToClose; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -60,9 +65,7 @@ abstract class TcpPlugin implements DuplexPlugin { protected final PluginCallback callback; protected final int maxLatency, maxIdleTime, socketTimeout; protected final AtomicBoolean used = new AtomicBoolean(false); - - protected volatile boolean running = false; - protected volatile ServerSocket socket = null; + protected final PluginState state = new PluginState(); /** * Returns zero or more socket addresses on which the plugin should listen, @@ -86,6 +89,7 @@ abstract class TcpPlugin implements DuplexPlugin { /** * Returns true if connections to the given address can be attempted. */ + @SuppressWarnings("BooleanMethodIsAlwaysInverted") protected abstract boolean isConnectable(InetSocketAddress remote); TcpPlugin(Executor ioExecutor, Backoff backoff, PluginCallback callback, @@ -115,14 +119,14 @@ abstract class TcpPlugin implements DuplexPlugin { @Override public void start() { if (used.getAndSet(true)) throw new IllegalStateException(); - running = true; + state.setStarted(); + callback.pluginStateChanged(getState()); bind(); } protected void bind() { bindExecutor.execute(() -> { - if (!running) return; - if (socket != null && !socket.isClosed()) return; + if (getState() != UNAVAILABLE) return; ServerSocket ss = null; for (InetSocketAddress addr : getLocalSocketAddresses()) { try { @@ -132,34 +136,29 @@ abstract class TcpPlugin implements DuplexPlugin { } catch (IOException e) { if (LOG.isLoggable(INFO)) LOG.info("Failed to bind " + scrubSocketAddress(addr)); - tryToClose(ss); + tryToClose(ss, LOG, WARNING); } } - if (ss == null || !ss.isBound()) { + if (ss == null) { LOG.info("Could not bind server socket"); return; } - if (!running) { - tryToClose(ss); + if (!state.setServerSocket(ss)) { + LOG.info("Closing redundant server socket"); + tryToClose(ss, LOG, WARNING); return; } - socket = ss; backoff.reset(); InetSocketAddress local = (InetSocketAddress) ss.getLocalSocketAddress(); setLocalSocketAddress(local); + callback.pluginStateChanged(getState()); if (LOG.isLoggable(INFO)) LOG.info("Listening on " + scrubSocketAddress(local)); - callback.transportEnabled(); - acceptContactConnections(); + acceptContactConnections(ss); }); } - protected void tryToClose(@Nullable ServerSocket ss) { - IoUtils.tryToClose(ss, LOG, WARNING); - callback.transportDisabled(); - } - String getIpPortString(InetSocketAddress a) { String addr = a.getAddress().getHostAddress(); int percent = addr.indexOf('%'); @@ -167,15 +166,18 @@ abstract class TcpPlugin implements DuplexPlugin { return addr + ":" + a.getPort(); } - private void acceptContactConnections() { - while (isRunning()) { + private void acceptContactConnections(ServerSocket ss) { + while (true) { Socket s; try { - s = socket.accept(); + s = ss.accept(); s.setSoTimeout(socketTimeout); } catch (IOException e) { - // This is expected when the socket is closed - if (LOG.isLoggable(INFO)) LOG.info(e.toString()); + // This is expected when the server socket is closed + // TODO: Check that this is logged at shutdown/when LAN disabled + LOG.info("Server socket closed"); + state.clearServerSocket(ss); + callback.pluginStateChanged(getState()); return; } if (LOG.isLoggable(INFO)) @@ -188,13 +190,14 @@ abstract class TcpPlugin implements DuplexPlugin { @Override public void stop() { - running = false; - tryToClose(socket); + ServerSocket ss = state.setStopped(); + callback.pluginStateChanged(getState()); + tryToClose(ss, LOG, WARNING); } @Override - public boolean isRunning() { - return running && socket != null && !socket.isClosed(); + public State getState() { + return state.getState(); } @Override @@ -210,7 +213,7 @@ abstract class TcpPlugin implements DuplexPlugin { @Override public void poll(Collection> properties) { - if (!isRunning()) return; + if (getState() != AVAILABLE) return; backoff.increment(); for (Pair p : properties) { connect(p.getFirst(), p.getSecond()); @@ -229,14 +232,14 @@ abstract class TcpPlugin implements DuplexPlugin { @Override public DuplexTransportConnection createConnection(TransportProperties p) { - if (!isRunning()) return null; + ServerSocket ss = state.getServerSocket(); + if (ss == null) return null; for (InetSocketAddress remote : getRemoteSocketAddresses(p)) { if (!isConnectable(remote)) { if (LOG.isLoggable(INFO)) { - SocketAddress local = socket.getLocalSocketAddress(); LOG.info(scrubSocketAddress(remote) + " is not connectable from " + - scrubSocketAddress(local)); + scrubSocketAddress(ss.getLocalSocketAddress())); } continue; } @@ -244,7 +247,7 @@ abstract class TcpPlugin implements DuplexPlugin { if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + scrubSocketAddress(remote)); Socket s = createSocket(); - s.bind(new InetSocketAddress(socket.getInetAddress(), 0)); + s.bind(new InetSocketAddress(ss.getInetAddress(), 0)); s.connect(remote); s.setSoTimeout(socketTimeout); if (LOG.isLoggable(INFO)) @@ -327,4 +330,47 @@ abstract class TcpPlugin implements DuplexPlugin { return emptyList(); } } + + @ThreadSafe + @NotNullByDefault + protected static class PluginState { + + @GuardedBy("this") + private boolean started = false, stopped = false; + @GuardedBy("this") + @Nullable + private ServerSocket serverSocket = null; + + synchronized void setStarted() { + started = true; + } + + @Nullable + synchronized ServerSocket setStopped() { + stopped = true; + ServerSocket ss = serverSocket; + serverSocket = null; + return ss; + } + + @Nullable + synchronized ServerSocket getServerSocket() { + return serverSocket; + } + + synchronized boolean setServerSocket(ServerSocket ss) { + if (stopped || serverSocket != null) return false; + serverSocket = ss; + return true; + } + + synchronized void clearServerSocket(ServerSocket ss) { + if (serverSocket == ss) serverSocket = null; + } + + synchronized State getState() { + if (!started || stopped) return DISABLED; + return serverSocket == null ? UNAVAILABLE : AVAILABLE; + } + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index e23a0da48..d973075f0 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -15,6 +15,7 @@ import org.briarproject.bramble.api.network.NetworkManager; import org.briarproject.bramble.api.network.NetworkStatus; import org.briarproject.bramble.api.network.event.NetworkStatusEvent; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.ConnectionHandler; @@ -54,6 +55,9 @@ import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.zip.ZipInputStream; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; import javax.net.SocketFactory; import static java.util.Arrays.asList; @@ -65,6 +69,10 @@ import static java.util.logging.Logger.getLogger; import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS; import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; +import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING; +import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.ID; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_MOBILE; @@ -113,16 +121,14 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private final int maxLatency, maxIdleTime, socketTimeout; private final File torDirectory, torFile, geoIpFile, obfs4File, configFile; private final File doneFile, cookieFile; - private final ConnectionStatus connectionStatus; private final AtomicBoolean used = new AtomicBoolean(false); - private volatile ServerSocket socket = null; + protected final PluginState state = new PluginState(); + private volatile Socket controlSocket = null; private volatile TorControlConnection controlConnection = null; private volatile Settings settings = null; - protected volatile boolean running = false; - protected abstract int getProcessId(); protected abstract long getLastUpdateTime(); @@ -159,7 +165,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { configFile = new File(torDirectory, "torrc"); doneFile = new File(torDirectory, "done"); cookieFile = new File(torDirectory, ".tor/control_auth_cookie"); - connectionStatus = new ConnectionStatus(); // Don't execute more than one connection status check at a time connectionStatusExecutor = new PoliteExecutor("TorPlugin", ioExecutor, 1); @@ -258,7 +263,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { // Tell Tor to exit when the control connection is closed controlConnection.takeOwnership(); controlConnection.resetConf(singletonList(OWNER)); - running = true; // Register to receive events from the Tor process controlConnection.setEventHandler(this); controlConnection.setEvents(asList(EVENTS)); @@ -266,11 +270,13 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { String phase = controlConnection.getInfo("status/bootstrap-phase"); if (phase != null && phase.contains("PROGRESS=100")) { LOG.info("Tor has already bootstrapped"); - connectionStatus.setBootstrapped(); + state.setBootstrapped(); } } catch (IOException e) { throw new PluginException(e); } + state.setStarted(); + callback.pluginStateChanged(getState()); // Check whether we're online updateConnectionStatus(networkManager.getNetworkStatus(), batteryManager.isCharging()); @@ -393,11 +399,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { tryToClose(ss, LOG, WARNING); return; } - if (!running) { + if (!state.setServerSocket(ss)) { + LOG.info("Closing redundant server socket"); tryToClose(ss, LOG, WARNING); return; } - socket = ss; // Store the port number String localPort = String.valueOf(ss.getLocalPort()); Settings s = new Settings(); @@ -412,7 +418,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } private void publishHiddenService(String port) { - if (!running) return; + if (!state.isRunning()) return; LOG.info("Creating hidden service"); String privKey = settings.get(HS_PRIVKEY); Map portLines = singletonMap(80, "127.0.0.1:" + port); @@ -450,14 +456,16 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } private void acceptContactConnections(ServerSocket ss) { - while (running) { + while (true) { Socket s; try { s = ss.accept(); s.setSoTimeout(socketTimeout); } catch (IOException e) { - // This is expected when the socket is closed - if (LOG.isLoggable(INFO)) LOG.info(e.toString()); + // This is expected when the server socket is closed + // TODO: Check that this is logged at shutdown + LOG.info("Server socket closed"); + state.clearServerSocket(ss); return; } LOG.info("Connection received"); @@ -467,10 +475,10 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } protected void enableNetwork(boolean enable) throws IOException { - if (!running) return; - connectionStatus.enableNetwork(enable); + if (!state.isRunning()) return; + state.enableNetwork(enable); + callback.pluginStateChanged(getState()); controlConnection.setConf("DisableNetwork", enable ? "0" : "1"); - if (!enable) callback.transportDisabled(); } private void enableBridges(boolean enable, boolean needsMeek) @@ -494,9 +502,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void stop() { - running = false; - tryToClose(socket, LOG, WARNING); - callback.transportDisabled(); + ServerSocket ss = state.setStopped(); + callback.pluginStateChanged(getState()); + tryToClose(ss, LOG, WARNING); if (controlSocket != null && controlConnection != null) { try { LOG.info("Stopping Tor"); @@ -510,8 +518,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } @Override - public boolean isRunning() { - return running && connectionStatus.isConnected(); + public State getState() { + return state.getState(); } @Override @@ -527,7 +535,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void poll(Collection> properties) { - if (!isRunning()) return; + if (getState() != AVAILABLE) return; backoff.increment(); for (Pair p : properties) { connect(p.getFirst(), p.getSecond()); @@ -546,7 +554,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public DuplexTransportConnection createConnection(TransportProperties p) { - if (!isRunning()) return null; + if (getState() != AVAILABLE) return null; String bestOnion = null; String onion2 = p.get(PROP_ONION_V2); String onion3 = p.get(PROP_ONION_V3); @@ -663,10 +671,10 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void circuitStatus(String status, String id, String path) { if (status.equals("BUILT") && - connectionStatus.getAndSetCircuitBuilt()) { + state.getAndSetCircuitBuilt()) { + callback.pluginStateChanged(getState()); LOG.info("First circuit built"); backoff.reset(); - if (isRunning()) callback.transportEnabled(); } } @@ -697,9 +705,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { public void message(String severity, String msg) { if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg); if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) { - connectionStatus.setBootstrapped(); + state.setBootstrapped(); + callback.pluginStateChanged(getState()); backoff.reset(); - if (isRunning()) callback.transportEnabled(); } } @@ -746,7 +754,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private void updateConnectionStatus(NetworkStatus status, boolean charging) { connectionStatusExecutor.execute(() -> { - if (!running) return; + if (!state.isRunning()) return; boolean online = status.isConnected(); boolean wifi = status.isWifi(); String country = locationUtils.getCurrentCountry(); @@ -762,7 +770,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { if (LOG.isLoggable(INFO)) { LOG.info("Online: " + online + ", wifi: " + wifi); - if ("".equals(country)) LOG.info("Country code unknown"); + if (country.isEmpty()) LOG.info("Country code unknown"); else LOG.info("Country code: " + country); LOG.info("Charging: " + charging); } @@ -810,33 +818,73 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } private void enableConnectionPadding(boolean enable) throws IOException { - if (!running) return; + if (!state.isRunning()) return; controlConnection.setConf("ConnectionPadding", enable ? "1" : "0"); } - private static class ConnectionStatus { + @ThreadSafe + @NotNullByDefault + protected static class PluginState { - // All of the following are locking: this - private boolean networkEnabled = false; - private boolean bootstrapped = false, circuitBuilt = false; + @GuardedBy("this") + private boolean started = false, + stopped = false, + networkInitialised = false, + networkEnabled = false, + bootstrapped = false, + circuitBuilt = false; - private synchronized void setBootstrapped() { + @GuardedBy("this") + @Nullable + private ServerSocket serverSocket = null; + + synchronized void setStarted() { + started = true; + } + + synchronized boolean isRunning() { + return started && !stopped; + } + + @Nullable + synchronized ServerSocket setStopped() { + stopped = true; + ServerSocket ss = serverSocket; + serverSocket = null; + return ss; + } + + synchronized void setBootstrapped() { bootstrapped = true; } - private synchronized boolean getAndSetCircuitBuilt() { + synchronized boolean getAndSetCircuitBuilt() { boolean firstCircuit = !circuitBuilt; circuitBuilt = true; return firstCircuit; } - private synchronized void enableNetwork(boolean enable) { + synchronized void enableNetwork(boolean enable) { + networkInitialised = true; networkEnabled = enable; if (!enable) circuitBuilt = false; } - private synchronized boolean isConnected() { - return networkEnabled && bootstrapped && circuitBuilt; + synchronized boolean setServerSocket(ServerSocket ss) { + if (stopped || serverSocket != null) return false; + serverSocket = ss; + return true; + } + + synchronized void clearServerSocket(ServerSocket ss) { + if (serverSocket == ss) serverSocket = null; + } + + synchronized State getState() { + if (!started || stopped) return DISABLED; + if (!networkInitialised) return ENABLING; + if (!networkEnabled) return UNAVAILABLE; + return bootstrapped && circuitBuilt ? AVAILABLE : ENABLING; } } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/tcp/LanTcpPluginTest.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/tcp/LanTcpPluginTest.java index 12ccaf1e8..7b175f805 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/plugin/tcp/LanTcpPluginTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/tcp/LanTcpPluginTest.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.Backoff; +import org.briarproject.bramble.api.plugin.Plugin.State; import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.TransportConnectionReader; import org.briarproject.bramble.api.plugin.TransportConnectionWriter; @@ -327,6 +328,7 @@ public class LanTcpPluginTest extends BrambleTestCase { assertEquals(0, comparator.compare(linkLocal, linkLocal)); } + @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean systemHasLocalIpv4Address() throws Exception { for (NetworkInterface i : list(getNetworkInterfaces())) { for (InetAddress a : list(i.getInetAddresses())) { @@ -365,11 +367,7 @@ public class LanTcpPluginTest extends BrambleTestCase { } @Override - public void transportEnabled() { - } - - @Override - public void transportDisabled() { + public void pluginStateChanged(State newState) { } @Override diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java index 16a0d0f31..9b115ad08 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.ConnectionHandler; import org.briarproject.bramble.api.plugin.PluginCallback; @@ -23,9 +24,16 @@ import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; + import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; +import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING; +import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -44,8 +52,8 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private final PluginCallback callback; private final int maxLatency; private final AtomicBoolean used = new AtomicBoolean(false); + private final PluginState state = new PluginState(); - private volatile boolean running = false; private volatile Modem modem = null; ModemPlugin(ModemFactory modemFactory, SerialPortList serialPortList, @@ -75,6 +83,8 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { @Override public void start() throws PluginException { if (used.getAndSet(true)) throw new IllegalStateException(); + state.setStarted(); + callback.pluginStateChanged(getState()); for (String portName : serialPortList.getPortNames()) { if (LOG.isLoggable(INFO)) LOG.info("Trying to initialise modem on " + portName); @@ -83,18 +93,23 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { if (!modem.start()) continue; if (LOG.isLoggable(INFO)) LOG.info("Initialised modem on " + portName); - running = true; + state.setInitialised(); + callback.pluginStateChanged(getState()); return; } catch (IOException e) { logException(LOG, WARNING, e); } } + LOG.warning("Failed to initialised modem"); + state.setFailed(); + callback.pluginStateChanged(getState()); throw new PluginException(); } @Override public void stop() { - running = false; + state.setStopped(); + callback.pluginStateChanged(getState()); if (modem != null) { try { modem.stop(); @@ -105,8 +120,8 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { } @Override - public boolean isRunning() { - return running; + public State getState() { + return state.getState(); } @Override @@ -125,8 +140,8 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { throw new UnsupportedOperationException(); } - private boolean resetModem() { - if (!running) return false; + private void resetModem() { + if (getState() != AVAILABLE) return; for (String portName : serialPortList.getPortNames()) { if (LOG.isLoggable(INFO)) LOG.info("Trying to initialise modem on " + portName); @@ -135,18 +150,19 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { if (!modem.start()) continue; if (LOG.isLoggable(INFO)) LOG.info("Initialised modem on " + portName); - return true; + return; } catch (IOException e) { logException(LOG, WARNING, e); } } - running = false; - return false; + LOG.warning("Failed to initialise modem"); + state.setFailed(); + callback.pluginStateChanged(getState()); } @Override public DuplexTransportConnection createConnection(TransportProperties p) { - if (!running) return null; + if (getState() != AVAILABLE) return null; // Get the ISO 3166 code for the caller's country String fromIso = callback.getLocalProperties().get("iso3166"); if (isNullOrEmpty(fromIso)) return null; @@ -232,4 +248,37 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { if (exception) resetModem(); } } + + @ThreadSafe + @NotNullByDefault + private static class PluginState { + + @GuardedBy("this") + private boolean started = false, + stopped = false, + initialised = false, + failed = false; + + private synchronized void setStarted() { + started = true; + } + + private synchronized void setStopped() { + stopped = true; + } + + private synchronized void setInitialised() { + initialised = true; + } + + private synchronized void setFailed() { + failed = true; + } + + private State getState() { + if (!started || stopped) return DISABLED; + if (failed) return UNAVAILABLE; + return initialised ? AVAILABLE : ENABLING; + } + } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java index 4af7eded3..0cb33503a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java @@ -30,6 +30,7 @@ import static java.util.concurrent.TimeUnit.DAYS; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE; import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; @@ -176,7 +177,7 @@ public class NavDrawerControllerImpl extends DbControllerImpl @Override public boolean isTransportRunning(TransportId transportId) { Plugin plugin = pluginManager.getPlugin(transportId); - return plugin != null && plugin.isRunning(); + return plugin != null && plugin.getState() == AVAILABLE; } } From 850ad18a36b916d46fbda8f91db247ba9c947420 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 15 Jan 2020 17:40:20 +0000 Subject: [PATCH 03/19] Check that server sockets are closed as expected. --- .../briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java | 2 +- .../bramble/plugin/bluetooth/BluetoothPlugin.java | 4 ---- .../java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java | 1 - .../java/org/briarproject/bramble/plugin/tor/TorPlugin.java | 1 - 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java index 00ea54c03..3df2d1721 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java @@ -154,7 +154,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { } else if (addrs.isEmpty()) { LOG.info("Not connected to wifi"); socketFactory = SocketFactory.getDefault(); - // TODO: Check that socket was closed when interface went down + // Server socket was closed when wifi interface went down } else { LOG.info("Connected to wifi"); socketFactory = getSocketFactory(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index 8df0d40f6..79e86584f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -132,9 +132,6 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { void onAdapterDisabled() { LOG.info("Bluetooth disabled"); - // TODO: Is this needed, or will the socket be closed automatically? - SS ss = state.clearServerSocket(); - tryToClose(ss); connectionLimiter.allConnectionsClosed(); callback.pluginStateChanged(getState()); } @@ -237,7 +234,6 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { conn = acceptConnection(ss); } catch (IOException e) { // This is expected when the socket is closed - // TODO: Check that this is logged at shutdown/when BT disabled LOG.info("Server socket closed"); state.clearServerSocket(); return; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java index 85bd9e468..ca99a745f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java @@ -174,7 +174,6 @@ abstract class TcpPlugin implements DuplexPlugin { s.setSoTimeout(socketTimeout); } catch (IOException e) { // This is expected when the server socket is closed - // TODO: Check that this is logged at shutdown/when LAN disabled LOG.info("Server socket closed"); state.clearServerSocket(ss); callback.pluginStateChanged(getState()); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index d973075f0..0ffa6ead9 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -463,7 +463,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { s.setSoTimeout(socketTimeout); } catch (IOException e) { // This is expected when the server socket is closed - // TODO: Check that this is logged at shutdown LOG.info("Server socket closed"); state.clearServerSocket(ss); return; From 1e7a1670dd8026d09a11cf21087f675e5533a8f1 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 15 Jan 2020 17:48:12 +0000 Subject: [PATCH 04/19] If adapter is disabled, forget that we enabled it. --- .../bramble/plugin/bluetooth/AndroidBluetoothPlugin.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java index 839dee2c6..2c6e37051 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/bluetooth/AndroidBluetoothPlugin.java @@ -146,6 +146,12 @@ class AndroidBluetoothPlugin extends BluetoothPlugin { wasEnabledByUs = true; } + @Override + void onAdapterDisabled() { + super.onAdapterDisabled(); + wasEnabledByUs = false; + } + @Override @Nullable String getBluetoothAddress() { From 32288c376b688809f6795746b29e451faaf1fed3 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 09:47:49 +0000 Subject: [PATCH 05/19] Update tests. --- .../org/briarproject/bramble/plugin/tor/BridgeTest.java | 5 +++-- .../bramble/plugin/tor/TestPluginCallback.java | 7 ++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java index b0f47bd86..5947a8265 100644 --- a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java +++ b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java @@ -32,6 +32,7 @@ import javax.net.SocketFactory; import static java.util.Collections.singletonList; import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled; @@ -141,10 +142,10 @@ public class BridgeTest extends BrambleTestCase { plugin.start(); long start = clock.currentTimeMillis(); while (clock.currentTimeMillis() - start < TIMEOUT) { - if (plugin.isRunning()) return; + if (plugin.getState() == AVAILABLE) return; clock.sleep(500); } - if (!plugin.isRunning()) { + if (plugin.getState() != AVAILABLE) { fail("Could not connect to Tor within timeout."); } } finally { diff --git a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/TestPluginCallback.java b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/TestPluginCallback.java index e8b8121da..aeb5a9ee9 100644 --- a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/TestPluginCallback.java +++ b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/TestPluginCallback.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.plugin.tor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Plugin.State; import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.TransportConnectionReader; import org.briarproject.bramble.api.plugin.TransportConnectionWriter; @@ -30,11 +31,7 @@ public class TestPluginCallback implements PluginCallback { } @Override - public void transportEnabled() { - } - - @Override - public void transportDisabled() { + public void pluginStateChanged(State state) { } @Override From c7565cb93e377d313029ceb33c38a725683f12ba Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 09:58:12 +0000 Subject: [PATCH 06/19] Rename available/unavailable states. --- .../plugin/tcp/AndroidLanTcpPlugin.java | 10 +++++----- .../bramble/api/plugin/Plugin.java | 13 +++++------- .../bramble/plugin/PluginManagerImpl.java | 4 ++-- .../plugin/bluetooth/BluetoothPlugin.java | 20 +++++++++---------- .../bramble/plugin/file/FilePlugin.java | 6 +++--- .../bramble/plugin/tcp/TcpPlugin.java | 10 +++++----- .../bramble/plugin/tor/TorPlugin.java | 12 +++++------ .../bramble/plugin/modem/ModemPlugin.java | 12 +++++------ .../bramble/plugin/tor/BridgeTest.java | 6 +++--- .../navdrawer/NavDrawerControllerImpl.java | 4 ++-- 10 files changed, 47 insertions(+), 50 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java index 3df2d1721..e11133069 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java @@ -33,8 +33,8 @@ import static android.os.Build.VERSION.SDK_INT; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; -import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; +import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; @NotNullByDefault class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { @@ -141,7 +141,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { private void updateConnectionStatus() { connectionStatusExecutor.execute(() -> { State state = getState(); - if (state != AVAILABLE && state != UNAVAILABLE) return; + if (state != ACTIVE && state != INACTIVE) return; Collection addrs = getLocalIpAddresses(); if (addrs.contains(WIFI_AP_ADDRESS)) { LOG.info("Providing wifi hotspot"); @@ -150,7 +150,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { // make outgoing connections on API 21+ if another network // has internet access socketFactory = SocketFactory.getDefault(); - if (state == UNAVAILABLE) bind(); + if (state == INACTIVE) bind(); } else if (addrs.isEmpty()) { LOG.info("Not connected to wifi"); socketFactory = SocketFactory.getDefault(); @@ -158,7 +158,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { } else { LOG.info("Connected to wifi"); socketFactory = getSocketFactory(); - if (state == UNAVAILABLE) bind(); + if (state == INACTIVE) bind(); } }); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java index b26a37159..d0d9c5ae0 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java @@ -18,23 +18,20 @@ public interface Plugin { DISABLED, /** - * The plugin has been started, has not been stopped, is enabled by - * settings, but can't yet tell whether it can make or receive + * The plugin is being enabled and can't yet make or receive * connections. */ ENABLING, /** - * The plugin has been started, has not been stopped, is enabled by - * settings, and can make or receive connections. + * The plugin is enabled and can make or receive connections. */ - AVAILABLE, + ACTIVE, /** - * The plugin has been started, has not been stopped, is enabled by - * settings, but can't make or receive connections + * The plugin is enabled but can't make or receive connections */ - UNAVAILABLE + INACTIVE } /** diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java index b64fa054c..cb9a8e6a4 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java @@ -47,7 +47,7 @@ import static java.util.logging.Level.FINE; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; @@ -308,7 +308,7 @@ class PluginManagerImpl implements PluginManager, Service { LOG.info(id + " changed from state " + oldState + " to " + newState); } - if (newState == AVAILABLE) { + if (newState == ACTIVE) { if (!enabled.getAndSet(true)) eventBus.broadcast(new TransportEnabledEvent(id)); } else { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index 79e86584f..85f5fd157 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -49,9 +49,9 @@ import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENA import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID; import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; -import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -180,7 +180,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { private void bind() { ioExecutor.execute(() -> { - if (!shouldAllowContactConnections() || getState() != AVAILABLE) + if (!shouldAllowContactConnections() || getState() != ACTIVE) return; // Bind a server socket to accept connections from contacts SS ss; @@ -271,7 +271,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public void poll(Collection> properties) { - if (!shouldAllowContactConnections() || getState() != AVAILABLE) return; + if (!shouldAllowContactConnections() || getState() != ACTIVE) return; backoff.increment(); for (Pair p : properties) { connect(p.getFirst(), p.getSecond()); @@ -284,7 +284,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { String uuid = p.get(PROP_UUID); if (isNullOrEmpty(uuid)) return; ioExecutor.execute(() -> { - if (!shouldAllowContactConnections() || getState() != AVAILABLE) + if (!shouldAllowContactConnections() || getState() != ACTIVE) return; if (!connectionLimiter.canOpenContactConnection()) return; DuplexTransportConnection d = createConnection(p); @@ -329,7 +329,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public DuplexTransportConnection createConnection(TransportProperties p) { - if (!shouldAllowContactConnections() || getState() != AVAILABLE) + if (!shouldAllowContactConnections() || getState() != ACTIVE) return null; if (!connectionLimiter.canOpenContactConnection()) return null; String address = p.get(PROP_ADDRESS); @@ -349,7 +349,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public KeyAgreementListener createKeyAgreementListener(byte[] commitment) { - if (getState() != AVAILABLE) return null; + if (getState() != ACTIVE) return null; // No truncation necessary because COMMIT_LENGTH = 16 String uuid = UUID.nameUUIDFromBytes(commitment).toString(); if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid); @@ -361,7 +361,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { logException(LOG, WARNING, e); return null; } - if (getState() != AVAILABLE) { + if (getState() != ACTIVE) { tryToClose(ss); return null; } @@ -375,7 +375,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public DuplexTransportConnection createKeyAgreementConnection( byte[] commitment, BdfList descriptor) { - if (getState() != AVAILABLE) return null; + if (getState() != ACTIVE) return null; // No truncation necessary because COMMIT_LENGTH = 16 String uuid = UUID.nameUUIDFromBytes(commitment).toString(); DuplexTransportConnection conn; @@ -510,7 +510,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { synchronized State getState() { if (!started || stopped) return DISABLED; - return isAdapterEnabled() ? AVAILABLE : UNAVAILABLE; + return isAdapterEnabled() ? ACTIVE : INACTIVE; } } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/FilePlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/FilePlugin.java index d846fd2ae..8a2673a7a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/FilePlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/file/FilePlugin.java @@ -16,7 +16,7 @@ import java.util.logging.Logger; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.plugin.FileConstants.PROP_PATH; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -46,7 +46,7 @@ abstract class FilePlugin implements SimplexPlugin { @Override public TransportConnectionReader createReader(TransportProperties p) { - if (getState() != AVAILABLE) return null; + if (getState() != ACTIVE) return null; String path = p.get(PROP_PATH); if (isNullOrEmpty(path)) return null; try { @@ -61,7 +61,7 @@ abstract class FilePlugin implements SimplexPlugin { @Override public TransportConnectionWriter createWriter(TransportProperties p) { - if (getState() != AVAILABLE) return null; + if (getState() != ACTIVE) return null; String path = p.get(PROP_PATH); if (isNullOrEmpty(path)) return null; try { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java index ca99a745f..9904e65e6 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java @@ -43,9 +43,9 @@ import static java.util.Collections.list; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; -import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.util.IoUtils.tryToClose; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress; @@ -126,7 +126,7 @@ abstract class TcpPlugin implements DuplexPlugin { protected void bind() { bindExecutor.execute(() -> { - if (getState() != UNAVAILABLE) return; + if (getState() != INACTIVE) return; ServerSocket ss = null; for (InetSocketAddress addr : getLocalSocketAddresses()) { try { @@ -212,7 +212,7 @@ abstract class TcpPlugin implements DuplexPlugin { @Override public void poll(Collection> properties) { - if (getState() != AVAILABLE) return; + if (getState() != ACTIVE) return; backoff.increment(); for (Pair p : properties) { connect(p.getFirst(), p.getSecond()); @@ -369,7 +369,7 @@ abstract class TcpPlugin implements DuplexPlugin { synchronized State getState() { if (!started || stopped) return DISABLED; - return serverSocket == null ? UNAVAILABLE : AVAILABLE; + return serverSocket == null ? INACTIVE : ACTIVE; } } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 0ffa6ead9..1b09fcfb5 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -69,10 +69,10 @@ import static java.util.logging.Logger.getLogger; import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS; import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING; -import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.ID; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_MOBILE; @@ -534,7 +534,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void poll(Collection> properties) { - if (getState() != AVAILABLE) return; + if (getState() != ACTIVE) return; backoff.increment(); for (Pair p : properties) { connect(p.getFirst(), p.getSecond()); @@ -553,7 +553,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public DuplexTransportConnection createConnection(TransportProperties p) { - if (getState() != AVAILABLE) return null; + if (getState() != ACTIVE) return null; String bestOnion = null; String onion2 = p.get(PROP_ONION_V2); String onion3 = p.get(PROP_ONION_V3); @@ -882,8 +882,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { synchronized State getState() { if (!started || stopped) return DISABLED; if (!networkInitialised) return ENABLING; - if (!networkEnabled) return UNAVAILABLE; - return bootstrapped && circuitBuilt ? AVAILABLE : ENABLING; + if (!networkEnabled) return INACTIVE; + return bootstrapped && circuitBuilt ? ACTIVE : ENABLING; } } } diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java index 9b115ad08..aebf61fd6 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java @@ -30,10 +30,10 @@ import javax.annotation.concurrent.ThreadSafe; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING; -import static org.briarproject.bramble.api.plugin.Plugin.State.UNAVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -141,7 +141,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { } private void resetModem() { - if (getState() != AVAILABLE) return; + if (getState() != ACTIVE) return; for (String portName : serialPortList.getPortNames()) { if (LOG.isLoggable(INFO)) LOG.info("Trying to initialise modem on " + portName); @@ -162,7 +162,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { @Override public DuplexTransportConnection createConnection(TransportProperties p) { - if (getState() != AVAILABLE) return null; + if (getState() != ACTIVE) return null; // Get the ISO 3166 code for the caller's country String fromIso = callback.getLocalProperties().get("iso3166"); if (isNullOrEmpty(fromIso)) return null; @@ -277,8 +277,8 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private State getState() { if (!started || stopped) return DISABLED; - if (failed) return UNAVAILABLE; - return initialised ? AVAILABLE : ENABLING; + if (failed) return INACTIVE; + return initialised ? ACTIVE : ENABLING; } } } diff --git a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java index 5947a8265..7439321fd 100644 --- a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java +++ b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/BridgeTest.java @@ -32,7 +32,7 @@ import javax.net.SocketFactory; import static java.util.Collections.singletonList; import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled; @@ -142,10 +142,10 @@ public class BridgeTest extends BrambleTestCase { plugin.start(); long start = clock.currentTimeMillis(); while (clock.currentTimeMillis() - start < TIMEOUT) { - if (plugin.getState() == AVAILABLE) return; + if (plugin.getState() == ACTIVE) return; clock.sleep(500); } - if (plugin.getState() != AVAILABLE) { + if (plugin.getState() != ACTIVE) { fail("Could not connect to Tor within timeout."); } } finally { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java index 0cb33503a..a927fe409 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java @@ -30,7 +30,7 @@ import static java.util.concurrent.TimeUnit.DAYS; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.plugin.Plugin.State.AVAILABLE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE; import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; @@ -177,7 +177,7 @@ public class NavDrawerControllerImpl extends DbControllerImpl @Override public boolean isTransportRunning(TransportId transportId) { Plugin plugin = pluginManager.getPlugin(transportId); - return plugin != null && plugin.getState() == AVAILABLE; + return plugin != null && plugin.getState() == ACTIVE; } } From 6bce4b76d20e7a7102288bdb7e545f763b35dd03 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 11:05:02 +0000 Subject: [PATCH 07/19] Fix test expectations. --- .../bramble/plugin/modem/ModemPluginTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bramble-java/src/test/java/org/briarproject/bramble/plugin/modem/ModemPluginTest.java b/bramble-java/src/test/java/org/briarproject/bramble/plugin/modem/ModemPluginTest.java index df03d3abf..4e3ae0684 100644 --- a/bramble-java/src/test/java/org/briarproject/bramble/plugin/modem/ModemPluginTest.java +++ b/bramble-java/src/test/java/org/briarproject/bramble/plugin/modem/ModemPluginTest.java @@ -9,6 +9,8 @@ import org.junit.Test; import java.io.IOException; +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; +import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -33,6 +35,7 @@ public class ModemPluginTest extends BrambleMockTestCase { @Test public void testModemCreation() throws Exception { context.checking(new Expectations() {{ + oneOf(callback).pluginStateChanged(ENABLING); oneOf(serialPortList).getPortNames(); will(returnValue(new String[] {"foo", "bar", "baz"})); // First call to createModem() returns false @@ -50,6 +53,7 @@ public class ModemPluginTest extends BrambleMockTestCase { will(returnValue(modem)); oneOf(modem).start(); will(returnValue(true)); + oneOf(callback).pluginStateChanged(ACTIVE); }}); plugin.start(); @@ -65,12 +69,14 @@ public class ModemPluginTest extends BrambleMockTestCase { context.checking(new Expectations() {{ // start() + oneOf(callback).pluginStateChanged(ENABLING); oneOf(serialPortList).getPortNames(); will(returnValue(new String[] {"foo"})); oneOf(modemFactory).createModem(plugin, "foo"); will(returnValue(modem)); oneOf(modem).start(); will(returnValue(true)); + oneOf(callback).pluginStateChanged(ACTIVE); // createConnection() oneOf(callback).getLocalProperties(); will(returnValue(local)); @@ -93,12 +99,14 @@ public class ModemPluginTest extends BrambleMockTestCase { context.checking(new Expectations() {{ // start() + oneOf(callback).pluginStateChanged(ENABLING); oneOf(serialPortList).getPortNames(); will(returnValue(new String[] {"foo"})); oneOf(modemFactory).createModem(plugin, "foo"); will(returnValue(modem)); oneOf(modem).start(); will(returnValue(true)); + oneOf(callback).pluginStateChanged(ACTIVE); // createConnection() oneOf(callback).getLocalProperties(); will(returnValue(local)); @@ -121,12 +129,14 @@ public class ModemPluginTest extends BrambleMockTestCase { context.checking(new Expectations() {{ // start() + oneOf(callback).pluginStateChanged(ENABLING); oneOf(serialPortList).getPortNames(); will(returnValue(new String[] {"foo"})); oneOf(modemFactory).createModem(plugin, "foo"); will(returnValue(modem)); oneOf(modem).start(); will(returnValue(true)); + oneOf(callback).pluginStateChanged(ACTIVE); // createConnection() oneOf(callback).getLocalProperties(); will(returnValue(local)); From 1c98d8f12a58c644f679f01f625460dc3398b6f7 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 11:05:36 +0000 Subject: [PATCH 08/19] Add method for getting reason why plugin is disabled. --- .../bramble/api/plugin/Plugin.java | 17 ++ .../bramble/api/plugin/TorConstants.java | 4 + .../plugin/bluetooth/BluetoothPlugin.java | 5 + .../bramble/plugin/tcp/TcpPlugin.java | 5 + .../bramble/plugin/tor/TorPlugin.java | 181 ++++++++++++------ .../bramble/plugin/modem/ModemPlugin.java | 5 + 6 files changed, 163 insertions(+), 54 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java index d0d9c5ae0..b7247967c 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/Plugin.java @@ -34,6 +34,13 @@ public interface Plugin { INACTIVE } + /** + * Reason code returned by {@link #getReasonDisabled()} ()} to indicate + * that the plugin is disabled because it has not been started or has been + * stopped. + */ + int REASON_STARTING_STOPPING = 0; + /** * Returns the plugin's transport identifier. */ @@ -64,6 +71,16 @@ public interface Plugin { */ State getState(); + /** + * Returns an integer code indicating why the plugin is + * {@link State#DISABLED disabled}, or -1 if the plugin is not disabled. + *

+ * The codes used are plugin-specific, except the generic code + * {@link #REASON_STARTING_STOPPING}, which may be used by + * any plugin. + */ + int getReasonDisabled(); + /** * Returns true if the plugin should be polled periodically to attempt to * establish connections. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java index 6be7582a1..2d808eaa9 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java @@ -23,4 +23,8 @@ public interface TorConstants { int PREF_TOR_NETWORK_WITH_BRIDGES = 2; int PREF_TOR_NETWORK_NEVER = 3; + int REASON_USER = 1; + int REASON_BATTERY = 2; + int REASON_MOBILE_DATA = 3; + int REASON_COUNTRY_BLOCKED = 4; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index 85f5fd157..aef543c51 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -258,6 +258,11 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { return state.getState(); } + @Override + public int getReasonDisabled() { + return getState() == DISABLED ? REASON_STARTING_STOPPING : -1; + } + @Override public boolean shouldPoll() { return true; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java index 9904e65e6..60244e1e2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java @@ -199,6 +199,11 @@ abstract class TcpPlugin implements DuplexPlugin { return state.getState(); } + @Override + public int getReasonDisabled() { + return getState() == DISABLED ? REASON_STARTING_STOPPING : -1; + } + @Override public boolean shouldPoll() { return true; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 1b09fcfb5..a32eb7b2c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -57,6 +57,7 @@ import java.util.zip.ZipInputStream; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.ThreadSafe; import javax.net.SocketFactory; @@ -84,6 +85,10 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_ONLY_WHE import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V2; import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION_V3; +import static org.briarproject.bramble.api.plugin.TorConstants.REASON_BATTERY; +import static org.briarproject.bramble.api.plugin.TorConstants.REASON_COUNTRY_BLOCKED; +import static org.briarproject.bramble.api.plugin.TorConstants.REASON_MOBILE_DATA; +import static org.briarproject.bramble.api.plugin.TorConstants.REASON_USER; import static org.briarproject.bramble.plugin.tor.TorRendezvousCrypto.SEED_BYTES; import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.bramble.util.IoUtils.tryToClose; @@ -521,6 +526,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { return state.getState(); } + @Override + public int getReasonDisabled() { + return state.getReasonDisabled(); + } + @Override public boolean shouldPoll() { return true; @@ -754,62 +764,91 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { boolean charging) { connectionStatusExecutor.execute(() -> { if (!state.isRunning()) return; - boolean online = status.isConnected(); - boolean wifi = status.isWifi(); - String country = locationUtils.getCurrentCountry(); - boolean blocked = - circumventionProvider.isTorProbablyBlocked(country); - int network = settings.getInt(PREF_TOR_NETWORK, - PREF_TOR_NETWORK_AUTOMATIC); - boolean useMobile = settings.getBoolean(PREF_TOR_MOBILE, true); - boolean onlyWhenCharging = - settings.getBoolean(PREF_TOR_ONLY_WHEN_CHARGING, false); - boolean bridgesWork = circumventionProvider.doBridgesWork(country); - boolean automatic = network == PREF_TOR_NETWORK_AUTOMATIC; + NetworkConfig config = getNetworkConfig(status, charging); + state.setDisabledBySettings(config.disabledBySettings, + config.reasonDisabled); + callback.pluginStateChanged(getState()); + applyNetworkConfig(config); + }); + } - if (LOG.isLoggable(INFO)) { - LOG.info("Online: " + online + ", wifi: " + wifi); - if (country.isEmpty()) LOG.info("Country code unknown"); - else LOG.info("Country code: " + country); - LOG.info("Charging: " + charging); + private NetworkConfig getNetworkConfig(NetworkStatus status, + boolean charging) { + boolean online = status.isConnected(); + boolean wifi = status.isWifi(); + String country = locationUtils.getCurrentCountry(); + boolean blocked = circumventionProvider.isTorProbablyBlocked(country); + int network = + settings.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_AUTOMATIC); + boolean useMobile = settings.getBoolean(PREF_TOR_MOBILE, true); + boolean onlyWhenCharging = + settings.getBoolean(PREF_TOR_ONLY_WHEN_CHARGING, false); + boolean bridgesWork = circumventionProvider.doBridgesWork(country); + boolean automatic = network == PREF_TOR_NETWORK_AUTOMATIC; + + if (LOG.isLoggable(INFO)) { + LOG.info("Online: " + online + ", wifi: " + wifi); + if (country.isEmpty()) LOG.info("Country code unknown"); + else LOG.info("Country code: " + country); + LOG.info("Charging: " + charging); + } + + boolean enableNetwork = false, enableBridges = false; + boolean useMeek = false, enableConnectionPadding = false; + boolean disabledBySettings = false; + int reasonDisabled = REASON_STARTING_STOPPING; + + if (!online) { + LOG.info("Disabling network, device is offline"); + } else if (network == PREF_TOR_NETWORK_NEVER) { + LOG.info("Disabling network, user has disabled Tor"); + disabledBySettings = true; + reasonDisabled = REASON_USER; + } else if (!charging && onlyWhenCharging) { + LOG.info("Disabling network, device is on battery"); + disabledBySettings = true; + reasonDisabled = REASON_BATTERY; + } else if (!useMobile && !wifi) { + LOG.info("Disabling network, device is using mobile data"); + disabledBySettings = true; + reasonDisabled = REASON_MOBILE_DATA; + } else if (automatic && blocked && !bridgesWork) { + LOG.info("Disabling network, country is blocked"); + disabledBySettings = true; + reasonDisabled = REASON_COUNTRY_BLOCKED; + } else if (network == PREF_TOR_NETWORK_WITH_BRIDGES || + (automatic && bridgesWork)) { + if (circumventionProvider.needsMeek(country)) { + LOG.info("Enabling network, using meek bridges"); + enableBridges = true; + useMeek = true; + } else { + LOG.info("Enabling network, using obfs4 bridges"); + enableBridges = true; } + enableNetwork = true; + } else { + LOG.info("Enabling network, not using bridges"); + enableNetwork = true; + } + if (online && wifi && charging) { + LOG.info("Enabling connection padding"); + enableConnectionPadding = true; + } else { + LOG.info("Disabling connection padding"); + } + + return new NetworkConfig(enableNetwork, enableBridges, useMeek, + enableConnectionPadding, disabledBySettings, reasonDisabled); + } + + private void applyNetworkConfig(NetworkConfig config) { + connectionStatusExecutor.execute(() -> { try { - if (!online) { - LOG.info("Disabling network, device is offline"); - enableNetwork(false); - } else if (!charging && onlyWhenCharging) { - LOG.info("Disabling network, device is on battery"); - enableNetwork(false); - } else if (network == PREF_TOR_NETWORK_NEVER || - (!useMobile && !wifi)) { - LOG.info("Disabling network, device is using mobile data"); - enableNetwork(false); - } else if (automatic && blocked && !bridgesWork) { - LOG.info("Disabling network, country is blocked"); - enableNetwork(false); - } else if (network == PREF_TOR_NETWORK_WITH_BRIDGES || - (automatic && bridgesWork)) { - if (circumventionProvider.needsMeek(country)) { - LOG.info("Enabling network, using meek bridges"); - enableBridges(true, true); - } else { - LOG.info("Enabling network, using obfs4 bridges"); - enableBridges(true, false); - } - enableNetwork(true); - } else { - LOG.info("Enabling network, not using bridges"); - enableBridges(false, false); - enableNetwork(true); - } - if (online && wifi && charging) { - LOG.info("Enabling connection padding"); - enableConnectionPadding(true); - } else { - LOG.info("Disabling connection padding"); - enableConnectionPadding(false); - } + enableBridges(config.enableBridges, config.useMeek); + enableNetwork(config.enableNetwork); + enableConnectionPadding(config.enableConnectionPadding); } catch (IOException e) { logException(LOG, WARNING, e); } @@ -821,6 +860,26 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { controlConnection.setConf("ConnectionPadding", enable ? "1" : "0"); } + @Immutable + @NotNullByDefault + private static class NetworkConfig { + + private final boolean enableNetwork, enableBridges, useMeek; + private final boolean enableConnectionPadding, disabledBySettings; + private final int reasonDisabled; + + private NetworkConfig(boolean enableNetwork, boolean enableBridges, + boolean useMeek, boolean enableConnectionPadding, + boolean disabledBySettings, int reasonDisabled) { + this.enableNetwork = enableNetwork; + this.enableBridges = enableBridges; + this.useMeek = useMeek; + this.enableConnectionPadding = enableConnectionPadding; + this.disabledBySettings = disabledBySettings; + this.reasonDisabled = reasonDisabled; + } + } + @ThreadSafe @NotNullByDefault protected static class PluginState { @@ -831,7 +890,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { networkInitialised = false, networkEnabled = false, bootstrapped = false, - circuitBuilt = false; + circuitBuilt = false, + disabledBySettings = false; + + @GuardedBy("this") + private int reasonDisabled = REASON_STARTING_STOPPING; @GuardedBy("this") @Nullable @@ -869,6 +932,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { if (!enable) circuitBuilt = false; } + synchronized void setDisabledBySettings(boolean disabledBySettings, + int reasonDisabled) { + this.disabledBySettings = disabledBySettings; + this.reasonDisabled = reasonDisabled; + } + synchronized boolean setServerSocket(ServerSocket ss) { if (stopped || serverSocket != null) return false; serverSocket = ss; @@ -880,10 +949,14 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } synchronized State getState() { - if (!started || stopped) return DISABLED; + if (!started || stopped || disabledBySettings) return DISABLED; if (!networkInitialised) return ENABLING; if (!networkEnabled) return INACTIVE; return bootstrapped && circuitBuilt ? ACTIVE : ENABLING; } + + synchronized int getReasonDisabled() { + return getState() == DISABLED ? reasonDisabled : -1; + } } } diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java index aebf61fd6..89a11ff2f 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java @@ -124,6 +124,11 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { return state.getState(); } + @Override + public int getReasonDisabled() { + return getState() == DISABLED ? REASON_STARTING_STOPPING : -1; + } + @Override public boolean shouldPoll() { return false; From 10791aea49259002d5eaca1fe2cdf54e2f51d035 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 11:35:32 +0000 Subject: [PATCH 09/19] Ensure server socket is closed. --- .../plugin/tcp/AndroidLanTcpPlugin.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java index e11133069..473df98bd 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java @@ -32,9 +32,11 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.os.Build.VERSION.SDK_INT; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; +import static org.briarproject.bramble.util.IoUtils.tryToClose; @NotNullByDefault class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { @@ -140,8 +142,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { private void updateConnectionStatus() { connectionStatusExecutor.execute(() -> { - State state = getState(); - if (state != ACTIVE && state != INACTIVE) return; + State s = getState(); + if (s != ACTIVE && s != INACTIVE) return; Collection addrs = getLocalIpAddresses(); if (addrs.contains(WIFI_AP_ADDRESS)) { LOG.info("Providing wifi hotspot"); @@ -150,15 +152,21 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { // make outgoing connections on API 21+ if another network // has internet access socketFactory = SocketFactory.getDefault(); - if (state == INACTIVE) bind(); + if (s == INACTIVE) bind(); } else if (addrs.isEmpty()) { LOG.info("Not connected to wifi"); socketFactory = SocketFactory.getDefault(); - // Server socket was closed when wifi interface went down + // Server socket may not have been closed automatically when + // interface was taken down. Socket will be cleared and state + // updated in acceptContactConnections() + if (s == ACTIVE) { + LOG.info("Closing server socket"); + tryToClose(state.getServerSocket(), LOG, WARNING); + } } else { LOG.info("Connected to wifi"); socketFactory = getSocketFactory(); - if (state == INACTIVE) bind(); + if (s == INACTIVE) bind(); } }); } From c6981fb2433ada5518d33c355372421c0c3191e6 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 11:54:28 +0000 Subject: [PATCH 10/19] Add TransportStateEvent, rename existing events. --- ...edEvent.java => TransportActiveEvent.java} | 8 +++-- ...Event.java => TransportInactiveEvent.java} | 8 +++-- .../api/plugin/event/TransportStateEvent.java | 32 +++++++++++++++++++ .../bramble/plugin/PluginManagerImpl.java | 15 ++++----- .../bramble/plugin/PollerImpl.java | 16 +++++----- .../rendezvous/RendezvousPollerImpl.java | 12 +++---- .../bramble/reporting/DevReporterImpl.java | 6 ++-- .../bramble/plugin/PollerImplTest.java | 18 +++++------ .../rendezvous/RendezvousPollerImplTest.java | 30 ++++++++--------- .../navdrawer/NavDrawerControllerImpl.java | 16 +++++----- .../briar/feed/FeedManagerImpl.java | 6 ++-- 11 files changed, 101 insertions(+), 66 deletions(-) rename bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/{TransportDisabledEvent.java => TransportActiveEvent.java} (64%) rename bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/{TransportEnabledEvent.java => TransportInactiveEvent.java} (64%) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportStateEvent.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportDisabledEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportActiveEvent.java similarity index 64% rename from bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportDisabledEvent.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportActiveEvent.java index 1d415ca9f..de9c49c90 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportDisabledEvent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportActiveEvent.java @@ -2,20 +2,22 @@ package org.briarproject.bramble.api.plugin.event; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Plugin.State; import org.briarproject.bramble.api.plugin.TransportId; import javax.annotation.concurrent.Immutable; /** - * An event that is broadcast when a transport is disabled. + * An event that is broadcast when a plugin enters the {@link State#ACTIVE} + * state. */ @Immutable @NotNullByDefault -public class TransportDisabledEvent extends Event { +public class TransportActiveEvent extends Event { private final TransportId transportId; - public TransportDisabledEvent(TransportId transportId) { + public TransportActiveEvent(TransportId transportId) { this.transportId = transportId; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportEnabledEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportInactiveEvent.java similarity index 64% rename from bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportEnabledEvent.java rename to bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportInactiveEvent.java index 7064c9b9a..e2167c0f5 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportEnabledEvent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportInactiveEvent.java @@ -2,20 +2,22 @@ package org.briarproject.bramble.api.plugin.event; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Plugin.State; import org.briarproject.bramble.api.plugin.TransportId; import javax.annotation.concurrent.Immutable; /** - * An event that is broadcast when a transport is enabled. + * An event that is broadcast when a plugin leaves the {@link State#ACTIVE} + * state. */ @Immutable @NotNullByDefault -public class TransportEnabledEvent extends Event { +public class TransportInactiveEvent extends Event { private final TransportId transportId; - public TransportEnabledEvent(TransportId transportId) { + public TransportInactiveEvent(TransportId transportId) { this.transportId = transportId; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportStateEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportStateEvent.java new file mode 100644 index 000000000..376b5303f --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/event/TransportStateEvent.java @@ -0,0 +1,32 @@ +package org.briarproject.bramble.api.plugin.event; + +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.Plugin.State; +import org.briarproject.bramble.api.plugin.TransportId; + +import javax.annotation.concurrent.Immutable; + +/** + * An event that is broadcast when the {@link State state} of a plugin changes. + */ +@Immutable +@NotNullByDefault +public class TransportStateEvent extends Event { + + private final TransportId transportId; + private final State state; + + public TransportStateEvent(TransportId transportId, State state) { + this.transportId = transportId; + this.state = state; + } + + public TransportId getTransportId() { + return transportId; + } + + public State getState() { + return state; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java index cb9a8e6a4..ca25d3d3b 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java @@ -19,8 +19,9 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; -import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent; -import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportStateEvent; import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; import org.briarproject.bramble.api.properties.TransportProperties; @@ -256,7 +257,6 @@ class PluginManagerImpl implements PluginManager, Service { private final TransportId id; private final AtomicReference state = new AtomicReference<>(DISABLED); - private final AtomicBoolean enabled = new AtomicBoolean(false); private Callback(TransportId id) { this.id = id; @@ -308,12 +308,11 @@ class PluginManagerImpl implements PluginManager, Service { LOG.info(id + " changed from state " + oldState + " to " + newState); } + eventBus.broadcast(new TransportStateEvent(id, newState)); if (newState == ACTIVE) { - if (!enabled.getAndSet(true)) - eventBus.broadcast(new TransportEnabledEvent(id)); - } else { - if (enabled.getAndSet(false)) - eventBus.broadcast(new TransportDisabledEvent(id)); + eventBus.broadcast(new TransportActiveEvent(id)); + } else if (oldState == ACTIVE) { + eventBus.broadcast(new TransportInactiveEvent(id)); } } else { // TODO: Remove diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PollerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PollerImpl.java index 256bf215e..3a4f51c8d 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PollerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PollerImpl.java @@ -20,8 +20,8 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent; import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent; -import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent; -import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent; import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; @@ -106,13 +106,13 @@ class PollerImpl implements Poller, EventListener { ConnectionOpenedEvent c = (ConnectionOpenedEvent) e; // Reschedule polling, the polling interval may have decreased reschedule(c.getTransportId()); - } else if (e instanceof TransportEnabledEvent) { - TransportEnabledEvent t = (TransportEnabledEvent) e; - // Poll the newly enabled transport + } else if (e instanceof TransportActiveEvent) { + TransportActiveEvent t = (TransportActiveEvent) e; + // Poll the newly activated transport pollNow(t.getTransportId()); - } else if (e instanceof TransportDisabledEvent) { - TransportDisabledEvent t = (TransportDisabledEvent) e; - // Cancel polling for the disabled transport + } else if (e instanceof TransportInactiveEvent) { + TransportInactiveEvent t = (TransportInactiveEvent) e; + // Cancel polling for the deactivated transport cancel(t.getTransportId()); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java index d16317bff..4bce3d661 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/rendezvous/RendezvousPollerImpl.java @@ -31,8 +31,8 @@ import org.briarproject.bramble.api.plugin.TransportConnectionWriter; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; -import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent; -import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.rendezvous.KeyMaterialSource; import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint; @@ -269,11 +269,11 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { } else if (e instanceof PendingContactRemovedEvent) { PendingContactRemovedEvent p = (PendingContactRemovedEvent) e; removePendingContactAsync(p.getId()); - } else if (e instanceof TransportEnabledEvent) { - TransportEnabledEvent t = (TransportEnabledEvent) e; + } else if (e instanceof TransportActiveEvent) { + TransportActiveEvent t = (TransportActiveEvent) e; addTransportAsync(t.getTransportId()); - } else if (e instanceof TransportDisabledEvent) { - TransportDisabledEvent t = (TransportDisabledEvent) e; + } else if (e instanceof TransportInactiveEvent) { + TransportInactiveEvent t = (TransportInactiveEvent) e; removeTransportAsync(t.getTransportId()); } else if (e instanceof RendezvousConnectionOpenedEvent) { RendezvousConnectionOpenedEvent r = diff --git a/bramble-core/src/main/java/org/briarproject/bramble/reporting/DevReporterImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/reporting/DevReporterImpl.java index f03d4f730..228569fa2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/reporting/DevReporterImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/reporting/DevReporterImpl.java @@ -6,7 +6,7 @@ import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TorConstants; -import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; import org.briarproject.bramble.api.reporting.DevConfig; import org.briarproject.bramble.api.reporting.DevReporter; import org.briarproject.bramble.util.IoUtils; @@ -92,8 +92,8 @@ class DevReporterImpl implements DevReporter, EventListener { @Override public void eventOccurred(Event e) { - if (e instanceof TransportEnabledEvent) { - TransportEnabledEvent t = (TransportEnabledEvent) e; + if (e instanceof TransportActiveEvent) { + TransportActiveEvent t = (TransportActiveEvent) e; if (t.getTransportId().equals(TorConstants.ID)) ioExecutor.execute(this::sendReports); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/PollerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/PollerImplTest.java index 255635a13..2cca5be44 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/plugin/PollerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/PollerImplTest.java @@ -13,8 +13,8 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent; import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent; -import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent; -import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent; import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; @@ -322,7 +322,7 @@ public class PollerImplTest extends BrambleMockTestCase { } @Test - public void testPollsOnTransportEnabled() throws Exception { + public void testPollsOnTransportActivated() throws Exception { DuplexPlugin plugin = context.mock(DuplexPlugin.class); context.checking(new Expectations() {{ @@ -361,7 +361,7 @@ public class PollerImplTest extends BrambleMockTestCase { pairOf(equal(properties), any(ConnectionHandler.class))))); }}); - poller.eventOccurred(new TransportEnabledEvent(transportId)); + poller.eventOccurred(new TransportActiveEvent(transportId)); } @Test @@ -402,11 +402,11 @@ public class PollerImplTest extends BrambleMockTestCase { // All contacts are connected, so don't poll the plugin }}); - poller.eventOccurred(new TransportEnabledEvent(transportId)); + poller.eventOccurred(new TransportActiveEvent(transportId)); } @Test - public void testCancelsPollingOnTransportDisabled() { + public void testCancelsPollingOnTransportDeactivated() { Plugin plugin = context.mock(Plugin.class); context.checking(new Expectations() {{ @@ -424,11 +424,11 @@ public class PollerImplTest extends BrambleMockTestCase { oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L), with(MILLISECONDS)); will(returnValue(future)); - // The plugin is disabled before the task runs - cancel the task + // The plugin is deactivated before the task runs - cancel the task oneOf(future).cancel(false); }}); - poller.eventOccurred(new TransportEnabledEvent(transportId)); - poller.eventOccurred(new TransportDisabledEvent(transportId)); + poller.eventOccurred(new TransportActiveEvent(transportId)); + poller.eventOccurred(new TransportInactiveEvent(transportId)); } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/rendezvous/RendezvousPollerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/rendezvous/RendezvousPollerImplTest.java index 0f65d9adf..2232b7c0e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/rendezvous/RendezvousPollerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/rendezvous/RendezvousPollerImplTest.java @@ -17,8 +17,8 @@ import org.briarproject.bramble.api.plugin.ConnectionManager; import org.briarproject.bramble.api.plugin.PluginManager; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; -import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent; -import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.rendezvous.KeyMaterialSource; import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint; @@ -178,10 +178,10 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { rendezvousPoller.startService(); context.assertIsSatisfied(); - // Enable the transport - no endpoints should be created yet + // Activate the transport - no endpoints should be created yet expectGetPlugin(); - rendezvousPoller.eventOccurred(new TransportEnabledEvent(transportId)); + rendezvousPoller.eventOccurred(new TransportActiveEvent(transportId)); context.assertIsSatisfied(); // Add the pending contact - endpoint should be created and polled @@ -212,8 +212,8 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { new PendingContactRemovedEvent(pendingContact.getId())); context.assertIsSatisfied(); - // Disable the transport - endpoint is already closed - rendezvousPoller.eventOccurred(new TransportDisabledEvent(transportId)); + // Deactivate the transport - endpoint is already closed + rendezvousPoller.eventOccurred(new TransportInactiveEvent(transportId)); } @Test @@ -230,10 +230,10 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { rendezvousPoller.startService(); context.assertIsSatisfied(); - // Enable the transport - no endpoints should be created yet + // Activate the transport - no endpoints should be created yet expectGetPlugin(); - rendezvousPoller.eventOccurred(new TransportEnabledEvent(transportId)); + rendezvousPoller.eventOccurred(new TransportActiveEvent(transportId)); context.assertIsSatisfied(); // Add the pending contact - endpoint should be created and polled @@ -269,12 +269,12 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { new PendingContactRemovedEvent(pendingContact.getId())); context.assertIsSatisfied(); - // Disable the transport - endpoint is already closed - rendezvousPoller.eventOccurred(new TransportDisabledEvent(transportId)); + // Deactivate the transport - endpoint is already closed + rendezvousPoller.eventOccurred(new TransportInactiveEvent(transportId)); } @Test - public void testCreatesAndClosesEndpointsWhenTransportIsEnabledAndDisabled() + public void testCreatesAndClosesEndpointsWhenTransportIsActivatedAndDeactivated() throws Exception { long beforeExpiry = pendingContact.getTimestamp(); @@ -292,19 +292,19 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase { new PendingContactAddedEvent(pendingContact)); context.assertIsSatisfied(); - // Enable the transport - endpoint should be created + // Activate the transport - endpoint should be created expectGetPlugin(); expectCreateEndpoint(); expectStateChangedEvent(WAITING_FOR_CONNECTION); - rendezvousPoller.eventOccurred(new TransportEnabledEvent(transportId)); + rendezvousPoller.eventOccurred(new TransportActiveEvent(transportId)); context.assertIsSatisfied(); - // Disable the transport - endpoint should be closed + // Deactivate the transport - endpoint should be closed expectCloseEndpoint(); expectStateChangedEvent(OFFLINE); - rendezvousPoller.eventOccurred(new TransportDisabledEvent(transportId)); + rendezvousPoller.eventOccurred(new TransportInactiveEvent(transportId)); context.assertIsSatisfied(); // Remove the pending contact - endpoint is already closed diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java index a927fe409..b3488804e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerControllerImpl.java @@ -14,8 +14,8 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.Plugin; import org.briarproject.bramble.api.plugin.PluginManager; import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent; -import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent; import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.SettingsManager; import org.briarproject.briar.android.controller.DbControllerImpl; @@ -86,16 +86,16 @@ public class NavDrawerControllerImpl extends DbControllerImpl @Override public void eventOccurred(Event e) { - if (e instanceof TransportEnabledEvent) { - TransportId id = ((TransportEnabledEvent) e).getTransportId(); + if (e instanceof TransportActiveEvent) { + TransportId id = ((TransportActiveEvent) e).getTransportId(); if (LOG.isLoggable(INFO)) { - LOG.info("TransportEnabledEvent: " + id.getString()); + LOG.info("TransportActiveEvent: " + id.getString()); } listener.stateUpdate(id, true); - } else if (e instanceof TransportDisabledEvent) { - TransportId id = ((TransportDisabledEvent) e).getTransportId(); + } else if (e instanceof TransportInactiveEvent) { + TransportId id = ((TransportInactiveEvent) e).getTransportId(); if (LOG.isLoggable(INFO)) { - LOG.info("TransportDisabledEvent: " + id.getString()); + LOG.info("TransportInactiveEvent: " + id.getString()); } listener.stateUpdate(id, false); } diff --git a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java index 04350c8a6..b7dfa5783 100644 --- a/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/feed/FeedManagerImpl.java @@ -24,7 +24,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TorConstants; import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.system.Clock; @@ -120,8 +120,8 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook, @Override public void eventOccurred(Event e) { - if (e instanceof TransportEnabledEvent) { - TransportId t = ((TransportEnabledEvent) e).getTransportId(); + if (e instanceof TransportActiveEvent) { + TransportId t = ((TransportActiveEvent) e).getTransportId(); if (t.equals(TorConstants.ID)) { startFeedExecutor(); } From 549cf4e2becabe703a82822cccf2562f892697cc Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 12:38:03 +0000 Subject: [PATCH 11/19] Move to enabling state earlier in Tor startup. --- .../bramble/plugin/tor/AndroidTorPlugin.java | 2 +- .../bramble/plugin/tor/TorPlugin.java | 23 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java index 10ac8e788..be7e4ee62 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java @@ -74,7 +74,7 @@ class AndroidTorPlugin extends TorPlugin { @Override protected void enableNetwork(boolean enable) throws IOException { - if (!state.isRunning()) return; + if (!state.isTorRunning()) return; if (enable) wakeLock.acquire(); super.enableNetwork(enable); if (!enable) wakeLock.release(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index a32eb7b2c..2ff626831 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -193,6 +193,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void start() throws PluginException { if (used.getAndSet(true)) throw new IllegalStateException(); + state.setStarted(); + callback.pluginStateChanged(getState()); if (!torDirectory.exists()) { if (!torDirectory.mkdirs()) { LOG.warning("Could not create Tor directory."); @@ -280,8 +282,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } catch (IOException e) { throw new PluginException(e); } - state.setStarted(); - callback.pluginStateChanged(getState()); + state.setTorStarted(); // Check whether we're online updateConnectionStatus(networkManager.getNetworkStatus(), batteryManager.isCharging()); @@ -423,7 +424,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } private void publishHiddenService(String port) { - if (!state.isRunning()) return; + if (!state.isTorRunning()) return; LOG.info("Creating hidden service"); String privKey = settings.get(HS_PRIVKEY); Map portLines = singletonMap(80, "127.0.0.1:" + port); @@ -479,7 +480,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } protected void enableNetwork(boolean enable) throws IOException { - if (!state.isRunning()) return; + if (!state.isTorRunning()) return; state.enableNetwork(enable); callback.pluginStateChanged(getState()); controlConnection.setConf("DisableNetwork", enable ? "0" : "1"); @@ -763,7 +764,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private void updateConnectionStatus(NetworkStatus status, boolean charging) { connectionStatusExecutor.execute(() -> { - if (!state.isRunning()) return; + if (!state.isTorRunning()) return; NetworkConfig config = getNetworkConfig(status, charging); state.setDisabledBySettings(config.disabledBySettings, config.reasonDisabled); @@ -856,7 +857,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } private void enableConnectionPadding(boolean enable) throws IOException { - if (!state.isRunning()) return; + if (!state.isTorRunning()) return; controlConnection.setConf("ConnectionPadding", enable ? "1" : "0"); } @@ -887,6 +888,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @GuardedBy("this") private boolean started = false, stopped = false, + torStarted = false, networkInitialised = false, networkEnabled = false, bootstrapped = false, @@ -904,8 +906,13 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { started = true; } - synchronized boolean isRunning() { - return started && !stopped; + synchronized void setTorStarted() { + torStarted = true; + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + synchronized boolean isTorRunning() { + return torStarted && !stopped; } @Nullable From 0aada896254b7a0f3e05dbea6cf92afaed181e22 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 13:01:41 +0000 Subject: [PATCH 12/19] Reset backoff before notifying of new state. The new state may cause the poller to poll the plugin. Let's avoid a race between updating and querying the polling interval. --- .../bramble/plugin/bluetooth/BluetoothPlugin.java | 2 +- .../org/briarproject/bramble/plugin/tcp/TcpPlugin.java | 2 +- .../org/briarproject/bramble/plugin/tor/TorPlugin.java | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index aef543c51..bce2dd41f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -233,7 +233,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { try { conn = acceptConnection(ss); } catch (IOException e) { - // This is expected when the socket is closed + // This is expected when the server socket is closed LOG.info("Server socket closed"); state.clearServerSocket(); return; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java index 60244e1e2..3e0ebb65d 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java @@ -152,9 +152,9 @@ abstract class TcpPlugin implements DuplexPlugin { InetSocketAddress local = (InetSocketAddress) ss.getLocalSocketAddress(); setLocalSocketAddress(local); - callback.pluginStateChanged(getState()); if (LOG.isLoggable(INFO)) LOG.info("Listening on " + scrubSocketAddress(local)); + callback.pluginStateChanged(getState()); acceptContactConnections(ss); }); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 2ff626831..dc7e495e8 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -652,8 +652,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { new TorTransportConnection(this, s)); } } catch (IOException e) { - // This is expected when the socket is closed - if (LOG.isLoggable(INFO)) LOG.info(e.toString()); + // This is expected when the server socket is closed + LOG.info("Rendezvous server socket closed"); } }); Map portLines = @@ -682,9 +682,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { public void circuitStatus(String status, String id, String path) { if (status.equals("BUILT") && state.getAndSetCircuitBuilt()) { - callback.pluginStateChanged(getState()); LOG.info("First circuit built"); backoff.reset(); + callback.pluginStateChanged(getState()); } } @@ -716,8 +716,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg); if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) { state.setBootstrapped(); - callback.pluginStateChanged(getState()); backoff.reset(); + callback.pluginStateChanged(getState()); } } From 0a5f93edf98bc869fcc9b3e92d6bd7de22b03147 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 13:08:16 +0000 Subject: [PATCH 13/19] Remove unnecessary inner class, state checks. --- .../bramble/plugin/tor/AndroidTorPlugin.java | 1 - .../bramble/plugin/tor/TorPlugin.java | 172 +++++++----------- 2 files changed, 69 insertions(+), 104 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java index be7e4ee62..528e611b0 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/AndroidTorPlugin.java @@ -74,7 +74,6 @@ class AndroidTorPlugin extends TorPlugin { @Override protected void enableNetwork(boolean enable) throws IOException { - if (!state.isTorRunning()) return; if (enable) wakeLock.acquire(); super.enableNetwork(enable); if (!enable) wakeLock.release(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index dc7e495e8..7010be7df 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -57,7 +57,6 @@ import java.util.zip.ZipInputStream; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.ThreadSafe; import javax.net.SocketFactory; @@ -480,7 +479,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } protected void enableNetwork(boolean enable) throws IOException { - if (!state.isTorRunning()) return; state.enableNetwork(enable); callback.pluginStateChanged(getState()); controlConnection.setConf("DisableNetwork", enable ? "0" : "1"); @@ -713,6 +711,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void message(String severity, String msg) { + if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg); if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg); if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) { state.setBootstrapped(); @@ -754,7 +753,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { private void disableNetwork() { connectionStatusExecutor.execute(() -> { try { - enableNetwork(false); + if (state.isTorRunning()) enableNetwork(false); } catch (IOException ex) { logException(LOG, WARNING, ex); } @@ -765,91 +764,79 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { boolean charging) { connectionStatusExecutor.execute(() -> { if (!state.isTorRunning()) return; - NetworkConfig config = getNetworkConfig(status, charging); - state.setDisabledBySettings(config.disabledBySettings, - config.reasonDisabled); - callback.pluginStateChanged(getState()); - applyNetworkConfig(config); - }); - } + boolean online = status.isConnected(); + boolean wifi = status.isWifi(); + String country = locationUtils.getCurrentCountry(); + boolean blocked = + circumventionProvider.isTorProbablyBlocked(country); + int network = settings.getInt(PREF_TOR_NETWORK, + PREF_TOR_NETWORK_AUTOMATIC); + boolean useMobile = settings.getBoolean(PREF_TOR_MOBILE, true); + boolean onlyWhenCharging = + settings.getBoolean(PREF_TOR_ONLY_WHEN_CHARGING, false); + boolean bridgesWork = circumventionProvider.doBridgesWork(country); + boolean automatic = network == PREF_TOR_NETWORK_AUTOMATIC; - private NetworkConfig getNetworkConfig(NetworkStatus status, - boolean charging) { - boolean online = status.isConnected(); - boolean wifi = status.isWifi(); - String country = locationUtils.getCurrentCountry(); - boolean blocked = circumventionProvider.isTorProbablyBlocked(country); - int network = - settings.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_AUTOMATIC); - boolean useMobile = settings.getBoolean(PREF_TOR_MOBILE, true); - boolean onlyWhenCharging = - settings.getBoolean(PREF_TOR_ONLY_WHEN_CHARGING, false); - boolean bridgesWork = circumventionProvider.doBridgesWork(country); - boolean automatic = network == PREF_TOR_NETWORK_AUTOMATIC; - - if (LOG.isLoggable(INFO)) { - LOG.info("Online: " + online + ", wifi: " + wifi); - if (country.isEmpty()) LOG.info("Country code unknown"); - else LOG.info("Country code: " + country); - LOG.info("Charging: " + charging); - } - - boolean enableNetwork = false, enableBridges = false; - boolean useMeek = false, enableConnectionPadding = false; - boolean disabledBySettings = false; - int reasonDisabled = REASON_STARTING_STOPPING; - - if (!online) { - LOG.info("Disabling network, device is offline"); - } else if (network == PREF_TOR_NETWORK_NEVER) { - LOG.info("Disabling network, user has disabled Tor"); - disabledBySettings = true; - reasonDisabled = REASON_USER; - } else if (!charging && onlyWhenCharging) { - LOG.info("Disabling network, device is on battery"); - disabledBySettings = true; - reasonDisabled = REASON_BATTERY; - } else if (!useMobile && !wifi) { - LOG.info("Disabling network, device is using mobile data"); - disabledBySettings = true; - reasonDisabled = REASON_MOBILE_DATA; - } else if (automatic && blocked && !bridgesWork) { - LOG.info("Disabling network, country is blocked"); - disabledBySettings = true; - reasonDisabled = REASON_COUNTRY_BLOCKED; - } else if (network == PREF_TOR_NETWORK_WITH_BRIDGES || - (automatic && bridgesWork)) { - if (circumventionProvider.needsMeek(country)) { - LOG.info("Enabling network, using meek bridges"); - enableBridges = true; - useMeek = true; - } else { - LOG.info("Enabling network, using obfs4 bridges"); - enableBridges = true; + if (LOG.isLoggable(INFO)) { + LOG.info("Online: " + online + ", wifi: " + wifi); + if (country.isEmpty()) LOG.info("Country code unknown"); + else LOG.info("Country code: " + country); + LOG.info("Charging: " + charging); } - enableNetwork = true; - } else { - LOG.info("Enabling network, not using bridges"); - enableNetwork = true; - } - if (online && wifi && charging) { - LOG.info("Enabling connection padding"); - enableConnectionPadding = true; - } else { - LOG.info("Disabling connection padding"); - } + boolean enableNetwork = false, enableBridges = false; + boolean useMeek = false, enableConnectionPadding = false; + boolean disabledBySettings = false; + int reasonDisabled = REASON_STARTING_STOPPING; - return new NetworkConfig(enableNetwork, enableBridges, useMeek, - enableConnectionPadding, disabledBySettings, reasonDisabled); - } + if (!online) { + LOG.info("Disabling network, device is offline"); + } else if (network == PREF_TOR_NETWORK_NEVER) { + LOG.info("Disabling network, user has disabled Tor"); + disabledBySettings = true; + reasonDisabled = REASON_USER; + } else if (!charging && onlyWhenCharging) { + LOG.info("Disabling network, device is on battery"); + disabledBySettings = true; + reasonDisabled = REASON_BATTERY; + } else if (!useMobile && !wifi) { + LOG.info("Disabling network, device is using mobile data"); + disabledBySettings = true; + reasonDisabled = REASON_MOBILE_DATA; + } else if (automatic && blocked && !bridgesWork) { + LOG.info("Disabling network, country is blocked"); + disabledBySettings = true; + reasonDisabled = REASON_COUNTRY_BLOCKED; + } else if (network == PREF_TOR_NETWORK_WITH_BRIDGES || + (automatic && bridgesWork)) { + if (circumventionProvider.needsMeek(country)) { + LOG.info("Enabling network, using meek bridges"); + enableBridges = true; + useMeek = true; + } else { + LOG.info("Enabling network, using obfs4 bridges"); + enableBridges = true; + } + enableNetwork = true; + } else { + LOG.info("Enabling network, not using bridges"); + enableNetwork = true; + } + + if (online && wifi && charging) { + LOG.info("Enabling connection padding"); + enableConnectionPadding = true; + } else { + LOG.info("Disabling connection padding"); + } + + state.setDisabledBySettings(disabledBySettings, reasonDisabled); + callback.pluginStateChanged(getState()); - private void applyNetworkConfig(NetworkConfig config) { - connectionStatusExecutor.execute(() -> { try { - enableBridges(config.enableBridges, config.useMeek); - enableNetwork(config.enableNetwork); - enableConnectionPadding(config.enableConnectionPadding); + enableBridges(enableBridges, useMeek); + enableNetwork(enableNetwork); + enableConnectionPadding(enableConnectionPadding); } catch (IOException e) { logException(LOG, WARNING, e); } @@ -857,30 +844,9 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } private void enableConnectionPadding(boolean enable) throws IOException { - if (!state.isTorRunning()) return; controlConnection.setConf("ConnectionPadding", enable ? "1" : "0"); } - @Immutable - @NotNullByDefault - private static class NetworkConfig { - - private final boolean enableNetwork, enableBridges, useMeek; - private final boolean enableConnectionPadding, disabledBySettings; - private final int reasonDisabled; - - private NetworkConfig(boolean enableNetwork, boolean enableBridges, - boolean useMeek, boolean enableConnectionPadding, - boolean disabledBySettings, int reasonDisabled) { - this.enableNetwork = enableNetwork; - this.enableBridges = enableBridges; - this.useMeek = useMeek; - this.enableConnectionPadding = enableConnectionPadding; - this.disabledBySettings = disabledBySettings; - this.reasonDisabled = reasonDisabled; - } - } - @ThreadSafe @NotNullByDefault protected static class PluginState { From 2b9ffc7fbe7676dc2ea1dc61474e95139750c577 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 17 Jan 2020 12:38:03 +0000 Subject: [PATCH 14/19] Close server socket when BT is disabled. --- .../briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index bce2dd41f..6a5cf1755 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -133,6 +133,8 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { void onAdapterDisabled() { LOG.info("Bluetooth disabled"); connectionLimiter.allConnectionsClosed(); + // The server socket may not have been closed automatically + tryToClose(state.clearServerSocket()); callback.pluginStateChanged(getState()); } From 8db481a17a156f71d6b444e6f828f04e0046b072 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 17 Jan 2020 12:38:43 +0000 Subject: [PATCH 15/19] Remove debug logging. --- .../org/briarproject/bramble/plugin/PluginManagerImpl.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java index ca25d3d3b..c1e9ced33 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java @@ -314,10 +314,6 @@ class PluginManagerImpl implements PluginManager, Service { } else if (oldState == ACTIVE) { eventBus.broadcast(new TransportInactiveEvent(id)); } - } else { - // TODO: Remove - if (LOG.isLoggable(INFO)) - LOG.info(id + " stayed in state " + oldState); } } From d7d8af7e32f45a9ed2c0b5191973d286bd3e90e6 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 20 Jan 2020 14:03:12 +0000 Subject: [PATCH 16/19] Remove redundant logging. --- .../main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 7010be7df..c4f063dc4 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -711,7 +711,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void message(String severity, String msg) { - if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg); if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg); if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) { state.setBootstrapped(); From 2689e5f3611baf7ab977bde6aad21932d7e67b1b Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 20 Jan 2020 14:48:33 +0000 Subject: [PATCH 17/19] Update javadocs for lock-safe methods. --- .../briarproject/bramble/api/event/EventBus.java | 2 ++ .../bramble/api/plugin/PluginCallback.java | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventBus.java b/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventBus.java index d27449833..cf57b67ed 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventBus.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/event/EventBus.java @@ -18,6 +18,8 @@ public interface EventBus { /** * Asynchronously notifies all listeners of an event. Listeners are * notified on the {@link EventExecutor}. + *

+ * This method can safely be called while holding a lock. */ void broadcast(Event e); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java index ed057a958..1b149cde1 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java @@ -2,6 +2,9 @@ package org.briarproject.bramble.api.plugin; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.Plugin.State; +import org.briarproject.bramble.api.plugin.event.TransportActiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent; +import org.briarproject.bramble.api.plugin.event.TransportStateEvent; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.settings.Settings; @@ -33,7 +36,17 @@ public interface PluginCallback extends ConnectionHandler { void mergeLocalProperties(TransportProperties p); /** - * Signals that the transport's state may have changed. + * Informs the callback of the plugin's current state. + *

+ * If the current state is different from the previous state, the callback + * will broadcast a {@link TransportStateEvent}. If the current state is + * {@link State#ACTIVE} and the previous state was not + * {@link State#ACTIVE}, the callback will broadcast a + * {@link TransportActiveEvent}. If the current state is not + * {@link State#ACTIVE} and the previous state was {@link State#ACTIVE}, + * the callback will broadcast a {@link TransportInactiveEvent}. + *

+ * This method can safely be called while holding a lock. */ void pluginStateChanged(State state); } From 9bfbb4d02d33aff1689808e14d2d4992969938d0 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 20 Jan 2020 15:00:16 +0000 Subject: [PATCH 18/19] Notify callback of state changes while holding lock. --- .../bramble/plugin/tcp/AndroidLanTcpPlugin.java | 1 - .../bramble/plugin/bluetooth/BluetoothPlugin.java | 6 +++--- .../briarproject/bramble/plugin/tcp/TcpPlugin.java | 10 +++++----- .../briarproject/bramble/plugin/tor/TorPlugin.java | 14 +++++++------- .../bramble/plugin/modem/ModemPlugin.java | 11 +++++------ 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java index 473df98bd..577a773e7 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java @@ -84,7 +84,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener { public void start() { if (used.getAndSet(true)) throw new IllegalStateException(); state.setStarted(); - callback.pluginStateChanged(getState()); updateConnectionStatus(); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index 6a5cf1755..e15a3e623 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -164,7 +164,6 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { } updateProperties(); state.setStarted(); - callback.pluginStateChanged(getState()); loadSettings(callback.getSettings()); if (shouldAllowContactConnections()) { if (isAdapterEnabled()) bind(); @@ -199,7 +198,6 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { return; } backoff.reset(); - callback.pluginStateChanged(getState()); acceptContactConnections(ss); }); } @@ -250,7 +248,6 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { @Override public void stop() { SS ss = state.setStopped(); - callback.pluginStateChanged(getState()); tryToClose(ss); disableAdapterIfEnabledByUs(); } @@ -492,6 +489,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { synchronized void setStarted() { started = true; + callback.pluginStateChanged(getState()); } @Nullable @@ -499,12 +497,14 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { stopped = true; SS ss = serverSocket; serverSocket = null; + callback.pluginStateChanged(getState()); return ss; } synchronized boolean setServerSocket(SS ss) { if (stopped || serverSocket != null) return false; serverSocket = ss; + callback.pluginStateChanged(getState()); return true; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java index 3e0ebb65d..d4713fecf 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/TcpPlugin.java @@ -120,7 +120,6 @@ abstract class TcpPlugin implements DuplexPlugin { public void start() { if (used.getAndSet(true)) throw new IllegalStateException(); state.setStarted(); - callback.pluginStateChanged(getState()); bind(); } @@ -154,7 +153,6 @@ abstract class TcpPlugin implements DuplexPlugin { setLocalSocketAddress(local); if (LOG.isLoggable(INFO)) LOG.info("Listening on " + scrubSocketAddress(local)); - callback.pluginStateChanged(getState()); acceptContactConnections(ss); }); } @@ -176,7 +174,6 @@ abstract class TcpPlugin implements DuplexPlugin { // This is expected when the server socket is closed LOG.info("Server socket closed"); state.clearServerSocket(ss); - callback.pluginStateChanged(getState()); return; } if (LOG.isLoggable(INFO)) @@ -190,7 +187,6 @@ abstract class TcpPlugin implements DuplexPlugin { @Override public void stop() { ServerSocket ss = state.setStopped(); - callback.pluginStateChanged(getState()); tryToClose(ss, LOG, WARNING); } @@ -337,7 +333,7 @@ abstract class TcpPlugin implements DuplexPlugin { @ThreadSafe @NotNullByDefault - protected static class PluginState { + protected class PluginState { @GuardedBy("this") private boolean started = false, stopped = false; @@ -347,6 +343,7 @@ abstract class TcpPlugin implements DuplexPlugin { synchronized void setStarted() { started = true; + callback.pluginStateChanged(getState()); } @Nullable @@ -354,6 +351,7 @@ abstract class TcpPlugin implements DuplexPlugin { stopped = true; ServerSocket ss = serverSocket; serverSocket = null; + callback.pluginStateChanged(getState()); return ss; } @@ -365,11 +363,13 @@ abstract class TcpPlugin implements DuplexPlugin { synchronized boolean setServerSocket(ServerSocket ss) { if (stopped || serverSocket != null) return false; serverSocket = ss; + callback.pluginStateChanged(getState()); return true; } synchronized void clearServerSocket(ServerSocket ss) { if (serverSocket == ss) serverSocket = null; + callback.pluginStateChanged(getState()); } synchronized State getState() { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index c4f063dc4..f284999dd 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -193,7 +193,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { public void start() throws PluginException { if (used.getAndSet(true)) throw new IllegalStateException(); state.setStarted(); - callback.pluginStateChanged(getState()); if (!torDirectory.exists()) { if (!torDirectory.mkdirs()) { LOG.warning("Could not create Tor directory."); @@ -480,7 +479,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { protected void enableNetwork(boolean enable) throws IOException { state.enableNetwork(enable); - callback.pluginStateChanged(getState()); controlConnection.setConf("DisableNetwork", enable ? "0" : "1"); } @@ -506,7 +504,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @Override public void stop() { ServerSocket ss = state.setStopped(); - callback.pluginStateChanged(getState()); tryToClose(ss, LOG, WARNING); if (controlSocket != null && controlConnection != null) { try { @@ -682,7 +679,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { state.getAndSetCircuitBuilt()) { LOG.info("First circuit built"); backoff.reset(); - callback.pluginStateChanged(getState()); } } @@ -715,7 +711,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) { state.setBootstrapped(); backoff.reset(); - callback.pluginStateChanged(getState()); } } @@ -830,7 +825,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { } state.setDisabledBySettings(disabledBySettings, reasonDisabled); - callback.pluginStateChanged(getState()); try { enableBridges(enableBridges, useMeek); @@ -848,7 +842,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { @ThreadSafe @NotNullByDefault - protected static class PluginState { + protected class PluginState { @GuardedBy("this") private boolean started = false, @@ -869,6 +863,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { synchronized void setStarted() { started = true; + callback.pluginStateChanged(getState()); } synchronized void setTorStarted() { @@ -885,16 +880,19 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { stopped = true; ServerSocket ss = serverSocket; serverSocket = null; + callback.pluginStateChanged(getState()); return ss; } synchronized void setBootstrapped() { bootstrapped = true; + callback.pluginStateChanged(getState()); } synchronized boolean getAndSetCircuitBuilt() { boolean firstCircuit = !circuitBuilt; circuitBuilt = true; + callback.pluginStateChanged(getState()); return firstCircuit; } @@ -902,12 +900,14 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { networkInitialised = true; networkEnabled = enable; if (!enable) circuitBuilt = false; + callback.pluginStateChanged(getState()); } synchronized void setDisabledBySettings(boolean disabledBySettings, int reasonDisabled) { this.disabledBySettings = disabledBySettings; this.reasonDisabled = reasonDisabled; + callback.pluginStateChanged(getState()); } synchronized boolean setServerSocket(ServerSocket ss) { diff --git a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java index 89a11ff2f..e2eb69ca8 100644 --- a/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java +++ b/bramble-java/src/main/java/org/briarproject/bramble/plugin/modem/ModemPlugin.java @@ -84,7 +84,6 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { public void start() throws PluginException { if (used.getAndSet(true)) throw new IllegalStateException(); state.setStarted(); - callback.pluginStateChanged(getState()); for (String portName : serialPortList.getPortNames()) { if (LOG.isLoggable(INFO)) LOG.info("Trying to initialise modem on " + portName); @@ -94,7 +93,6 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { if (LOG.isLoggable(INFO)) LOG.info("Initialised modem on " + portName); state.setInitialised(); - callback.pluginStateChanged(getState()); return; } catch (IOException e) { logException(LOG, WARNING, e); @@ -102,14 +100,12 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { } LOG.warning("Failed to initialised modem"); state.setFailed(); - callback.pluginStateChanged(getState()); throw new PluginException(); } @Override public void stop() { state.setStopped(); - callback.pluginStateChanged(getState()); if (modem != null) { try { modem.stop(); @@ -162,7 +158,6 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { } LOG.warning("Failed to initialise modem"); state.setFailed(); - callback.pluginStateChanged(getState()); } @Override @@ -256,7 +251,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { @ThreadSafe @NotNullByDefault - private static class PluginState { + private class PluginState { @GuardedBy("this") private boolean started = false, @@ -266,18 +261,22 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private synchronized void setStarted() { started = true; + callback.pluginStateChanged(getState()); } private synchronized void setStopped() { stopped = true; + callback.pluginStateChanged(getState()); } private synchronized void setInitialised() { initialised = true; + callback.pluginStateChanged(getState()); } private synchronized void setFailed() { failed = true; + callback.pluginStateChanged(getState()); } private State getState() { From 2e42fb3c44819689854d30308b0af53b4da93a77 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 20 Jan 2020 16:20:36 +0000 Subject: [PATCH 19/19] Only update bridge and padding settings if network is enabled. --- .../bramble/plugin/tor/TorPlugin.java | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index f284999dd..d20901002 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -801,35 +801,39 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { LOG.info("Disabling network, country is blocked"); disabledBySettings = true; reasonDisabled = REASON_COUNTRY_BLOCKED; - } else if (network == PREF_TOR_NETWORK_WITH_BRIDGES || - (automatic && bridgesWork)) { - if (circumventionProvider.needsMeek(country)) { - LOG.info("Enabling network, using meek bridges"); - enableBridges = true; - useMeek = true; - } else { - LOG.info("Enabling network, using obfs4 bridges"); - enableBridges = true; - } - enableNetwork = true; } else { - LOG.info("Enabling network, not using bridges"); + LOG.info("Enabling network"); enableNetwork = true; + if (network == PREF_TOR_NETWORK_WITH_BRIDGES || + (automatic && bridgesWork)) { + if (circumventionProvider.needsMeek(country)) { + LOG.info("Using meek bridges"); + enableBridges = true; + useMeek = true; + } else { + LOG.info("Using obfs4 bridges"); + enableBridges = true; + } + } else { + LOG.info("Not using bridges"); + } + if (wifi && charging) { + LOG.info("Enabling connection padding"); + enableConnectionPadding = true; + } else { + LOG.info("Disabling connection padding"); + } } - if (online && wifi && charging) { - LOG.info("Enabling connection padding"); - enableConnectionPadding = true; - } else { - LOG.info("Disabling connection padding"); - } state.setDisabledBySettings(disabledBySettings, reasonDisabled); try { - enableBridges(enableBridges, useMeek); + if (enableNetwork) { + enableBridges(enableBridges, useMeek); + enableConnectionPadding(enableConnectionPadding); + } enableNetwork(enableNetwork); - enableConnectionPadding(enableConnectionPadding); } catch (IOException e) { logException(LOG, WARNING, e); }