LAN plugin should re-bind each time wifi becomes available. Bug #51.

This commit is contained in:
akwizgran
2014-04-04 18:58:14 +01:00
parent e260aac3d2
commit 75ce6cf1da
5 changed files with 153 additions and 48 deletions

View File

@@ -15,7 +15,7 @@ import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
import org.briarproject.api.system.LocationUtils; import org.briarproject.api.system.LocationUtils;
import org.briarproject.plugins.droidtooth.DroidtoothPluginFactory; import org.briarproject.plugins.droidtooth.DroidtoothPluginFactory;
import org.briarproject.plugins.tcp.LanTcpPluginFactory; import org.briarproject.plugins.tcp.AndroidLanTcpPluginFactory;
import org.briarproject.plugins.tor.TorPluginFactory; import org.briarproject.plugins.tor.TorPluginFactory;
import android.app.Application; import android.app.Application;
@@ -44,14 +44,15 @@ public class AndroidPluginsModule extends AbstractModule {
CryptoComponent crypto, LocationUtils locationUtils, CryptoComponent crypto, LocationUtils locationUtils,
ShutdownManager shutdownManager) { ShutdownManager shutdownManager) {
Context appContext = app.getApplicationContext(); Context appContext = app.getApplicationContext();
DuplexPluginFactory droidtooth = new DroidtoothPluginFactory( DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(
pluginExecutor, androidExecutor, appContext, pluginExecutor, androidExecutor, appContext,
crypto.getSecureRandom()); crypto.getSecureRandom());
DuplexPluginFactory tor = new TorPluginFactory(pluginExecutor, DuplexPluginFactory tor = new TorPluginFactory(pluginExecutor,
appContext, locationUtils, shutdownManager); appContext, locationUtils, shutdownManager);
DuplexPluginFactory lan = new LanTcpPluginFactory(pluginExecutor); DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(
pluginExecutor, appContext);
final Collection<DuplexPluginFactory> factories = final Collection<DuplexPluginFactory> factories =
Arrays.asList(droidtooth, tor, lan); Arrays.asList(bluetooth, tor, lan);
return new DuplexPluginConfig() { return new DuplexPluginConfig() {
public Collection<DuplexPluginFactory> getFactories() { public Collection<DuplexPluginFactory> getFactories() {
return factories; return factories;

View File

@@ -0,0 +1,71 @@
package org.briarproject.plugins.tcp;
import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
class AndroidLanTcpPlugin extends LanTcpPlugin {
private static final Logger LOG =
Logger.getLogger(AndroidLanTcpPlugin.class.getName());
private final Context appContext;
private volatile BroadcastReceiver networkStateReceiver = null;
AndroidLanTcpPlugin(Executor pluginExecutor, Context appContext,
DuplexPluginCallback callback, int maxFrameLength, long maxLatency,
long pollingInterval) {
super(pluginExecutor, callback, maxFrameLength, maxLatency,
pollingInterval);
this.appContext = appContext;
}
@Override
public boolean start() {
running = true;
// Register to receive network status events
networkStateReceiver = new NetworkStateReceiver();
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
appContext.registerReceiver(networkStateReceiver, filter);
return true;
}
@Override
public void stop() {
running = false;
if(networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver);
tryToClose(socket);
}
private class NetworkStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent i) {
if(!running) return;
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
ConnectivityManager cm = (ConnectivityManager) o;
NetworkInfo net = cm.getActiveNetworkInfo();
if(net != null && net.getType() == TYPE_WIFI && net.isConnected()) {
LOG.info("Connected to Wi-Fi");
if(socket == null || socket.isClosed()) bind();
} else {
LOG.info("Not connected to Wi-Fi");
tryToClose(socket);
}
}
}
}

View File

@@ -0,0 +1,35 @@
package org.briarproject.plugins.tcp;
import java.util.concurrent.Executor;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
import android.content.Context;
public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private static final int MAX_FRAME_LENGTH = 1024;
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;
public AndroidLanTcpPluginFactory(Executor pluginExecutor,
Context appContext) {
this.pluginExecutor = pluginExecutor;
this.appContext = appContext;
}
public TransportId getId() {
return LanTcpPlugin.ID;
}
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
return new AndroidLanTcpPlugin(pluginExecutor, appContext, callback,
MAX_FRAME_LENGTH, MAX_LATENCY, POLLING_INTERVAL);
}
}

View File

@@ -18,7 +18,6 @@ import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties; import org.briarproject.api.TransportProperties;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
/** A TCP plugin that supports exchanging invitations over a LAN. */
class LanTcpPlugin extends TcpPlugin { class LanTcpPlugin extends TcpPlugin {
static final TransportId ID = new TransportId("lan"); static final TransportId ID = new TransportId("lan");

View File

@@ -38,7 +38,7 @@ abstract class TcpPlugin implements DuplexPlugin {
protected final long maxLatency, pollingInterval; protected final long maxLatency, pollingInterval;
protected volatile boolean running = false; protected volatile boolean running = false;
private volatile ServerSocket socket = null; protected volatile ServerSocket socket = null;
/** /**
* Returns zero or more socket addresses on which the plugin should listen, * Returns zero or more socket addresses on which the plugin should listen,
@@ -65,47 +65,47 @@ abstract class TcpPlugin implements DuplexPlugin {
public boolean start() { public boolean start() {
running = true; running = true;
pluginExecutor.execute(new Runnable() { bind();
public void run() {
bind();
}
});
return true; return true;
} }
private void bind() { protected void bind() {
ServerSocket ss = null; pluginExecutor.execute(new Runnable() {
boolean found = false; public void run() {
for(SocketAddress addr : getLocalSocketAddresses()) { if(!running) return;
try { ServerSocket ss = null;
ss = new ServerSocket(); for(SocketAddress addr : getLocalSocketAddresses()) {
ss.bind(addr); try {
found = true; ss = new ServerSocket();
break; ss.bind(addr);
} catch(IOException e) { break;
if(LOG.isLoggable(INFO)) LOG.info("Failed to bind " + addr); } catch(IOException e) {
tryToClose(ss); if(LOG.isLoggable(INFO))
continue; LOG.info("Failed to bind " + addr);
tryToClose(ss);
continue;
}
}
if(ss == null || !ss.isBound()) {
LOG.info("Could not bind server socket");
return;
}
if(!running) {
tryToClose(ss);
return;
}
socket = ss;
SocketAddress local = ss.getLocalSocketAddress();
setLocalSocketAddress((InetSocketAddress) local);
if(LOG.isLoggable(INFO)) LOG.info("Listening on " + local);
acceptContactConnections();
} }
} });
if(!found) {
LOG.info("Could not bind server socket");
return;
}
if(!running) {
tryToClose(ss);
return;
}
socket = ss;
if(LOG.isLoggable(INFO))
LOG.info("Listening on " + ss.getLocalSocketAddress());
setLocalSocketAddress((InetSocketAddress) ss.getLocalSocketAddress());
acceptContactConnections(ss);
} }
protected void tryToClose(ServerSocket ss) { protected void tryToClose(ServerSocket ss) {
try { try {
ss.close(); if(ss != null) ss.close();
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
@@ -124,32 +124,31 @@ abstract class TcpPlugin implements DuplexPlugin {
callback.mergeLocalProperties(p); callback.mergeLocalProperties(p);
} }
private void acceptContactConnections(ServerSocket ss) { private void acceptContactConnections() {
while(true) { while(isRunning()) {
Socket s; Socket s;
try { try {
s = ss.accept(); s = socket.accept();
} catch(IOException e) { } catch(IOException e) {
// This is expected when the socket is closed // This is expected when the socket is closed
if(LOG.isLoggable(INFO)) LOG.info(e.toString()); if(LOG.isLoggable(INFO)) LOG.info(e.toString());
tryToClose(ss); tryToClose(socket);
return; return;
} }
if(LOG.isLoggable(INFO)) if(LOG.isLoggable(INFO))
LOG.info("Connection from " + s.getRemoteSocketAddress()); LOG.info("Connection from " + s.getRemoteSocketAddress());
TcpTransportConnection conn = new TcpTransportConnection(this, s); TcpTransportConnection conn = new TcpTransportConnection(this, s);
callback.incomingConnectionCreated(conn); callback.incomingConnectionCreated(conn);
if(!running) return;
} }
} }
public void stop() { public void stop() {
running = false; running = false;
if(socket != null) tryToClose(socket); tryToClose(socket);
} }
public boolean isRunning() { public boolean isRunning() {
return running && socket != null && socket.isBound(); return running && socket != null && !socket.isClosed();
} }
public boolean shouldPoll() { public boolean shouldPoll() {
@@ -161,7 +160,7 @@ abstract class TcpPlugin implements DuplexPlugin {
} }
public void poll(Collection<ContactId> connected) { public void poll(Collection<ContactId> connected) {
if(!running) return; if(!isRunning()) return;
Map<ContactId, TransportProperties> remote = Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties(); callback.getRemoteProperties();
for(final ContactId c : remote.keySet()) { for(final ContactId c : remote.keySet()) {
@@ -180,7 +179,7 @@ abstract class TcpPlugin implements DuplexPlugin {
} }
public DuplexTransportConnection createConnection(ContactId c) { public DuplexTransportConnection createConnection(ContactId c) {
if(!running) return null; if(!isRunning()) return null;
SocketAddress addr = getRemoteSocketAddress(c); SocketAddress addr = getRemoteSocketAddress(c);
if(addr == null) return null; if(addr == null) return null;
Socket s = new Socket(); Socket s = new Socket();