mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 20:29:52 +01:00
Created Android-specific LAN TCP plugin in order to enable multicast.
Some Android devices require a lock to be held while using multicast, to disable the packet filter that normally filters out multicast packets.
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<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.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||||
|
|
||||||
|
|||||||
@@ -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.SimplexPluginConfig;
|
||||||
import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
|
import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
|
||||||
import net.sf.briar.plugins.droidtooth.DroidtoothPluginFactory;
|
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.tcp.WanTcpPluginFactory;
|
||||||
import net.sf.briar.plugins.tor.TorPluginFactory;
|
import net.sf.briar.plugins.tor.TorPluginFactory;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -71,7 +71,8 @@ public class AndroidModule extends AbstractModule {
|
|||||||
crypto.getSecureRandom());
|
crypto.getSecureRandom());
|
||||||
DuplexPluginFactory tor = new TorPluginFactory(pluginExecutor,
|
DuplexPluginFactory tor = new TorPluginFactory(pluginExecutor,
|
||||||
appContext, shutdownManager);
|
appContext, shutdownManager);
|
||||||
DuplexPluginFactory lan = new LanTcpPluginFactory(pluginExecutor);
|
DuplexPluginFactory lan = new DroidLanTcpPluginFactory(pluginExecutor,
|
||||||
|
appContext);
|
||||||
DuplexPluginFactory wan = new WanTcpPluginFactory(pluginExecutor,
|
DuplexPluginFactory wan = new WanTcpPluginFactory(pluginExecutor,
|
||||||
shutdownManager);
|
shutdownManager);
|
||||||
final Collection<DuplexPluginFactory> factories =
|
final Collection<DuplexPluginFactory> factories =
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -136,6 +136,7 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
if(ms != null) tryToClose(ms, mcast.getAddress());
|
if(ms != null) tryToClose(ms, mcast.getAddress());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if(LOG.isLoggable(INFO)) LOG.info("Listening for multicast packets");
|
||||||
// Listen until a valid packet is received or the timeout occurs
|
// Listen until a valid packet is received or the timeout occurs
|
||||||
byte[] buffer = new byte[2];
|
byte[] buffer = new byte[2];
|
||||||
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
||||||
@@ -150,10 +151,15 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
int off = packet.getOffset();
|
int off = packet.getOffset();
|
||||||
int len = packet.getLength();
|
int len = packet.getLength();
|
||||||
int port = parsePacket(b, off, len);
|
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) {
|
if(port >= 32768 && port < 65536) {
|
||||||
try {
|
try {
|
||||||
// Connect back on the advertised TCP port
|
// Connect back on the advertised TCP port
|
||||||
Socket s = new Socket(packet.getAddress(), port);
|
Socket s = new Socket(packet.getAddress(), port);
|
||||||
|
if(LOG.isLoggable(INFO)) LOG.info("Connected back");
|
||||||
return new TcpTransportConnection(s, maxLatency);
|
return new TcpTransportConnection(s, maxLatency);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if(LOG.isLoggable(WARNING))
|
||||||
@@ -161,6 +167,7 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(SocketTimeoutException e) {
|
} catch(SocketTimeoutException e) {
|
||||||
|
if(LOG.isLoggable(INFO)) LOG.info("Timed out");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
now = clock.currentTimeMillis();
|
now = clock.currentTimeMillis();
|
||||||
@@ -282,11 +289,17 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
try {
|
try {
|
||||||
int wait = (int) (Math.min(end, nextPacket) - now);
|
int wait = (int) (Math.min(end, nextPacket) - now);
|
||||||
ss.setSoTimeout(wait < 1 ? 1 : wait);
|
ss.setSoTimeout(wait < 1 ? 1 : wait);
|
||||||
|
if(LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Listening for TCP connections: " + wait);
|
||||||
Socket s = ss.accept();
|
Socket s = ss.accept();
|
||||||
|
if(LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Received a TCP connection");
|
||||||
return new TcpTransportConnection(s, maxLatency);
|
return new TcpTransportConnection(s, maxLatency);
|
||||||
} catch(SocketTimeoutException e) {
|
} catch(SocketTimeoutException e) {
|
||||||
now = clock.currentTimeMillis();
|
now = clock.currentTimeMillis();
|
||||||
if(now < end) {
|
if(now < end) {
|
||||||
|
if(LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Sending multicast packet");
|
||||||
ms.send(packet);
|
ms.send(packet);
|
||||||
now = clock.currentTimeMillis();
|
now = clock.currentTimeMillis();
|
||||||
nextPacket = now + MULTICAST_INTERVAL;
|
nextPacket = now + MULTICAST_INTERVAL;
|
||||||
|
|||||||
Reference in New Issue
Block a user