Skip to content
Snippets Groups Projects
Commit 75ce6cf1 authored by akwizgran's avatar akwizgran
Browse files

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

parent e260aac3
No related branches found
No related tags found
No related merge requests found
......@@ -15,7 +15,7 @@ import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
import org.briarproject.api.system.LocationUtils;
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 android.app.Application;
......@@ -44,14 +44,15 @@ public class AndroidPluginsModule extends AbstractModule {
CryptoComponent crypto, LocationUtils locationUtils,
ShutdownManager shutdownManager) {
Context appContext = app.getApplicationContext();
DuplexPluginFactory droidtooth = new DroidtoothPluginFactory(
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(
pluginExecutor, androidExecutor, appContext,
crypto.getSecureRandom());
DuplexPluginFactory tor = new TorPluginFactory(pluginExecutor,
appContext, locationUtils, shutdownManager);
DuplexPluginFactory lan = new LanTcpPluginFactory(pluginExecutor);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(
pluginExecutor, appContext);
final Collection<DuplexPluginFactory> factories =
Arrays.asList(droidtooth, tor, lan);
Arrays.asList(bluetooth, tor, lan);
return new DuplexPluginConfig() {
public Collection<DuplexPluginFactory> getFactories() {
return factories;
......
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);
}
}
}
}
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);
}
}
......@@ -18,7 +18,6 @@ import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
/** A TCP plugin that supports exchanging invitations over a LAN. */
class LanTcpPlugin extends TcpPlugin {
static final TransportId ID = new TransportId("lan");
......
......@@ -38,7 +38,7 @@ abstract class TcpPlugin implements DuplexPlugin {
protected final long maxLatency, pollingInterval;
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,
......@@ -65,47 +65,47 @@ abstract class TcpPlugin implements DuplexPlugin {
public boolean start() {
running = true;
pluginExecutor.execute(new Runnable() {
public void run() {
bind();
}
});
bind();
return true;
}
private void bind() {
ServerSocket ss = null;
boolean found = false;
for(SocketAddress addr : getLocalSocketAddresses()) {
try {
ss = new ServerSocket();
ss.bind(addr);
found = true;
break;
} catch(IOException e) {
if(LOG.isLoggable(INFO)) LOG.info("Failed to bind " + addr);
tryToClose(ss);
continue;
protected void bind() {
pluginExecutor.execute(new Runnable() {
public void run() {
if(!running) return;
ServerSocket ss = null;
for(SocketAddress addr : getLocalSocketAddresses()) {
try {
ss = new ServerSocket();
ss.bind(addr);
break;
} catch(IOException e) {
if(LOG.isLoggable(INFO))
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) {
try {
ss.close();
if(ss != null) ss.close();
} catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
......@@ -124,32 +124,31 @@ abstract class TcpPlugin implements DuplexPlugin {
callback.mergeLocalProperties(p);
}
private void acceptContactConnections(ServerSocket ss) {
while(true) {
private void acceptContactConnections() {
while(isRunning()) {
Socket s;
try {
s = ss.accept();
s = socket.accept();
} catch(IOException e) {
// This is expected when the socket is closed
if(LOG.isLoggable(INFO)) LOG.info(e.toString());
tryToClose(ss);
tryToClose(socket);
return;
}
if(LOG.isLoggable(INFO))
LOG.info("Connection from " + s.getRemoteSocketAddress());
TcpTransportConnection conn = new TcpTransportConnection(this, s);
callback.incomingConnectionCreated(conn);
if(!running) return;
}
}
public void stop() {
running = false;
if(socket != null) tryToClose(socket);
tryToClose(socket);
}
public boolean isRunning() {
return running && socket != null && socket.isBound();
return running && socket != null && !socket.isClosed();
}
public boolean shouldPoll() {
......@@ -161,7 +160,7 @@ abstract class TcpPlugin implements DuplexPlugin {
}
public void poll(Collection<ContactId> connected) {
if(!running) return;
if(!isRunning()) return;
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
for(final ContactId c : remote.keySet()) {
......@@ -180,7 +179,7 @@ abstract class TcpPlugin implements DuplexPlugin {
}
public DuplexTransportConnection createConnection(ContactId c) {
if(!running) return null;
if(!isRunning()) return null;
SocketAddress addr = getRemoteSocketAddress(c);
if(addr == null) return null;
Socket s = new Socket();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment