diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java index ca6b4f6a85b8d56d2d3f1328437d4b1e5f1e6333..c6eba28c7d8f9508e799fe1861f047b1efa4e09f 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java @@ -4,6 +4,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -11,16 +14,22 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.Backoff; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback; +import java.io.IOException; import java.net.InetAddress; +import java.net.Socket; import java.net.UnknownHostException; import java.util.Collection; import java.util.concurrent.Executor; import java.util.logging.Logger; import javax.annotation.Nullable; +import javax.net.SocketFactory; +import static android.content.Context.CONNECTIVITY_SERVICE; import static android.content.Context.WIFI_SERVICE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.os.Build.VERSION.SDK_INT; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -31,19 +40,26 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { Logger.getLogger(AndroidLanTcpPlugin.class.getName()); private final Context appContext; + private final ConnectivityManager connectivityManager; @Nullable private final WifiManager wifiManager; @Nullable private volatile BroadcastReceiver networkStateReceiver = null; + private volatile SocketFactory socketFactory; AndroidLanTcpPlugin(Executor ioExecutor, Backoff backoff, Context appContext, DuplexPluginCallback callback, int maxLatency, int maxIdleTime) { super(ioExecutor, backoff, callback, maxLatency, maxIdleTime); this.appContext = appContext; + ConnectivityManager connectivityManager = (ConnectivityManager) + appContext.getSystemService(CONNECTIVITY_SERVICE); + if (connectivityManager == null) throw new AssertionError(); + this.connectivityManager = connectivityManager; wifiManager = (WifiManager) appContext.getApplicationContext() .getSystemService(WIFI_SERVICE); + socketFactory = getSocketFactory(); } @Override @@ -64,6 +80,11 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { tryToClose(socket); } + @Override + protected Socket createSocket() throws IOException { + return socketFactory.createSocket(); + } + @Override protected Collection<InetAddress> getLocalIpAddresses() { if (wifiManager == null) return emptyList(); @@ -86,6 +107,19 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { } } + // On API 21 and later, a socket that is not created with the wifi + // network's socket factory may try to connect via another network + private SocketFactory getSocketFactory() { + if (SDK_INT < 21) return SocketFactory.getDefault(); + for (Network net : connectivityManager.getAllNetworks()) { + NetworkInfo info = connectivityManager.getNetworkInfo(net); + if (info != null && info.getType() == TYPE_WIFI) + return net.getSocketFactory(); + } + LOG.warning("Could not find suitable socket factory"); + return SocketFactory.getDefault(); + } + private class NetworkStateReceiver extends BroadcastReceiver { @Override @@ -94,9 +128,11 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { WifiInfo info = wifiManager.getConnectionInfo(); if (info == null || info.getIpAddress() == 0) { LOG.info("Not connected to wifi"); + socketFactory = SocketFactory.getDefault(); tryToClose(socket); } else { LOG.info("Connected to wifi"); + socketFactory = getSocketFactory(); if (socket == null || socket.isClosed()) bind(); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java index 450367381a4562ebfd0d590fc1c67c5ffc7dd0df..192a43c3d9ad66500a3ebd54d0c33710eaa977ed 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java @@ -241,10 +241,11 @@ class LanTcpPlugin extends TcpPlugin { } return null; } - Socket s = new Socket(); try { if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + scrubSocketAddress(remote)); + Socket s = createSocket(); + s.bind(new InetSocketAddress(socket.getInetAddress(), 0)); s.connect(remote); s.setSoTimeout(socketTimeout); if (LOG.isLoggable(INFO)) 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 9b686fc86d6571f2854389eee4ba72c3b743781b..8b861164df2dd4144bccbea99d0953793e085d8e 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 @@ -243,10 +243,11 @@ abstract class TcpPlugin implements DuplexPlugin { } continue; } - Socket s = new Socket(); try { if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + scrubSocketAddress(remote)); + Socket s = createSocket(); + s.bind(new InetSocketAddress(socket.getInetAddress(), 0)); s.connect(remote); s.setSoTimeout(socketTimeout); if (LOG.isLoggable(INFO)) @@ -261,6 +262,10 @@ abstract class TcpPlugin implements DuplexPlugin { return null; } + protected Socket createSocket() throws IOException { + return new Socket(); + } + @Nullable InetSocketAddress parseSocketAddress(String ipPort) { if (StringUtils.isNullOrEmpty(ipPort)) return null;