summaryrefslogtreecommitdiffhomepage
path: root/app/src/main/java/com/wireguard/android/model
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/com/wireguard/android/model')
-rw-r--r--app/src/main/java/com/wireguard/android/model/ObservableTunnel.java (renamed from app/src/main/java/com/wireguard/android/model/Tunnel.java)82
-rw-r--r--app/src/main/java/com/wireguard/android/model/TunnelManager.java78
2 files changed, 53 insertions, 107 deletions
diff --git a/app/src/main/java/com/wireguard/android/model/Tunnel.java b/app/src/main/java/com/wireguard/android/model/ObservableTunnel.java
index 87b607d0..826a6a2a 100644
--- a/app/src/main/java/com/wireguard/android/model/Tunnel.java
+++ b/app/src/main/java/com/wireguard/android/model/ObservableTunnel.java
@@ -5,23 +5,17 @@
package com.wireguard.android.model;
-import android.os.SystemClock;
-import android.util.Pair;
-
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import androidx.annotation.Nullable;
import com.wireguard.android.BR;
+import com.wireguard.android.backend.Statistics;
+import com.wireguard.android.backend.Tunnel;
import com.wireguard.android.util.ExceptionLoggers;
import com.wireguard.config.Config;
-import com.wireguard.crypto.Key;
import com.wireguard.util.Keyed;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Pattern;
-
import java9.util.concurrent.CompletableFuture;
import java9.util.concurrent.CompletionStage;
@@ -29,28 +23,21 @@ import java9.util.concurrent.CompletionStage;
* Encapsulates the volatile and nonvolatile state of a WireGuard tunnel.
*/
-public class Tunnel extends BaseObservable implements Keyed<String> {
- public static final int NAME_MAX_LENGTH = 15;
- private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_=+.-]{1,15}");
-
+public class ObservableTunnel extends BaseObservable implements Keyed<String>, Tunnel {
private final TunnelManager manager;
@Nullable private Config config;
- private String name;
private State state;
+ private String name;
@Nullable private Statistics statistics;
- Tunnel(final TunnelManager manager, final String name,
+ ObservableTunnel(final TunnelManager manager, final String name,
@Nullable final Config config, final State state) {
- this.manager = manager;
this.name = name;
+ this.manager = manager;
this.config = config;
this.state = state;
}
- public static boolean isNameInvalid(final CharSequence name) {
- return !NAME_PATTERN.matcher(name).matches();
- }
-
public CompletionStage<Void> delete() {
return manager.delete(this);
}
@@ -74,6 +61,7 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
return name;
}
+ @Override
@Bindable
public String getName() {
return name;
@@ -146,60 +134,4 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
return manager.setTunnelState(this, state);
return CompletableFuture.completedFuture(this.state);
}
-
- public enum State {
- DOWN,
- TOGGLE,
- UP;
-
- public static State of(final boolean running) {
- return running ? UP : DOWN;
- }
- }
-
- public static class Statistics extends BaseObservable {
- private long lastTouched = SystemClock.elapsedRealtime();
- private final Map<Key, Pair<Long, Long>> peerBytes = new HashMap<>();
-
- public void add(final Key key, final long rx, final long tx) {
- peerBytes.put(key, Pair.create(rx, tx));
- lastTouched = SystemClock.elapsedRealtime();
- }
-
- private boolean isStale() {
- return SystemClock.elapsedRealtime() - lastTouched > 900;
- }
-
- public Key[] peers() {
- return peerBytes.keySet().toArray(new Key[0]);
- }
-
- public long peerRx(final Key peer) {
- if (!peerBytes.containsKey(peer))
- return 0;
- return peerBytes.get(peer).first;
- }
-
- public long peerTx(final Key peer) {
- if (!peerBytes.containsKey(peer))
- return 0;
- return peerBytes.get(peer).second;
- }
-
- public long totalRx() {
- long rx = 0;
- for (final Pair<Long, Long> val : peerBytes.values()) {
- rx += val.first;
- }
- return rx;
- }
-
- public long totalTx() {
- long tx = 0;
- for (final Pair<Long, Long> val : peerBytes.values()) {
- tx += val.second;
- }
- return tx;
- }
- }
}
diff --git a/app/src/main/java/com/wireguard/android/model/TunnelManager.java b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
index 2deea6df..e7bb9cd5 100644
--- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java
+++ b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
@@ -15,9 +15,11 @@ import androidx.annotation.Nullable;
import com.wireguard.android.Application;
import com.wireguard.android.BR;
import com.wireguard.android.R;
+import com.wireguard.android.backend.Backend.TunnelStateChangeNotificationReceiver;
import com.wireguard.android.configStore.ConfigStore;
-import com.wireguard.android.model.Tunnel.State;
-import com.wireguard.android.model.Tunnel.Statistics;
+import com.wireguard.android.backend.Tunnel;
+import com.wireguard.android.backend.Tunnel.State;
+import com.wireguard.android.backend.Statistics;
import com.wireguard.android.util.ExceptionLoggers;
import com.wireguard.android.util.ObservableSortedKeyedArrayList;
import com.wireguard.android.util.ObservableSortedKeyedList;
@@ -38,42 +40,49 @@ import java9.util.stream.StreamSupport;
* Maintains and mediates changes to the set of available WireGuard tunnels,
*/
-public final class TunnelManager extends BaseObservable {
+public final class TunnelManager extends BaseObservable implements TunnelStateChangeNotificationReceiver {
private static final Comparator<String> COMPARATOR = Comparators.<String>thenComparing(
String.CASE_INSENSITIVE_ORDER, Comparators.naturalOrder());
private static final String KEY_LAST_USED_TUNNEL = "last_used_tunnel";
private static final String KEY_RESTORE_ON_BOOT = "restore_on_boot";
private static final String KEY_RUNNING_TUNNELS = "enabled_configs";
- private final CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> completableTunnels = new CompletableFuture<>();
+ private final CompletableFuture<ObservableSortedKeyedList<String, ObservableTunnel>> completableTunnels = new CompletableFuture<>();
private final ConfigStore configStore;
private final Context context = Application.get();
private final ArrayList<CompletableFuture<Void>> delayedLoadRestoreTunnels = new ArrayList<>();
- private final ObservableSortedKeyedList<String, Tunnel> tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR);
+ private final ObservableSortedKeyedList<String, ObservableTunnel> tunnels = new ObservableSortedKeyedArrayList<>(COMPARATOR);
private boolean haveLoaded;
- @Nullable private Tunnel lastUsedTunnel;
+ @Nullable private ObservableTunnel lastUsedTunnel;
public TunnelManager(final ConfigStore configStore) {
this.configStore = configStore;
+ Application.getBackendAsync().thenAccept(backend -> backend.registerStateChangeNotification(this));
}
- static CompletionStage<State> getTunnelState(final Tunnel tunnel) {
+ @Override
+ protected void finalize() throws Throwable {
+ Application.getBackendAsync().thenAccept(backend -> backend.unregisterStateChangeNotification(this));
+ super.finalize();
+ }
+
+ static CompletionStage<State> getTunnelState(final ObservableTunnel tunnel) {
return Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getState(tunnel))
.thenApply(tunnel::onStateChanged);
}
- static CompletionStage<Statistics> getTunnelStatistics(final Tunnel tunnel) {
+ static CompletionStage<Statistics> getTunnelStatistics(final ObservableTunnel tunnel) {
return Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getStatistics(tunnel))
.thenApply(tunnel::onStatisticsChanged);
}
- private Tunnel addToList(final String name, @Nullable final Config config, final State state) {
- final Tunnel tunnel = new Tunnel(this, name, config, state);
+ private ObservableTunnel addToList(final String name, @Nullable final Config config, final State state) {
+ final ObservableTunnel tunnel = new ObservableTunnel(this, name, config, state);
tunnels.add(tunnel);
return tunnel;
}
- public CompletionStage<Tunnel> create(final String name, @Nullable final Config config) {
+ public CompletionStage<ObservableTunnel> create(final String name, @Nullable final Config config) {
if (Tunnel.isNameInvalid(name))
return CompletableFuture.failedFuture(new IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_name)));
if (tunnels.containsKey(name)) {
@@ -84,7 +93,7 @@ public final class TunnelManager extends BaseObservable {
.thenApply(savedConfig -> addToList(name, savedConfig, State.DOWN));
}
- CompletionStage<Void> delete(final Tunnel tunnel) {
+ CompletionStage<Void> delete(final ObservableTunnel tunnel) {
final State originalState = tunnel.getState();
final boolean wasLastUsed = tunnel == lastUsedTunnel;
// Make sure nothing touches the tunnel.
@@ -93,12 +102,12 @@ public final class TunnelManager extends BaseObservable {
tunnels.remove(tunnel);
return Application.getAsyncWorker().runAsync(() -> {
if (originalState == State.UP)
- Application.getBackend().setState(tunnel, State.DOWN);
+ Application.getBackend().setState(tunnel, State.DOWN, null);
try {
configStore.delete(tunnel.getName());
} catch (final Exception e) {
if (originalState == State.UP)
- Application.getBackend().setState(tunnel, State.UP);
+ Application.getBackend().setState(tunnel, State.UP, tunnel.getConfig());
// Re-throw the exception to fail the completion.
throw e;
}
@@ -114,22 +123,22 @@ public final class TunnelManager extends BaseObservable {
@Bindable
@Nullable
- public Tunnel getLastUsedTunnel() {
+ public ObservableTunnel getLastUsedTunnel() {
return lastUsedTunnel;
}
- CompletionStage<Config> getTunnelConfig(final Tunnel tunnel) {
+ CompletionStage<Config> getTunnelConfig(final ObservableTunnel tunnel) {
return Application.getAsyncWorker().supplyAsync(() -> configStore.load(tunnel.getName()))
.thenApply(tunnel::onConfigChanged);
}
- public CompletableFuture<ObservableSortedKeyedList<String, Tunnel>> getTunnels() {
+ public CompletableFuture<ObservableSortedKeyedList<String, ObservableTunnel>> getTunnels() {
return completableTunnels;
}
public void onCreate() {
Application.getAsyncWorker().supplyAsync(configStore::enumerate)
- .thenAcceptBoth(Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().enumerate()), this::onTunnelsLoaded)
+ .thenAcceptBoth(Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getRunningTunnelNames()), this::onTunnelsLoaded)
.whenComplete(ExceptionLoggers.E);
}
@@ -159,9 +168,9 @@ public final class TunnelManager extends BaseObservable {
}
public void refreshTunnelStates() {
- Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().enumerate())
+ Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().getRunningTunnelNames())
.thenAccept(running -> {
- for (final Tunnel tunnel : tunnels)
+ for (final ObservableTunnel tunnel : tunnels)
tunnel.onStateChanged(running.contains(tunnel.getName()) ? State.UP : State.DOWN);
})
.whenComplete(ExceptionLoggers.E);
@@ -189,12 +198,12 @@ public final class TunnelManager extends BaseObservable {
public void saveState() {
final Set<String> runningTunnels = StreamSupport.stream(tunnels)
.filter(tunnel -> tunnel.getState() == State.UP)
- .map(Tunnel::getName)
+ .map(ObservableTunnel::getName)
.collect(Collectors.toUnmodifiableSet());
Application.getSharedPreferences().edit().putStringSet(KEY_RUNNING_TUNNELS, runningTunnels).apply();
}
- private void setLastUsedTunnel(@Nullable final Tunnel tunnel) {
+ private void setLastUsedTunnel(@Nullable final ObservableTunnel tunnel) {
if (tunnel == lastUsedTunnel)
return;
lastUsedTunnel = tunnel;
@@ -205,14 +214,14 @@ public final class TunnelManager extends BaseObservable {
Application.getSharedPreferences().edit().remove(KEY_LAST_USED_TUNNEL).apply();
}
- CompletionStage<Config> setTunnelConfig(final Tunnel tunnel, final Config config) {
+ CompletionStage<Config> setTunnelConfig(final ObservableTunnel tunnel, final Config config) {
return Application.getAsyncWorker().supplyAsync(() -> {
- final Config appliedConfig = Application.getBackend().applyConfig(tunnel, config);
- return configStore.save(tunnel.getName(), appliedConfig);
+ Application.getBackend().setState(tunnel, tunnel.getState(), config);
+ return configStore.save(tunnel.getName(), config);
}).thenApply(tunnel::onConfigChanged);
}
- CompletionStage<String> setTunnelName(final Tunnel tunnel, final String name) {
+ CompletionStage<String> setTunnelName(final ObservableTunnel tunnel, final String name) {
if (Tunnel.isNameInvalid(name))
return CompletableFuture.failedFuture(new IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_name)));
if (tunnels.containsKey(name)) {
@@ -227,11 +236,11 @@ public final class TunnelManager extends BaseObservable {
tunnels.remove(tunnel);
return Application.getAsyncWorker().supplyAsync(() -> {
if (originalState == State.UP)
- Application.getBackend().setState(tunnel, State.DOWN);
+ Application.getBackend().setState(tunnel, State.DOWN, null);
configStore.rename(tunnel.getName(), name);
final String newName = tunnel.onNameChanged(name);
if (originalState == State.UP)
- Application.getBackend().setState(tunnel, State.UP);
+ Application.getBackend().setState(tunnel, State.UP, tunnel.getConfig());
return newName;
}).whenComplete((newName, e) -> {
// On failure, we don't know what state the tunnel might be in. Fix that.
@@ -244,10 +253,10 @@ public final class TunnelManager extends BaseObservable {
});
}
- CompletionStage<State> setTunnelState(final Tunnel tunnel, final State state) {
+ CompletionStage<State> setTunnelState(final ObservableTunnel tunnel, final State state) {
// Ensure the configuration is loaded before trying to use it.
- return tunnel.getConfigAsync().thenCompose(x ->
- Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().setState(tunnel, state))
+ return tunnel.getConfigAsync().thenCompose(config ->
+ Application.getAsyncWorker().supplyAsync(() -> Application.getBackend().setState(tunnel, state, config))
).whenComplete((newState, e) -> {
// Ensure onStateChanged is always called (failure or not), and with the correct state.
tunnel.onStateChanged(e == null ? newState : tunnel.getState());
@@ -257,6 +266,11 @@ public final class TunnelManager extends BaseObservable {
});
}
+ @Override
+ public void tunnelStateChange(final Tunnel tunnel, final State state) {
+ ((ObservableTunnel)tunnel).onStateChanged(state);
+ }
+
public static final class IntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, @Nullable final Intent intent) {
@@ -290,7 +304,7 @@ public final class TunnelManager extends BaseObservable {
if (tunnelName == null)
return;
manager.getTunnels().thenAccept(tunnels -> {
- final Tunnel tunnel = tunnels.get(tunnelName);
+ final ObservableTunnel tunnel = tunnels.get(tunnelName);
if (tunnel == null)
return;
manager.setTunnelState(tunnel, state);