mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 14:49:53 +01:00
Add bootstrap percentage and HS desc uploads to observer interface.
This commit is contained in:
@@ -55,10 +55,10 @@ public class AndroidTorWrapper extends AbstractTorWrapper {
|
|||||||
* @param ioExecutor The wrapper will use this executor to run IO tasks,
|
* @param ioExecutor The wrapper will use this executor to run IO tasks,
|
||||||
* some of which may run for the lifetime of the wrapper, so the executor
|
* some of which may run for the lifetime of the wrapper, so the executor
|
||||||
* should have an unlimited thread pool.
|
* should have an unlimited thread pool.
|
||||||
* @param eventExecutor The wrapper will use this executor to call
|
* @param eventExecutor The wrapper will use this executor to call the
|
||||||
* {@link StateObserver#observeState(TorState)}. To ensure that state
|
* {@link Observer observer} (if any). To ensure that events are observed
|
||||||
* changes are observed in the order they occur, this executor should have
|
* in the order they occur, this executor should have a single thread (eg
|
||||||
* a single thread (eg the app's main thread).
|
* the app's main thread).
|
||||||
* @param architecture The processor architecture of the Tor and pluggable
|
* @param architecture The processor architecture of the Tor and pluggable
|
||||||
* transport binaries.
|
* transport binaries.
|
||||||
* @param torDirectory The directory where the Tor process should keep its
|
* @param torDirectory The directory where the Tor process should keep its
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.briarproject.bramble.api.system.LocationUtils;
|
|||||||
import org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType;
|
import org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType;
|
||||||
import org.briarproject.bramble.plugin.tor.wrapper.TorWrapper;
|
import org.briarproject.bramble.plugin.tor.wrapper.TorWrapper;
|
||||||
import org.briarproject.bramble.plugin.tor.wrapper.TorWrapper.HiddenServiceProperties;
|
import org.briarproject.bramble.plugin.tor.wrapper.TorWrapper.HiddenServiceProperties;
|
||||||
|
import org.briarproject.bramble.plugin.tor.wrapper.TorWrapper.Observer;
|
||||||
import org.briarproject.bramble.plugin.tor.wrapper.TorWrapper.TorState;
|
import org.briarproject.bramble.plugin.tor.wrapper.TorWrapper.TorState;
|
||||||
import org.briarproject.nullsafety.InterfaceNotNullByDefault;
|
import org.briarproject.nullsafety.InterfaceNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
@@ -148,10 +149,22 @@ class TorPlugin implements DuplexPlugin, EventListener {
|
|||||||
// Don't execute more than one connection status check at a time
|
// Don't execute more than one connection status check at a time
|
||||||
connectionStatusExecutor =
|
connectionStatusExecutor =
|
||||||
new PoliteExecutor("TorPlugin", ioExecutor, 1);
|
new PoliteExecutor("TorPlugin", ioExecutor, 1);
|
||||||
tor.setStateObserver(torState -> {
|
tor.setObserver(new Observer() {
|
||||||
State s = state.getState(torState);
|
|
||||||
if (s == ACTIVE) backoff.reset();
|
@Override
|
||||||
callback.pluginStateChanged(s);
|
public void onState(TorState torState) {
|
||||||
|
State s = state.getState(torState);
|
||||||
|
if (s == ACTIVE) backoff.reset();
|
||||||
|
callback.pluginStateChanged(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBootstrapPercentage(int percentage) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHsDescriptorUpload(String onion) {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import java.util.Map;
|
|||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
@@ -61,6 +63,8 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
private static final String OWNER = "__OwningControllerProcess";
|
private static final String OWNER = "__OwningControllerProcess";
|
||||||
private static final int COOKIE_TIMEOUT_MS = 3000;
|
private static final int COOKIE_TIMEOUT_MS = 3000;
|
||||||
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
|
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
|
||||||
|
private static final Pattern BOOTSTRAP_PERCENTAGE =
|
||||||
|
Pattern.compile("PROGRESS=(\\d{1,3})");
|
||||||
|
|
||||||
protected final Executor ioExecutor;
|
protected final Executor ioExecutor;
|
||||||
protected final Executor eventExecutor;
|
protected final Executor eventExecutor;
|
||||||
@@ -112,8 +116,8 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStateObserver(@Nullable StateObserver stateObserver) {
|
public void setObserver(@Nullable Observer observer) {
|
||||||
state.setObserver(stateObserver);
|
state.setObserver(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -172,9 +176,10 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
controlConnection.setEvents(asList(EVENTS));
|
controlConnection.setEvents(asList(EVENTS));
|
||||||
// Check whether Tor has already bootstrapped
|
// Check whether Tor has already bootstrapped
|
||||||
String info = controlConnection.getInfo("status/bootstrap-phase");
|
String info = controlConnection.getInfo("status/bootstrap-phase");
|
||||||
if (info != null && info.contains("PROGRESS=100")) {
|
if (info != null && info.contains("PROGRESS=")) {
|
||||||
LOG.info("Tor has already bootstrapped");
|
int percentage = parseBootstrapPercentage(info);
|
||||||
state.setBootstrapped();
|
if (percentage == 100) LOG.info("Tor has already bootstrapped");
|
||||||
|
state.setBootstrapPercentage(percentage);
|
||||||
}
|
}
|
||||||
// Check whether Tor has already built a circuit
|
// Check whether Tor has already built a circuit
|
||||||
info = controlConnection.getInfo("status/circuit-established");
|
info = controlConnection.getInfo("status/circuit-established");
|
||||||
@@ -410,7 +415,9 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
if (parts.length < 2) {
|
if (parts.length < 2) {
|
||||||
LOG.warning("Failed to parse HS_DESC UPLOADED event");
|
LOG.warning("Failed to parse HS_DESC UPLOADED event");
|
||||||
} else if (LOG.isLoggable(INFO)) {
|
} else if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("V3 descriptor uploaded for " + scrubOnion(parts[1]));
|
String onion = parts[1];
|
||||||
|
LOG.info("V3 descriptor uploaded for " + scrubOnion(onion));
|
||||||
|
state.onHsDescriptorUploaded(onion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,9 +427,10 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleClientStatus(String msg) {
|
private void handleClientStatus(String msg) {
|
||||||
if (msg.startsWith("BOOTSTRAP PROGRESS=100")) {
|
if (msg.startsWith("BOOTSTRAP PROGRESS=")) {
|
||||||
LOG.info("Bootstrapped");
|
int percentage = parseBootstrapPercentage(msg);
|
||||||
state.setBootstrapped();
|
if (percentage == 100) LOG.info("Bootstrapped");
|
||||||
|
state.setBootstrapPercentage(percentage);
|
||||||
} else if (msg.startsWith("CIRCUIT_ESTABLISHED")) {
|
} else if (msg.startsWith("CIRCUIT_ESTABLISHED")) {
|
||||||
if (state.setCircuitBuilt(true)) LOG.info("Circuit built");
|
if (state.setCircuitBuilt(true)) LOG.info("Circuit built");
|
||||||
} else if (msg.startsWith("CIRCUIT_NOT_ESTABLISHED")) {
|
} else if (msg.startsWith("CIRCUIT_NOT_ESTABLISHED")) {
|
||||||
@@ -435,6 +443,21 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int parseBootstrapPercentage(String s) {
|
||||||
|
Matcher matcher = BOOTSTRAP_PERCENTAGE.matcher(s);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(matcher.group(1));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// Fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("Failed to parse bootstrap percentage: " + s);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private void handleGeneralStatus(String msg) {
|
private void handleGeneralStatus(String msg) {
|
||||||
if (msg.startsWith("CLOCK_JUMPED")) {
|
if (msg.startsWith("CLOCK_JUMPED")) {
|
||||||
Long time = parseLongArgument(msg, "TIME");
|
Long time = parseLongArgument(msg, "TIME");
|
||||||
@@ -512,7 +535,7 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
@Nullable
|
@Nullable
|
||||||
private StateObserver observer = null;
|
private Observer observer = null;
|
||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private boolean started = false,
|
private boolean started = false,
|
||||||
@@ -521,9 +544,14 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
networkEnabled = false,
|
networkEnabled = false,
|
||||||
paddingEnabled = false,
|
paddingEnabled = false,
|
||||||
ipv6Enabled = false,
|
ipv6Enabled = false,
|
||||||
bootstrapped = false,
|
|
||||||
circuitBuilt = false;
|
circuitBuilt = false;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
private int bootstrapPercentage = 0;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
private List<String> bridges = emptyList();
|
||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private int orConnectionsConnected = 0;
|
private int orConnectionsConnected = 0;
|
||||||
|
|
||||||
@@ -532,32 +560,25 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
private TorState state = null;
|
private TorState state = null;
|
||||||
|
|
||||||
private synchronized void setObserver(
|
private synchronized void setObserver(
|
||||||
@Nullable StateObserver observer) {
|
@Nullable Observer observer) {
|
||||||
this.observer = observer;
|
this.observer = observer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private void updateObserver() {
|
private void updateState() {
|
||||||
TorState newState = getState();
|
TorState newState = getState();
|
||||||
if (newState != state) {
|
if (newState != state) {
|
||||||
state = newState;
|
state = newState;
|
||||||
// Post the new state to the event executor. The contract of
|
|
||||||
// this executor is to execute tasks in the order they're
|
|
||||||
// submitted, so state changes will be observed in the correct
|
|
||||||
// order but outside the lock
|
|
||||||
if (observer != null) {
|
if (observer != null) {
|
||||||
eventExecutor.execute(() ->
|
// Notify the observer on the event executor
|
||||||
observer.observeState(newState));
|
eventExecutor.execute(() -> observer.onState(newState));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("this")
|
|
||||||
private List<String> bridges = emptyList();
|
|
||||||
|
|
||||||
private synchronized void setStarted() {
|
private synchronized void setStarted() {
|
||||||
started = true;
|
started = true;
|
||||||
updateObserver();
|
updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
@@ -567,13 +588,18 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
|
|
||||||
private synchronized void setStopped() {
|
private synchronized void setStopped() {
|
||||||
stopped = true;
|
stopped = true;
|
||||||
updateObserver();
|
updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void setBootstrapped() {
|
private synchronized void setBootstrapPercentage(int percentage) {
|
||||||
if (bootstrapped) return;
|
if (percentage == bootstrapPercentage) return;
|
||||||
bootstrapped = true;
|
bootstrapPercentage = percentage;
|
||||||
updateObserver();
|
if (observer != null) {
|
||||||
|
// Notify the observer on the event executor
|
||||||
|
eventExecutor.execute(() ->
|
||||||
|
observer.onBootstrapPercentage(percentage));
|
||||||
|
}
|
||||||
|
updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -583,7 +609,7 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
private synchronized boolean setCircuitBuilt(boolean built) {
|
private synchronized boolean setCircuitBuilt(boolean built) {
|
||||||
if (built == circuitBuilt) return false; // Unchanged
|
if (built == circuitBuilt) return false; // Unchanged
|
||||||
circuitBuilt = built;
|
circuitBuilt = built;
|
||||||
updateObserver();
|
updateState();
|
||||||
return true; // Changed
|
return true; // Changed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,7 +624,7 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
networkEnabled = enable;
|
networkEnabled = enable;
|
||||||
if (!enable) circuitBuilt = false;
|
if (!enable) circuitBuilt = false;
|
||||||
if (!wasInitialised || enable != wasEnabled) {
|
if (!wasInitialised || enable != wasEnabled) {
|
||||||
updateObserver();
|
updateState();
|
||||||
}
|
}
|
||||||
return enable != wasEnabled;
|
return enable != wasEnabled;
|
||||||
}
|
}
|
||||||
@@ -639,15 +665,15 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
if (!started || stopped) return STARTING_STOPPING;
|
if (!started || stopped) return STARTING_STOPPING;
|
||||||
if (!networkInitialised) return CONNECTING;
|
if (!networkInitialised) return CONNECTING;
|
||||||
if (!networkEnabled) return DISABLED;
|
if (!networkEnabled) return DISABLED;
|
||||||
return bootstrapped && circuitBuilt && orConnectionsConnected > 0
|
return bootstrapPercentage == 100 && circuitBuilt
|
||||||
? CONNECTED : CONNECTING;
|
&& orConnectionsConnected > 0 ? CONNECTED : CONNECTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void onOrConnectionConnected() {
|
private synchronized void onOrConnectionConnected() {
|
||||||
int oldConnected = orConnectionsConnected;
|
int oldConnected = orConnectionsConnected;
|
||||||
orConnectionsConnected++;
|
orConnectionsConnected++;
|
||||||
logOrConnections();
|
logOrConnections();
|
||||||
if (oldConnected == 0) updateObserver();
|
if (oldConnected == 0) updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void onOrConnectionClosed() {
|
private synchronized void onOrConnectionClosed() {
|
||||||
@@ -659,7 +685,7 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
}
|
}
|
||||||
logOrConnections();
|
logOrConnections();
|
||||||
if (orConnectionsConnected == 0 && oldConnected != 0) {
|
if (orConnectionsConnected == 0 && oldConnected != 0) {
|
||||||
updateObserver();
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,5 +695,13 @@ abstract class AbstractTorWrapper implements EventHandler, TorWrapper {
|
|||||||
LOG.info(orConnectionsConnected + " OR connections connected");
|
LOG.info(orConnectionsConnected + " OR connections connected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void onHsDescriptorUploaded(String onion) {
|
||||||
|
if (observer != null) {
|
||||||
|
// Notify the observer on the event executor
|
||||||
|
eventExecutor.execute(() ->
|
||||||
|
observer.onHsDescriptorUpload(onion));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public interface TorWrapper {
|
|||||||
* existing observer, or removes any existing observer if the argument is
|
* existing observer, or removes any existing observer if the argument is
|
||||||
* null.
|
* null.
|
||||||
*/
|
*/
|
||||||
void setStateObserver(@Nullable StateObserver stateObserver);
|
void setObserver(@Nullable Observer observer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current state of the wrapper.
|
* Returns the current state of the wrapper.
|
||||||
@@ -129,16 +129,25 @@ public interface TorWrapper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for observing changes to the {@link TorState state} of the
|
* An interface for observing changes to the {@link TorState state} of the
|
||||||
* Tor process.
|
* Tor process. All calls happen on the event executor supplied to the
|
||||||
|
* wrapper's constructor.
|
||||||
*/
|
*/
|
||||||
interface StateObserver {
|
interface Observer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called whenever the state of the Tor process changes.
|
* Called whenever the state of the Tor process changes.
|
||||||
* The call happens on the event executor supplied to the wrapper's
|
|
||||||
* constructor.
|
|
||||||
*/
|
*/
|
||||||
void observeState(TorState s);
|
void onState(TorState s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever the bootstrap percentage changes.
|
||||||
|
*/
|
||||||
|
void onBootstrapPercentage(int percentage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever a hidden service descriptor is uploaded.
|
||||||
|
*/
|
||||||
|
void onHsDescriptorUpload(String onion);
|
||||||
}
|
}
|
||||||
|
|
||||||
class HiddenServiceProperties {
|
class HiddenServiceProperties {
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ public class UnixTorWrapper extends JavaTorWrapper {
|
|||||||
* @param ioExecutor The wrapper will use this executor to run IO tasks,
|
* @param ioExecutor The wrapper will use this executor to run IO tasks,
|
||||||
* some of which may run for the lifetime of the wrapper, so the executor
|
* some of which may run for the lifetime of the wrapper, so the executor
|
||||||
* should have an unlimited thread pool.
|
* should have an unlimited thread pool.
|
||||||
* @param eventExecutor The wrapper will use this executor to call
|
* @param eventExecutor The wrapper will use this executor to call the
|
||||||
* {@link StateObserver#observeState(TorState)}. To ensure that state
|
* {@link Observer observer} (if any). To ensure that events are observed
|
||||||
* changes are observed in the order they occur, this executor should have
|
* in the order they occur, this executor should have a single thread (eg
|
||||||
* a single thread (eg the app's main thread).
|
* the app's main thread).
|
||||||
* @param architecture The processor architecture of the Tor and pluggable
|
* @param architecture The processor architecture of the Tor and pluggable
|
||||||
* transport binaries.
|
* transport binaries.
|
||||||
* @param torDirectory The directory where the Tor process should keep its
|
* @param torDirectory The directory where the Tor process should keep its
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ public class WindowsTorWrapper extends JavaTorWrapper {
|
|||||||
* some of which may run for the lifetime of the wrapper, so the executor
|
* some of which may run for the lifetime of the wrapper, so the executor
|
||||||
* should have an unlimited thread pool.
|
* should have an unlimited thread pool.
|
||||||
* @param eventExecutor The wrapper will use this executor to call
|
* @param eventExecutor The wrapper will use this executor to call
|
||||||
* {@link StateObserver#observeState(TorState)}. To ensure that state
|
* @param eventExecutor The wrapper will use this executor to call the
|
||||||
* changes are observed in the order they occur, this executor should have
|
* {@link Observer observer} (if any). To ensure that events are observed
|
||||||
* a single thread (eg the app's main thread).
|
* in the order they occur, this executor should have a single thread (eg
|
||||||
|
* the app's main thread).
|
||||||
* @param architecture The processor architecture of the Tor and pluggable
|
* @param architecture The processor architecture of the Tor and pluggable
|
||||||
* transport binaries.
|
* transport binaries.
|
||||||
* @param torDirectory The directory where the Tor process should keep its
|
* @param torDirectory The directory where the Tor process should keep its
|
||||||
|
|||||||
Reference in New Issue
Block a user