mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 19:59:05 +01:00
Merge branch '1328-reuse-port' into 'master'
Choose port in advance when providing wifi access point Closes #1328 See merge request briar/briar!1228
This commit is contained in:
@@ -32,6 +32,7 @@ import static android.content.Intent.ACTION_SCREEN_OFF;
|
|||||||
import static android.content.Intent.ACTION_SCREEN_ON;
|
import static android.content.Intent.ACTION_SCREEN_ON;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||||
|
import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
||||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
@@ -76,9 +77,9 @@ class AndroidNetworkManager implements NetworkManager, Service {
|
|||||||
filter.addAction(ACTION_SCREEN_ON);
|
filter.addAction(ACTION_SCREEN_ON);
|
||||||
filter.addAction(ACTION_SCREEN_OFF);
|
filter.addAction(ACTION_SCREEN_OFF);
|
||||||
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
|
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
|
||||||
|
filter.addAction(WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
|
||||||
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
|
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
|
||||||
appContext.registerReceiver(networkStateReceiver, filter);
|
appContext.registerReceiver(networkStateReceiver, filter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -136,7 +137,8 @@ class AndroidNetworkManager implements NetworkManager, Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isApEvent(@Nullable String action) {
|
private boolean isApEvent(@Nullable String action) {
|
||||||
return WIFI_AP_STATE_CHANGED_ACTION.equals(action);
|
return WIFI_AP_STATE_CHANGED_ACTION.equals(action) ||
|
||||||
|
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,19 +40,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(AndroidLanTcpPlugin.class.getName());
|
getLogger(AndroidLanTcpPlugin.class.getName());
|
||||||
|
|
||||||
private static final byte[] WIFI_AP_ADDRESS_BYTES =
|
|
||||||
{(byte) 192, (byte) 168, 43, 1};
|
|
||||||
private static final InetAddress WIFI_AP_ADDRESS;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
WIFI_AP_ADDRESS = InetAddress.getByAddress(WIFI_AP_ADDRESS_BYTES);
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
// Should only be thrown if the address has an illegal length
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Executor connectionStatusExecutor;
|
private final Executor connectionStatusExecutor;
|
||||||
private final ConnectivityManager connectivityManager;
|
private final ConnectivityManager connectivityManager;
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -62,8 +49,9 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
|||||||
|
|
||||||
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
|
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
|
||||||
Backoff backoff, PluginCallback callback, int maxLatency,
|
Backoff backoff, PluginCallback callback, int maxLatency,
|
||||||
int maxIdleTime) {
|
int maxIdleTime, int connectionTimeout) {
|
||||||
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
|
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime,
|
||||||
|
connectionTimeout);
|
||||||
// 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("AndroidLanTcpPlugin", ioExecutor, 1);
|
new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1);
|
||||||
@@ -79,6 +67,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void start() {
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
|
initialisePortProperty();
|
||||||
running = true;
|
running = true;
|
||||||
updateConnectionStatus();
|
updateConnectionStatus();
|
||||||
}
|
}
|
||||||
@@ -103,8 +92,11 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
|||||||
if (info != null && info.getIpAddress() != 0)
|
if (info != null && info.getIpAddress() != 0)
|
||||||
return singletonList(intToInetAddress(info.getIpAddress()));
|
return singletonList(intToInetAddress(info.getIpAddress()));
|
||||||
// If we're running an access point, return its address
|
// If we're running an access point, return its address
|
||||||
if (super.getLocalIpAddresses().contains(WIFI_AP_ADDRESS))
|
Collection<InetAddress> all = super.getLocalIpAddresses();
|
||||||
|
if (all.contains(WIFI_AP_ADDRESS))
|
||||||
return singletonList(WIFI_AP_ADDRESS);
|
return singletonList(WIFI_AP_ADDRESS);
|
||||||
|
if (all.contains(WIFI_DIRECT_AP_ADDRESS))
|
||||||
|
return singletonList(WIFI_DIRECT_AP_ADDRESS);
|
||||||
// No suitable addresses
|
// No suitable addresses
|
||||||
return emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
@@ -145,7 +137,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
|
|||||||
connectionStatusExecutor.execute(() -> {
|
connectionStatusExecutor.execute(() -> {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
Collection<InetAddress> addrs = getLocalIpAddresses();
|
Collection<InetAddress> addrs = getLocalIpAddresses();
|
||||||
if (addrs.contains(WIFI_AP_ADDRESS)) {
|
if (addrs.contains(WIFI_AP_ADDRESS)
|
||||||
|
|| addrs.contains(WIFI_DIRECT_AP_ADDRESS)) {
|
||||||
LOG.info("Providing wifi hotspot");
|
LOG.info("Providing wifi hotspot");
|
||||||
// There's no corresponding Network object and thus no way
|
// There's no corresponding Network object and thus no way
|
||||||
// to get a suitable socket factory, so we won't be able to
|
// to get a suitable socket factory, so we won't be able to
|
||||||
|
|||||||
@@ -21,10 +21,11 @@ import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
|
public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30_000; // 30 seconds
|
||||||
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
private static final int MAX_IDLE_TIME = 30_000; // 30 seconds
|
||||||
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
|
private static final int CONNECTION_TIMEOUT = 3_000; // 3 seconds
|
||||||
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
|
private static final int MIN_POLLING_INTERVAL = 60_000; // 1 minute
|
||||||
|
private static final int MAX_POLLING_INTERVAL = 600_000; // 10 mins
|
||||||
private static final double BACKOFF_BASE = 1.2;
|
private static final double BACKOFF_BASE = 1.2;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
@@ -55,7 +56,8 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
|
|||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,
|
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,
|
||||||
appContext, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME);
|
appContext, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME,
|
||||||
|
CONNECTION_TIMEOUT);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ public interface LanTcpConstants {
|
|||||||
|
|
||||||
TransportId ID = new TransportId("org.briarproject.bramble.lan");
|
TransportId ID = new TransportId("org.briarproject.bramble.lan");
|
||||||
|
|
||||||
// a transport property (shared with contacts)
|
// Transport properties (shared with contacts)
|
||||||
String PROP_IP_PORTS = "ipPorts";
|
String PROP_IP_PORTS = "ipPorts";
|
||||||
|
String PROP_PORT = "port";
|
||||||
|
|
||||||
// a local setting
|
// A local setting
|
||||||
String PREF_LAN_IP_PORTS = "ipPorts";
|
String PREF_LAN_IP_PORTS = "ipPorts";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,14 @@ import java.net.UnknownHostException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static java.lang.Integer.parseInt;
|
||||||
import static java.util.Collections.addAll;
|
import static java.util.Collections.addAll;
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
import static java.util.Collections.sort;
|
import static java.util.Collections.sort;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -37,6 +40,7 @@ import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TR
|
|||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
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.PREF_LAN_IP_PORTS;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
||||||
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_PORT;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
||||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
@@ -53,9 +57,33 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
private static final int MAX_ADDRESSES = 4;
|
private static final int MAX_ADDRESSES = 4;
|
||||||
private static final String SEPARATOR = ",";
|
private static final String SEPARATOR = ",";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IP address of an Android device providing a wifi access point.
|
||||||
|
*/
|
||||||
|
protected static final InetAddress WIFI_AP_ADDRESS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IP address of an Android device providing a wifi direct
|
||||||
|
* legacy mode access point.
|
||||||
|
*/
|
||||||
|
protected static final InetAddress WIFI_DIRECT_AP_ADDRESS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
WIFI_AP_ADDRESS = InetAddress.getByAddress(
|
||||||
|
new byte[] {(byte) 192, (byte) 168, 43, 1});
|
||||||
|
WIFI_DIRECT_AP_ADDRESS = InetAddress.getByAddress(
|
||||||
|
new byte[] {(byte) 192, (byte) 168, 49, 1});
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
// Should only be thrown if the address has an illegal length
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LanTcpPlugin(Executor ioExecutor, Backoff backoff, PluginCallback callback,
|
LanTcpPlugin(Executor ioExecutor, Backoff backoff, PluginCallback callback,
|
||||||
int maxLatency, int maxIdleTime) {
|
int maxLatency, int maxIdleTime, int connectionTimeout) {
|
||||||
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
|
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime,
|
||||||
|
connectionTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -64,19 +92,43 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<InetSocketAddress> getLocalSocketAddresses() {
|
public void start() {
|
||||||
// Use the same address and port as last time if available
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
|
initialisePortProperty();
|
||||||
|
running = true;
|
||||||
|
bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initialisePortProperty() {
|
||||||
TransportProperties p = callback.getLocalProperties();
|
TransportProperties p = callback.getLocalProperties();
|
||||||
|
if (isNullOrEmpty(p.get(PROP_PORT))) {
|
||||||
|
int port = new Random().nextInt(32768) + 32768;
|
||||||
|
p.put(PROP_PORT, String.valueOf(port));
|
||||||
|
callback.mergeLocalProperties(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<InetSocketAddress> getLocalSocketAddresses() {
|
||||||
|
TransportProperties p = callback.getLocalProperties();
|
||||||
|
int port = parsePortProperty(p.get(PROP_PORT));
|
||||||
String oldIpPorts = p.get(PROP_IP_PORTS);
|
String oldIpPorts = p.get(PROP_IP_PORTS);
|
||||||
List<InetSocketAddress> olds = parseSocketAddresses(oldIpPorts);
|
List<InetSocketAddress> olds = parseSocketAddresses(oldIpPorts);
|
||||||
List<InetSocketAddress> locals = new ArrayList<>();
|
List<InetSocketAddress> locals = new ArrayList<>();
|
||||||
for (InetAddress local : getLocalIpAddresses()) {
|
for (InetAddress local : getLocalIpAddresses()) {
|
||||||
if (isAcceptableAddress(local)) {
|
if (isAcceptableAddress(local)) {
|
||||||
// If this is the old address, try to use the same port
|
// If we've used this address before, try to use the same port
|
||||||
|
boolean reused = false;
|
||||||
for (InetSocketAddress old : olds) {
|
for (InetSocketAddress old : olds) {
|
||||||
if (old.getAddress().equals(local))
|
if (old.getAddress().equals(local)) {
|
||||||
locals.add(new InetSocketAddress(local, old.getPort()));
|
locals.add(new InetSocketAddress(local, old.getPort()));
|
||||||
|
reused = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Otherwise try to use our preferred port
|
||||||
|
if (!reused) locals.add(new InetSocketAddress(local, port));
|
||||||
|
// Fall back to any available port
|
||||||
locals.add(new InetSocketAddress(local, 0));
|
locals.add(new InetSocketAddress(local, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,11 +136,19 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
return locals;
|
return locals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int parsePortProperty(@Nullable String portProperty) {
|
||||||
|
if (isNullOrEmpty(portProperty)) return 0;
|
||||||
|
try {
|
||||||
|
return parseInt(portProperty);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<InetSocketAddress> parseSocketAddresses(String ipPorts) {
|
private List<InetSocketAddress> parseSocketAddresses(String ipPorts) {
|
||||||
if (isNullOrEmpty(ipPorts)) return emptyList();
|
|
||||||
String[] split = ipPorts.split(SEPARATOR);
|
|
||||||
List<InetSocketAddress> addresses = new ArrayList<>();
|
List<InetSocketAddress> addresses = new ArrayList<>();
|
||||||
for (String ipPort : split) {
|
if (isNullOrEmpty(ipPorts)) return addresses;
|
||||||
|
for (String ipPort : ipPorts.split(SEPARATOR)) {
|
||||||
InetSocketAddress a = parseSocketAddress(ipPort);
|
InetSocketAddress a = parseSocketAddress(ipPort);
|
||||||
if (a != null) addresses.add(a);
|
if (a != null) addresses.add(a);
|
||||||
}
|
}
|
||||||
@@ -132,7 +192,20 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
@Override
|
@Override
|
||||||
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
||||||
TransportProperties p) {
|
TransportProperties p) {
|
||||||
return parseSocketAddresses(p.get(PROP_IP_PORTS));
|
String ipPorts = p.get(PROP_IP_PORTS);
|
||||||
|
List<InetSocketAddress> remotes = parseSocketAddresses(ipPorts);
|
||||||
|
int port = parsePortProperty(p.get(PROP_PORT));
|
||||||
|
// If the contact has a preferred port, we can guess their IP:port when
|
||||||
|
// they're providing a wifi access point
|
||||||
|
if (port != 0) {
|
||||||
|
InetSocketAddress wifiAp =
|
||||||
|
new InetSocketAddress(WIFI_AP_ADDRESS, port);
|
||||||
|
if (!remotes.contains(wifiAp)) remotes.add(wifiAp);
|
||||||
|
InetSocketAddress wifiDirectAp =
|
||||||
|
new InetSocketAddress(WIFI_DIRECT_AP_ADDRESS, port);
|
||||||
|
if (!remotes.contains(wifiDirectAp)) remotes.add(wifiDirectAp);
|
||||||
|
}
|
||||||
|
return remotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAcceptableAddress(InetAddress a) {
|
private boolean isAcceptableAddress(InetAddress a) {
|
||||||
@@ -250,7 +323,7 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
LOG.info("Connecting to " + scrubSocketAddress(remote));
|
LOG.info("Connecting to " + scrubSocketAddress(remote));
|
||||||
Socket s = createSocket();
|
Socket s = createSocket();
|
||||||
s.bind(new InetSocketAddress(socket.getInetAddress(), 0));
|
s.bind(new InetSocketAddress(socket.getInetAddress(), 0));
|
||||||
s.connect(remote);
|
s.connect(remote, connectionTimeout);
|
||||||
s.setSoTimeout(socketTimeout);
|
s.setSoTimeout(socketTimeout);
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connected to " + scrubSocketAddress(remote));
|
LOG.info("Connected to " + scrubSocketAddress(remote));
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class LanTcpPluginFactory implements DuplexPluginFactory {
|
public class LanTcpPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30_000; // 30 seconds
|
||||||
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
private static final int MAX_IDLE_TIME = 30_000; // 30 seconds
|
||||||
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
|
private static final int CONNECTION_TIMEOUT = 3_000; // 3 seconds
|
||||||
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
|
private static final int MIN_POLLING_INTERVAL = 60_000; // 1 minute
|
||||||
|
private static final int MAX_POLLING_INTERVAL = 600_000; // 10 mins
|
||||||
private static final double BACKOFF_BASE = 1.2;
|
private static final double BACKOFF_BASE = 1.2;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
@@ -48,6 +49,6 @@ public class LanTcpPluginFactory implements DuplexPluginFactory {
|
|||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
return new LanTcpPlugin(ioExecutor, backoff, callback, MAX_LATENCY,
|
return new LanTcpPlugin(ioExecutor, backoff, callback, MAX_LATENCY,
|
||||||
MAX_IDLE_TIME);
|
MAX_IDLE_TIME, CONNECTION_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
protected final Executor ioExecutor, bindExecutor;
|
protected final Executor ioExecutor, bindExecutor;
|
||||||
protected final Backoff backoff;
|
protected final Backoff backoff;
|
||||||
protected final PluginCallback callback;
|
protected final PluginCallback callback;
|
||||||
protected final int maxLatency, maxIdleTime, socketTimeout;
|
protected final int maxLatency, maxIdleTime;
|
||||||
|
protected final int connectionTimeout, socketTimeout;
|
||||||
protected final AtomicBoolean used = new AtomicBoolean(false);
|
protected final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
protected volatile boolean running = false;
|
protected volatile boolean running = false;
|
||||||
@@ -86,15 +87,17 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
/**
|
/**
|
||||||
* Returns true if connections to the given address can be attempted.
|
* Returns true if connections to the given address can be attempted.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
protected abstract boolean isConnectable(InetSocketAddress remote);
|
protected abstract boolean isConnectable(InetSocketAddress remote);
|
||||||
|
|
||||||
TcpPlugin(Executor ioExecutor, Backoff backoff, PluginCallback callback,
|
TcpPlugin(Executor ioExecutor, Backoff backoff, PluginCallback callback,
|
||||||
int maxLatency, int maxIdleTime) {
|
int maxLatency, int maxIdleTime, int connectionTimeout) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
this.maxIdleTime = maxIdleTime;
|
this.maxIdleTime = maxIdleTime;
|
||||||
|
this.connectionTimeout = connectionTimeout;
|
||||||
if (maxIdleTime > Integer.MAX_VALUE / 2)
|
if (maxIdleTime > Integer.MAX_VALUE / 2)
|
||||||
socketTimeout = Integer.MAX_VALUE;
|
socketTimeout = Integer.MAX_VALUE;
|
||||||
else socketTimeout = maxIdleTime * 2;
|
else socketTimeout = maxIdleTime * 2;
|
||||||
@@ -231,6 +234,11 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
public DuplexTransportConnection createConnection(TransportProperties p) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
||||||
|
// Don't try to connect to our own address
|
||||||
|
if (!canConnectToOwnAddress() &&
|
||||||
|
remote.getAddress().equals(socket.getInetAddress())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!isConnectable(remote)) {
|
if (!isConnectable(remote)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
SocketAddress local = socket.getLocalSocketAddress();
|
SocketAddress local = socket.getLocalSocketAddress();
|
||||||
@@ -245,7 +253,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
LOG.info("Connecting to " + scrubSocketAddress(remote));
|
LOG.info("Connecting to " + scrubSocketAddress(remote));
|
||||||
Socket s = createSocket();
|
Socket s = createSocket();
|
||||||
s.bind(new InetSocketAddress(socket.getInetAddress(), 0));
|
s.bind(new InetSocketAddress(socket.getInetAddress(), 0));
|
||||||
s.connect(remote);
|
s.connect(remote, connectionTimeout);
|
||||||
s.setSoTimeout(socketTimeout);
|
s.setSoTimeout(socketTimeout);
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connected to " + scrubSocketAddress(remote));
|
LOG.info("Connected to " + scrubSocketAddress(remote));
|
||||||
@@ -259,6 +267,11 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override for testing
|
||||||
|
protected boolean canConnectToOwnAddress() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected Socket createSocket() throws IOException {
|
protected Socket createSocket() throws IOException {
|
||||||
return new Socket();
|
return new Socket();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,10 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
private volatile MappingResult mappingResult;
|
private volatile MappingResult mappingResult;
|
||||||
|
|
||||||
WanTcpPlugin(Executor ioExecutor, Backoff backoff, PortMapper portMapper,
|
WanTcpPlugin(Executor ioExecutor, Backoff backoff, PortMapper portMapper,
|
||||||
PluginCallback callback, int maxLatency, int maxIdleTime) {
|
PluginCallback callback, int maxLatency, int maxIdleTime,
|
||||||
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
|
int connectionTimeout) {
|
||||||
|
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime,
|
||||||
|
connectionTimeout);
|
||||||
this.portMapper = portMapper;
|
this.portMapper = portMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ import static org.briarproject.bramble.api.plugin.WanTcpConstants.ID;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class WanTcpPluginFactory implements DuplexPluginFactory {
|
public class WanTcpPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30_000; // 30 seconds
|
||||||
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
private static final int MAX_IDLE_TIME = 30_000; // 30 seconds
|
||||||
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
|
private static final int CONNECTION_TIMEOUT = 30_000; // 30 seconds
|
||||||
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
|
private static final int MIN_POLLING_INTERVAL = 60_000; // 1 minute
|
||||||
|
private static final int MAX_POLLING_INTERVAL = 600_000; // 10 mins
|
||||||
private static final double BACKOFF_BASE = 1.2;
|
private static final double BACKOFF_BASE = 1.2;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
@@ -52,6 +53,6 @@ public class WanTcpPluginFactory implements DuplexPluginFactory {
|
|||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
return new WanTcpPlugin(ioExecutor, backoff,
|
return new WanTcpPlugin(ioExecutor, backoff,
|
||||||
new PortMapperImpl(shutdownManager), callback, MAX_LATENCY,
|
new PortMapperImpl(shutdownManager), callback, MAX_LATENCY,
|
||||||
MAX_IDLE_TIME);
|
MAX_IDLE_TIME, CONNECTION_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import org.briarproject.bramble.api.plugin.Backoff;
|
|||||||
import org.briarproject.bramble.api.plugin.PluginCallback;
|
import org.briarproject.bramble.api.plugin.PluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
import org.briarproject.bramble.plugin.tcp.LanTcpPlugin.LanAddressComparator;
|
import org.briarproject.bramble.plugin.tcp.LanTcpPlugin.LanAddressComparator;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -37,17 +37,29 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
public class LanTcpPluginTest extends BrambleTestCase {
|
public class LanTcpPluginTest extends BrambleTestCase {
|
||||||
|
|
||||||
private final Backoff backoff = new TestBackoff();
|
private final Backoff backoff = new TestBackoff();
|
||||||
private final ExecutorService ioExecutor = newCachedThreadPool();
|
private final ExecutorService ioExecutor = newCachedThreadPool();
|
||||||
|
|
||||||
|
private Callback callback = null;
|
||||||
|
private LanTcpPlugin plugin = null;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
callback = new Callback();
|
||||||
|
plugin = new LanTcpPlugin(ioExecutor, backoff, callback, 0, 0, 1000) {
|
||||||
|
@Override
|
||||||
|
protected boolean canConnectToOwnAddress() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddressesAreOnSameLan() {
|
public void testAddressesAreOnSameLan() {
|
||||||
Callback callback = new Callback();
|
|
||||||
LanTcpPlugin plugin = new LanTcpPlugin(ioExecutor, backoff, callback,
|
|
||||||
0, 0);
|
|
||||||
// Local and remote in 10.0.0.0/8 should return true
|
// Local and remote in 10.0.0.0/8 should return true
|
||||||
assertTrue(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0),
|
assertTrue(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0),
|
||||||
makeAddress(10, 255, 255, 255)));
|
makeAddress(10, 255, 255, 255)));
|
||||||
@@ -93,13 +105,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncomingConnection() throws Exception {
|
public void testIncomingConnection() throws Exception {
|
||||||
if (!systemHasLocalIpv4Address()) {
|
assumeTrue(systemHasLocalIpv4Address());
|
||||||
System.err.println("WARNING: Skipping test, no local IPv4 address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Callback callback = new Callback();
|
|
||||||
DuplexPlugin plugin = new LanTcpPlugin(ioExecutor, backoff, callback,
|
|
||||||
0, 0);
|
|
||||||
plugin.start();
|
plugin.start();
|
||||||
// The plugin should have bound a socket and stored the port number
|
// The plugin should have bound a socket and stored the port number
|
||||||
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
||||||
@@ -128,13 +134,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutgoingConnection() throws Exception {
|
public void testOutgoingConnection() throws Exception {
|
||||||
if (!systemHasLocalIpv4Address()) {
|
assumeTrue(systemHasLocalIpv4Address());
|
||||||
System.err.println("WARNING: Skipping test, no local IPv4 address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Callback callback = new Callback();
|
|
||||||
DuplexPlugin plugin = new LanTcpPlugin(ioExecutor, backoff, callback,
|
|
||||||
0, 0);
|
|
||||||
plugin.start();
|
plugin.start();
|
||||||
// The plugin should have bound a socket and stored the port number
|
// The plugin should have bound a socket and stored the port number
|
||||||
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
||||||
@@ -177,13 +177,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncomingKeyAgreementConnection() throws Exception {
|
public void testIncomingKeyAgreementConnection() throws Exception {
|
||||||
if (!systemHasLocalIpv4Address()) {
|
assumeTrue(systemHasLocalIpv4Address());
|
||||||
System.err.println("WARNING: Skipping test, no local IPv4 address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Callback callback = new Callback();
|
|
||||||
DuplexPlugin plugin = new LanTcpPlugin(ioExecutor, backoff, callback,
|
|
||||||
0, 0);
|
|
||||||
plugin.start();
|
plugin.start();
|
||||||
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
||||||
KeyAgreementListener kal =
|
KeyAgreementListener kal =
|
||||||
@@ -225,13 +219,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutgoingKeyAgreementConnection() throws Exception {
|
public void testOutgoingKeyAgreementConnection() throws Exception {
|
||||||
if (!systemHasLocalIpv4Address()) {
|
assumeTrue(systemHasLocalIpv4Address());
|
||||||
System.err.println("WARNING: Skipping test, no local IPv4 address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Callback callback = new Callback();
|
|
||||||
DuplexPlugin plugin = new LanTcpPlugin(ioExecutor, backoff, callback,
|
|
||||||
0, 0);
|
|
||||||
plugin.start();
|
plugin.start();
|
||||||
// The plugin should have bound a socket and stored the port number
|
// The plugin should have bound a socket and stored the port number
|
||||||
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
||||||
@@ -340,7 +328,9 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
private static class Callback implements PluginCallback {
|
private static class Callback implements PluginCallback {
|
||||||
|
|
||||||
private final CountDownLatch propertiesLatch = new CountDownLatch(1);
|
// Properties will be stored twice: the preferred port at startup,
|
||||||
|
// and the IP:port when the server socket is bound
|
||||||
|
private final CountDownLatch propertiesLatch = new CountDownLatch(2);
|
||||||
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
||||||
private final TransportProperties local = new TransportProperties();
|
private final TransportProperties local = new TransportProperties();
|
||||||
|
|
||||||
|
|||||||
@@ -230,6 +230,8 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
sb.append(getRandomLanAddress());
|
sb.append(getRandomLanAddress());
|
||||||
}
|
}
|
||||||
lan.put(LanTcpConstants.PROP_IP_PORTS, sb.toString());
|
lan.put(LanTcpConstants.PROP_IP_PORTS, sb.toString());
|
||||||
|
String port = String.valueOf(getRandomPortNumber());
|
||||||
|
lan.put(LanTcpConstants.PROP_PORT, port);
|
||||||
props.put(LanTcpConstants.ID, lan);
|
props.put(LanTcpConstants.ID, lan);
|
||||||
|
|
||||||
// Tor
|
// Tor
|
||||||
@@ -266,18 +268,21 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
sb.append("10.");
|
sb.append("10.");
|
||||||
sb.append(random.nextInt(2)).append('.');
|
sb.append(random.nextInt(2)).append('.');
|
||||||
sb.append(random.nextInt(2)).append('.');
|
sb.append(random.nextInt(2)).append('.');
|
||||||
sb.append(random.nextInt(256));
|
sb.append(random.nextInt(255));
|
||||||
} else {
|
} else {
|
||||||
sb.append("192.168.");
|
sb.append("192.168.");
|
||||||
sb.append(random.nextInt(2)).append('.');
|
sb.append(random.nextInt(2)).append('.');
|
||||||
sb.append(random.nextInt(256));
|
sb.append(random.nextInt(255));
|
||||||
}
|
}
|
||||||
// port
|
// port
|
||||||
sb.append(":");
|
sb.append(':').append(getRandomPortNumber());
|
||||||
sb.append(1024 + random.nextInt(50000));
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getRandomPortNumber() {
|
||||||
|
return 32768 + random.nextInt(32768);
|
||||||
|
}
|
||||||
|
|
||||||
private String getRandomTorAddress() {
|
private String getRandomTorAddress() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
// address
|
// address
|
||||||
|
|||||||
Reference in New Issue
Block a user