From b6a73f2c98acf001eefde22ffdfc9bff802e1b3c Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jan 2020 11:05:36 +0000 Subject: [PATCH] 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 627e1d680..e92314ee5 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 @@ -202,6 +202,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;