Add Tor reachability monitor.

This commit is contained in:
akwizgran
2022-05-27 16:33:09 +01:00
parent 6e61827fe6
commit 63c0210047
2 changed files with 173 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MINUTES;
@ThreadSafe
@NotNullByDefault
interface TorReachabilityMonitor {
/**
* How long the Tor plugin needs to be continuously
* {@link Plugin.State#ACTIVE active} before we assume our contacts can
* reach our hidden service.
*/
long REACHABILITY_PERIOD_MS = MINUTES.toMillis(10);
/**
* Starts the monitor.
*/
void start();
/**
* Destroys the monitor.
*/
void destroy();
/**
* Adds an observer that will be called when our Tor hidden service becomes
* reachable. If our hidden service is already reachable, the observer is
* called immediately.
* <p>
* Observers are removed after being called, or when the monitor is
* {@link #destroy() destroyed}.
*/
void addObserver(TorReachabilityObserver o);
interface TorReachabilityObserver {
void onTorReachable();
}
}

View File

@@ -0,0 +1,128 @@
package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.Cancellable;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
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.Plugin;
import org.briarproject.bramble.api.plugin.PluginManager;
import org.briarproject.bramble.api.plugin.event.TransportActiveEvent;
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
@ThreadSafe
@NotNullByDefault
class TorReachabilityMonitorImpl
implements TorReachabilityMonitor, EventListener {
private final Executor ioExecutor;
private final TaskScheduler taskScheduler;
private final PluginManager pluginManager;
private final EventBus eventBus;
private final Object lock = new Object();
@GuardedBy("lock")
private boolean reachable = false, destroyed = false;
@GuardedBy("lock")
private final List<TorReachabilityObserver> observers = new ArrayList<>();
@GuardedBy("lock")
@Nullable
private Cancellable task = null;
@Inject
TorReachabilityMonitorImpl(
@IoExecutor Executor ioExecutor,
TaskScheduler taskScheduler,
PluginManager pluginManager,
EventBus eventBus) {
this.ioExecutor = ioExecutor;
this.taskScheduler = taskScheduler;
this.pluginManager = pluginManager;
this.eventBus = eventBus;
}
@Override
public void start() {
eventBus.addListener(this);
Plugin plugin = pluginManager.getPlugin(ID);
if (plugin != null && plugin.getState() == ACTIVE) onTorActive();
}
@Override
public void destroy() {
eventBus.removeListener(this);
synchronized (lock) {
destroyed = true;
onTorInactive();
observers.clear();
}
}
@Override
public void addObserver(TorReachabilityObserver o) {
boolean callNow = false;
synchronized (lock) {
if (destroyed) return;
if (reachable) callNow = true;
else observers.add(o);
}
if (callNow) o.onTorReachable();
}
@Override
public void eventOccurred(Event e) {
if (e instanceof TransportActiveEvent) {
TransportActiveEvent t = (TransportActiveEvent) e;
if (t.getTransportId().equals(ID)) onTorActive();
} else if (e instanceof TransportInactiveEvent) {
TransportInactiveEvent t = (TransportInactiveEvent) e;
if (t.getTransportId().equals(ID)) onTorInactive();
}
}
private void onTorActive() {
synchronized (lock) {
if (destroyed || task != null) return;
task = taskScheduler.schedule(this::onTorReachable, ioExecutor,
REACHABILITY_PERIOD_MS, MILLISECONDS);
}
}
private void onTorInactive() {
synchronized (lock) {
reachable = false;
if (task != null) task.cancel();
task = null;
}
}
@IoExecutor
private void onTorReachable() {
List<TorReachabilityObserver> observers;
synchronized (lock) {
if (destroyed) return;
reachable = true;
observers = new ArrayList<>(this.observers);
this.observers.clear();
task = null;
}
for (TorReachabilityObserver o : observers) o.onTorReachable();
}
}