diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index 2f5e0d87b53bc775d9c0cb23bd9fdc4491a0da2b..70d79d2fa924a6fa2b4b08750d75154181da6985 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -9,6 +9,7 @@ <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> diff --git a/briar-android/src/net/sf/briar/android/AndroidModule.java b/briar-android/src/net/sf/briar/android/AndroidModule.java index 06dbc4bcfa2763637f0143e217bece04442dac05..afac6d63c65d077ae8691d71c453b5aa33b0483f 100644 --- a/briar-android/src/net/sf/briar/android/AndroidModule.java +++ b/briar-android/src/net/sf/briar/android/AndroidModule.java @@ -23,7 +23,7 @@ import net.sf.briar.api.plugins.duplex.DuplexPluginFactory; import net.sf.briar.api.plugins.simplex.SimplexPluginConfig; import net.sf.briar.api.plugins.simplex.SimplexPluginFactory; import net.sf.briar.plugins.droidtooth.DroidtoothPluginFactory; -import net.sf.briar.plugins.tcp.LanTcpPluginFactory; +import net.sf.briar.plugins.tcp.DroidLanTcpPluginFactory; import net.sf.briar.plugins.tcp.WanTcpPluginFactory; import net.sf.briar.plugins.tor.TorPluginFactory; import android.content.Context; @@ -71,7 +71,8 @@ public class AndroidModule extends AbstractModule { crypto.getSecureRandom()); DuplexPluginFactory tor = new TorPluginFactory(pluginExecutor, appContext, shutdownManager); - DuplexPluginFactory lan = new LanTcpPluginFactory(pluginExecutor); + DuplexPluginFactory lan = new DroidLanTcpPluginFactory(pluginExecutor, + appContext); DuplexPluginFactory wan = new WanTcpPluginFactory(pluginExecutor, shutdownManager); final Collection<DuplexPluginFactory> factories = diff --git a/briar-core/src/net/sf/briar/plugins/tcp/DroidLanTcpPlugin.java b/briar-core/src/net/sf/briar/plugins/tcp/DroidLanTcpPlugin.java new file mode 100644 index 0000000000000000000000000000000000000000..818472cbd7567f462cb3a54584756d64dd394e0c --- /dev/null +++ b/briar-core/src/net/sf/briar/plugins/tcp/DroidLanTcpPlugin.java @@ -0,0 +1,55 @@ +package net.sf.briar.plugins.tcp; + +import static android.content.Context.WIFI_SERVICE; + +import java.util.concurrent.Executor; + +import net.sf.briar.api.clock.Clock; +import net.sf.briar.api.crypto.PseudoRandom; +import net.sf.briar.api.plugins.duplex.DuplexPluginCallback; +import net.sf.briar.api.plugins.duplex.DuplexTransportConnection; +import android.content.Context; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.MulticastLock; + +class DroidLanTcpPlugin extends LanTcpPlugin { + + private final Context appContext; + + DroidLanTcpPlugin(Executor pluginExecutor, Context appContext, Clock clock, + DuplexPluginCallback callback, long maxLatency, + long pollingInterval) { + super(pluginExecutor, clock, callback, maxLatency, pollingInterval); + this.appContext = appContext; + } + + @Override + public DuplexTransportConnection sendInvitation(PseudoRandom r, + long timeout) { + WifiManager wifi = + (WifiManager) appContext.getSystemService(WIFI_SERVICE); + if(wifi == null || !wifi.isWifiEnabled()) return null; + MulticastLock lock = wifi.createMulticastLock("invitation"); + lock.acquire(); + try { + return super.sendInvitation(r, timeout); + } finally { + lock.release(); + } + } + + @Override + public DuplexTransportConnection acceptInvitation(PseudoRandom r, + long timeout) { + WifiManager wifi = + (WifiManager) appContext.getSystemService(WIFI_SERVICE); + if(wifi == null || !wifi.isWifiEnabled()) return null; + MulticastLock lock = wifi.createMulticastLock("invitation"); + lock.acquire(); + try { + return super.acceptInvitation(r, timeout); + } finally { + lock.release(); + } + } +} diff --git a/briar-core/src/net/sf/briar/plugins/tcp/DroidLanTcpPluginFactory.java b/briar-core/src/net/sf/briar/plugins/tcp/DroidLanTcpPluginFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..44d4881658423ef1146d74afb3bc1f31f2889885 --- /dev/null +++ b/briar-core/src/net/sf/briar/plugins/tcp/DroidLanTcpPluginFactory.java @@ -0,0 +1,37 @@ +package net.sf.briar.plugins.tcp; + +import java.util.concurrent.Executor; + +import net.sf.briar.api.TransportId; +import net.sf.briar.api.clock.Clock; +import net.sf.briar.api.clock.SystemClock; +import net.sf.briar.api.plugins.duplex.DuplexPlugin; +import net.sf.briar.api.plugins.duplex.DuplexPluginCallback; +import net.sf.briar.api.plugins.duplex.DuplexPluginFactory; +import android.content.Context; + +public class DroidLanTcpPluginFactory implements DuplexPluginFactory { + + private static final long MAX_LATENCY = 60 * 1000; // 1 minute + private static final long POLLING_INTERVAL = 60 * 1000; // 1 minute + + private final Executor pluginExecutor; + private final Context appContext; + private final Clock clock; + + public DroidLanTcpPluginFactory(Executor pluginExecutor, + Context appContext) { + this.pluginExecutor = pluginExecutor; + this.appContext = appContext; + clock = new SystemClock(); + } + + public TransportId getId() { + return LanTcpPlugin.ID; + } + + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { + return new DroidLanTcpPlugin(pluginExecutor, appContext, clock, + callback, MAX_LATENCY, POLLING_INTERVAL); + } +} diff --git a/briar-core/src/net/sf/briar/plugins/tcp/LanTcpPlugin.java b/briar-core/src/net/sf/briar/plugins/tcp/LanTcpPlugin.java index aeb307c6f49fd902d0f1489ed754caef615caba6..b81250fd13673c0bcedbefa341fd44a82d6b1aad 100644 --- a/briar-core/src/net/sf/briar/plugins/tcp/LanTcpPlugin.java +++ b/briar-core/src/net/sf/briar/plugins/tcp/LanTcpPlugin.java @@ -136,6 +136,7 @@ class LanTcpPlugin extends TcpPlugin { if(ms != null) tryToClose(ms, mcast.getAddress()); return null; } + if(LOG.isLoggable(INFO)) LOG.info("Listening for multicast packets"); // Listen until a valid packet is received or the timeout occurs byte[] buffer = new byte[2]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); @@ -150,10 +151,15 @@ class LanTcpPlugin extends TcpPlugin { int off = packet.getOffset(); int len = packet.getLength(); int port = parsePacket(b, off, len); + if(LOG.isLoggable(INFO)){ + String addr = getHostAddress(packet.getAddress()); + LOG.info("Received a packet from " + addr + ":" + port); + } if(port >= 32768 && port < 65536) { try { // Connect back on the advertised TCP port Socket s = new Socket(packet.getAddress(), port); + if(LOG.isLoggable(INFO)) LOG.info("Connected back"); return new TcpTransportConnection(s, maxLatency); } catch(IOException e) { if(LOG.isLoggable(WARNING)) @@ -161,6 +167,7 @@ class LanTcpPlugin extends TcpPlugin { } } } catch(SocketTimeoutException e) { + if(LOG.isLoggable(INFO)) LOG.info("Timed out"); break; } now = clock.currentTimeMillis(); @@ -282,11 +289,17 @@ class LanTcpPlugin extends TcpPlugin { try { int wait = (int) (Math.min(end, nextPacket) - now); ss.setSoTimeout(wait < 1 ? 1 : wait); + if(LOG.isLoggable(INFO)) + LOG.info("Listening for TCP connections: " + wait); Socket s = ss.accept(); + if(LOG.isLoggable(INFO)) + LOG.info("Received a TCP connection"); return new TcpTransportConnection(s, maxLatency); } catch(SocketTimeoutException e) { now = clock.currentTimeMillis(); if(now < end) { + if(LOG.isLoggable(INFO)) + LOG.info("Sending multicast packet"); ms.send(packet); now = clock.currentTimeMillis(); nextPacket = now + MULTICAST_INTERVAL;