mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 04:39:54 +01:00
Separated TCP plugin into LAN and WAN plugins and renamed package.
This commit is contained in:
@@ -10,9 +10,9 @@ public interface PluginManager {
|
|||||||
/**
|
/**
|
||||||
* Starts the plugins and returns the number of plugins successfully
|
* Starts the plugins and returns the number of plugins successfully
|
||||||
* started. This method must not be called until the database has been
|
* started. This method must not be called until the database has been
|
||||||
* opened.
|
* opened. The appContext argument is null on non-Android platforms.
|
||||||
*/
|
*/
|
||||||
int start(Context context);
|
int start(Context appContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the plugins and returns the number of plugins successfully stopped.
|
* Stops the plugins and returns the number of plugins successfully stopped.
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ class PluginManagerImpl implements PluginManager {
|
|||||||
|
|
||||||
private static final String[] ANDROID_DUPLEX_FACTORIES = new String[] {
|
private static final String[] ANDROID_DUPLEX_FACTORIES = new String[] {
|
||||||
"net.sf.briar.plugins.droidtooth.DroidtoothPluginFactory",
|
"net.sf.briar.plugins.droidtooth.DroidtoothPluginFactory",
|
||||||
"net.sf.briar.plugins.socket.SimpleSocketPluginFactory"
|
"net.sf.briar.plugins.tcp.LanTcpPluginFactory",
|
||||||
|
"net.sf.briar.plugins.tcp.WanTcpPluginFactory"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String[] J2SE_SIMPLEX_FACTORIES = new String[] {
|
private static final String[] J2SE_SIMPLEX_FACTORIES = new String[] {
|
||||||
@@ -59,7 +60,8 @@ class PluginManagerImpl implements PluginManager {
|
|||||||
|
|
||||||
private static final String[] J2SE_DUPLEX_FACTORIES = new String[] {
|
private static final String[] J2SE_DUPLEX_FACTORIES = new String[] {
|
||||||
"net.sf.briar.plugins.bluetooth.BluetoothPluginFactory",
|
"net.sf.briar.plugins.bluetooth.BluetoothPluginFactory",
|
||||||
"net.sf.briar.plugins.socket.SimpleSocketPluginFactory",
|
"net.sf.briar.plugins.tcp.LanSocketPluginFactory",
|
||||||
|
"net.sf.briar.plugins.tcp.WanSocketPluginFactory",
|
||||||
"net.sf.briar.plugins.tor.TorPluginFactory"
|
"net.sf.briar.plugins.tor.TorPluginFactory"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,154 +0,0 @@
|
|||||||
package net.sf.briar.plugins.socket;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.NetworkInterface;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import net.sf.briar.api.ContactId;
|
|
||||||
import net.sf.briar.api.TransportProperties;
|
|
||||||
import net.sf.briar.api.crypto.PseudoRandom;
|
|
||||||
import net.sf.briar.api.plugins.PluginExecutor;
|
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
|
||||||
import net.sf.briar.api.protocol.TransportId;
|
|
||||||
import net.sf.briar.util.StringUtils;
|
|
||||||
|
|
||||||
class SimpleSocketPlugin extends SocketPlugin {
|
|
||||||
|
|
||||||
public static final byte[] TRANSPORT_ID =
|
|
||||||
StringUtils.fromHexString("58c66d999e492b85065924acfd739d80"
|
|
||||||
+ "c65a62f87e5a4fc6c284f95908b9007d"
|
|
||||||
+ "512a93ebf89bf68f50a29e96eebf97b6");
|
|
||||||
|
|
||||||
private static final TransportId ID = new TransportId(TRANSPORT_ID);
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(SimpleSocketPlugin.class.getName());
|
|
||||||
|
|
||||||
SimpleSocketPlugin(@PluginExecutor Executor pluginExecutor,
|
|
||||||
DuplexPluginCallback callback, long pollingInterval) {
|
|
||||||
super(pluginExecutor, callback, pollingInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransportId getId() {
|
|
||||||
return ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Socket createClientSocket() throws IOException {
|
|
||||||
assert running;
|
|
||||||
return new Socket();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ServerSocket createServerSocket() throws IOException {
|
|
||||||
assert running;
|
|
||||||
return new ServerSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected SocketAddress getLocalSocketAddress() {
|
|
||||||
SocketAddress addr = createSocketAddress(callback.getLocalProperties());
|
|
||||||
if(addr == null) {
|
|
||||||
try {
|
|
||||||
return new InetSocketAddress(chooseInterface(false), 0);
|
|
||||||
} catch(IOException e) {
|
|
||||||
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected InetAddress chooseInterface(boolean lan) throws IOException {
|
|
||||||
List<NetworkInterface> ifaces =
|
|
||||||
Collections.list(NetworkInterface.getNetworkInterfaces());
|
|
||||||
// Try to find an interface of the preferred type (LAN or WAN)
|
|
||||||
for(NetworkInterface iface : ifaces) {
|
|
||||||
for(InetAddress addr : Collections.list(iface.getInetAddresses())) {
|
|
||||||
if(!addr.isLoopbackAddress()) {
|
|
||||||
boolean link = addr.isLinkLocalAddress();
|
|
||||||
boolean site = addr.isSiteLocalAddress();
|
|
||||||
if(lan == (link || site)) {
|
|
||||||
if(LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Choosing interface "
|
|
||||||
+ addr.getHostAddress());
|
|
||||||
}
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Settle for an interface that's not of the preferred type
|
|
||||||
for(NetworkInterface iface : ifaces) {
|
|
||||||
for(InetAddress addr : Collections.list(iface.getInetAddresses())) {
|
|
||||||
if(!addr.isLoopbackAddress()) {
|
|
||||||
if(LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Accepting interface "
|
|
||||||
+ addr.getHostAddress());
|
|
||||||
}
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IOException("No suitable interfaces");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected SocketAddress getRemoteSocketAddress(ContactId c) {
|
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
|
||||||
return p == null ? null : createSocketAddress(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SocketAddress createSocketAddress(TransportProperties p) {
|
|
||||||
assert p != null;
|
|
||||||
String host = p.get("external");
|
|
||||||
if(host == null) host = p.get("internal");
|
|
||||||
String portString = p.get("port");
|
|
||||||
if(host == null || portString == null) return null;
|
|
||||||
int port;
|
|
||||||
try {
|
|
||||||
port = Integer.valueOf(portString);
|
|
||||||
} catch(NumberFormatException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new InetSocketAddress(host, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setLocalSocketAddress(SocketAddress s) {
|
|
||||||
if(!(s instanceof InetSocketAddress))
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
InetSocketAddress i = (InetSocketAddress) s;
|
|
||||||
InetAddress addr = i.getAddress();
|
|
||||||
TransportProperties p = new TransportProperties();
|
|
||||||
if(addr.isLinkLocalAddress() || addr.isSiteLocalAddress())
|
|
||||||
p.put("internal", addr.getHostAddress());
|
|
||||||
else p.put("external", addr.getHostAddress());
|
|
||||||
p.put("port", String.valueOf(i.getPort()));
|
|
||||||
callback.mergeLocalProperties(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsInvitations() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DuplexTransportConnection sendInvitation(PseudoRandom r,
|
|
||||||
long timeout) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DuplexTransportConnection acceptInvitation(PseudoRandom r,
|
|
||||||
long timeout) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package net.sf.briar.plugins.socket;
|
package net.sf.briar.plugins.tcp;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -8,36 +8,103 @@ import java.net.DatagramPacket;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.MulticastSocket;
|
import java.net.MulticastSocket;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import net.sf.briar.api.TransportProperties;
|
||||||
import net.sf.briar.api.crypto.PseudoRandom;
|
import net.sf.briar.api.crypto.PseudoRandom;
|
||||||
import net.sf.briar.api.plugins.PluginExecutor;
|
import net.sf.briar.api.plugins.PluginExecutor;
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
||||||
|
import net.sf.briar.api.protocol.TransportId;
|
||||||
import net.sf.briar.util.ByteUtils;
|
import net.sf.briar.util.ByteUtils;
|
||||||
|
import net.sf.briar.util.StringUtils;
|
||||||
|
|
||||||
/** A socket plugin that supports exchanging invitations over a LAN. */
|
/** A socket plugin that supports exchanging invitations over a LAN. */
|
||||||
class LanSocketPlugin extends SimpleSocketPlugin {
|
class LanTcpPlugin extends TcpPlugin {
|
||||||
|
|
||||||
|
public static final byte[] TRANSPORT_ID =
|
||||||
|
StringUtils.fromHexString("0d79357fd7f74d66c2f6f6ad0f7fff81"
|
||||||
|
+ "d21c53a43b90b0507ed0683872d8e2fc"
|
||||||
|
+ "5a88e8f953638228dc26669639757bbf");
|
||||||
|
|
||||||
|
private static final TransportId ID = new TransportId(TRANSPORT_ID);
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(LanSocketPlugin.class.getName());
|
Logger.getLogger(LanTcpPlugin.class.getName());
|
||||||
|
|
||||||
LanSocketPlugin(@PluginExecutor Executor pluginExecutor,
|
LanTcpPlugin(@PluginExecutor Executor pluginExecutor,
|
||||||
DuplexPluginCallback callback, long pollingInterval) {
|
DuplexPluginCallback callback, long pollingInterval) {
|
||||||
super(pluginExecutor, callback, pollingInterval);
|
super(pluginExecutor, callback, pollingInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TransportId getId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
protected List<SocketAddress> getLocalSocketAddresses() {
|
||||||
|
List<SocketAddress> addrs = new ArrayList<SocketAddress>();
|
||||||
|
// Prefer a previously used address and port if available
|
||||||
|
TransportProperties p = callback.getLocalProperties();
|
||||||
|
String addrString = p.get("address");
|
||||||
|
String portString = p.get("port");
|
||||||
|
InetAddress addr = null;
|
||||||
|
if(addrString != null && portString != null) {
|
||||||
|
try {
|
||||||
|
addr = InetAddress.getByName(addrString);
|
||||||
|
int port = Integer.valueOf(portString);
|
||||||
|
addrs.add(new InetSocketAddress(addr, port));
|
||||||
|
addrs.add(new InetSocketAddress(addr, 0));
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
} catch(UnknownHostException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<NetworkInterface> ifaces;
|
||||||
|
try {
|
||||||
|
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||||
|
} catch(SocketException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
return addrs;
|
||||||
|
}
|
||||||
|
// Prefer interfaces with link-local or site-local addresses
|
||||||
|
for(NetworkInterface iface : ifaces) {
|
||||||
|
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
||||||
|
if(addr != null && a.equals(addr)) continue;
|
||||||
|
if(a.isLoopbackAddress()) continue;
|
||||||
|
boolean link = a.isLinkLocalAddress();
|
||||||
|
boolean site = a.isSiteLocalAddress();
|
||||||
|
if(link || site) addrs.add(new InetSocketAddress(a, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Accept interfaces without link-local or site-local addresses
|
||||||
|
for(NetworkInterface iface : ifaces) {
|
||||||
|
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
||||||
|
if(addr != null && a.equals(addr)) continue;
|
||||||
|
if(a.isLoopbackAddress()) continue;
|
||||||
|
boolean link = a.isLinkLocalAddress();
|
||||||
|
boolean site = a.isSiteLocalAddress();
|
||||||
|
if(!link && !site) addrs.add(new InetSocketAddress(a, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addrs;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean supportsInvitations() {
|
public boolean supportsInvitations() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DuplexTransportConnection sendInvitation(PseudoRandom r,
|
public DuplexTransportConnection sendInvitation(PseudoRandom r,
|
||||||
long timeout) {
|
long timeout) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
@@ -48,7 +115,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
|
|||||||
// Bind a multicast socket for receiving packets
|
// Bind a multicast socket for receiving packets
|
||||||
MulticastSocket ms = null;
|
MulticastSocket ms = null;
|
||||||
try {
|
try {
|
||||||
InetAddress iface = chooseInterface(true);
|
InetAddress iface = chooseInterface();
|
||||||
ms = new MulticastSocket(mcast.getPort());
|
ms = new MulticastSocket(mcast.getPort());
|
||||||
ms.setInterface(iface);
|
ms.setInterface(iface);
|
||||||
ms.joinGroup(mcast.getAddress());
|
ms.joinGroup(mcast.getAddress());
|
||||||
@@ -75,7 +142,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
|
|||||||
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);
|
||||||
return new SocketTransportConnection(s);
|
return new TcpTransportConnection(s);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if(LOG.isLoggable(WARNING))
|
||||||
LOG.warning(e.toString());
|
LOG.warning(e.toString());
|
||||||
@@ -99,6 +166,35 @@ class LanSocketPlugin extends SimpleSocketPlugin {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InetAddress chooseInterface() throws IOException {
|
||||||
|
List<NetworkInterface> ifaces =
|
||||||
|
Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||||
|
// Prefer an interface with a link-local or site-local address
|
||||||
|
for(NetworkInterface iface : ifaces) {
|
||||||
|
for(InetAddress addr : Collections.list(iface.getInetAddresses())) {
|
||||||
|
if(addr.isLoopbackAddress()) continue;
|
||||||
|
boolean link = addr.isLinkLocalAddress();
|
||||||
|
boolean site = addr.isSiteLocalAddress();
|
||||||
|
if(link || site) {
|
||||||
|
if(LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Preferring " + addr.getHostAddress());
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Accept an interface without a link-local or site-local address
|
||||||
|
for(NetworkInterface iface : ifaces) {
|
||||||
|
for(InetAddress addr : Collections.list(iface.getInetAddresses())) {
|
||||||
|
if(addr.isLoopbackAddress()) continue;
|
||||||
|
if(LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Accepting " + addr.getHostAddress());
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No suitable interfaces
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void tryToClose(MulticastSocket ms, InetAddress addr) {
|
private void tryToClose(MulticastSocket ms, InetAddress addr) {
|
||||||
try {
|
try {
|
||||||
ms.leaveGroup(addr);
|
ms.leaveGroup(addr);
|
||||||
@@ -139,7 +235,6 @@ class LanSocketPlugin extends SimpleSocketPlugin {
|
|||||||
return ByteUtils.readUint16(b, off);
|
return ByteUtils.readUint16(b, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DuplexTransportConnection acceptInvitation(PseudoRandom r,
|
public DuplexTransportConnection acceptInvitation(PseudoRandom r,
|
||||||
long timeout) {
|
long timeout) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
@@ -150,7 +245,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
|
|||||||
// Bind a TCP socket for receiving connections
|
// Bind a TCP socket for receiving connections
|
||||||
ServerSocket ss = null;
|
ServerSocket ss = null;
|
||||||
try {
|
try {
|
||||||
InetAddress iface = chooseInterface(true);
|
InetAddress iface = chooseInterface();
|
||||||
ss = new ServerSocket();
|
ss = new ServerSocket();
|
||||||
ss.bind(new InetSocketAddress(iface, 0));
|
ss.bind(new InetSocketAddress(iface, 0));
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
@@ -161,7 +256,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
|
|||||||
// Bind a multicast socket for sending packets
|
// Bind a multicast socket for sending packets
|
||||||
MulticastSocket ms = null;
|
MulticastSocket ms = null;
|
||||||
try {
|
try {
|
||||||
InetAddress iface = chooseInterface(true);
|
InetAddress iface = chooseInterface();
|
||||||
ms = new MulticastSocket();
|
ms = new MulticastSocket();
|
||||||
ms.setInterface(iface);
|
ms.setInterface(iface);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
@@ -185,7 +280,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
|
|||||||
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);
|
||||||
return new SocketTransportConnection(ss.accept());
|
return new TcpTransportConnection(ss.accept());
|
||||||
} catch(SocketTimeoutException e) {
|
} catch(SocketTimeoutException e) {
|
||||||
now = System.currentTimeMillis();
|
now = System.currentTimeMillis();
|
||||||
if(now < end) {
|
if(now < end) {
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
package net.sf.briar.plugins.socket;
|
package net.sf.briar.plugins.tcp;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -19,10 +23,10 @@ import net.sf.briar.api.plugins.duplex.DuplexPlugin;
|
|||||||
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
||||||
|
|
||||||
abstract class SocketPlugin implements DuplexPlugin {
|
abstract class TcpPlugin implements DuplexPlugin {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(SocketPlugin.class.getName());
|
Logger.getLogger(TcpPlugin.class.getName());
|
||||||
|
|
||||||
protected final Executor pluginExecutor;
|
protected final Executor pluginExecutor;
|
||||||
protected final DuplexPluginCallback callback;
|
protected final DuplexPluginCallback callback;
|
||||||
@@ -30,16 +34,15 @@ abstract class SocketPlugin implements DuplexPlugin {
|
|||||||
private final long pollingInterval;
|
private final long pollingInterval;
|
||||||
|
|
||||||
protected boolean running = false; // Locking: this
|
protected boolean running = false; // Locking: this
|
||||||
protected ServerSocket socket = null; // Locking: this
|
private ServerSocket socket = null; // Locking: this
|
||||||
|
|
||||||
protected abstract void setLocalSocketAddress(SocketAddress s);
|
/**
|
||||||
|
* Returns zero or more socket addresses on which the plugin should listen,
|
||||||
|
* in order of preference. At most one of the addresses will be bound.
|
||||||
|
*/
|
||||||
|
protected abstract List<SocketAddress> getLocalSocketAddresses();
|
||||||
|
|
||||||
protected abstract Socket createClientSocket() throws IOException;
|
protected TcpPlugin(@PluginExecutor Executor pluginExecutor,
|
||||||
protected abstract ServerSocket createServerSocket() throws IOException;
|
|
||||||
protected abstract SocketAddress getLocalSocketAddress();
|
|
||||||
protected abstract SocketAddress getRemoteSocketAddress(ContactId c);
|
|
||||||
|
|
||||||
protected SocketPlugin(@PluginExecutor Executor pluginExecutor,
|
|
||||||
DuplexPluginCallback callback, long pollingInterval) {
|
DuplexPluginCallback callback, long pollingInterval) {
|
||||||
this.pluginExecutor = pluginExecutor;
|
this.pluginExecutor = pluginExecutor;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
@@ -58,21 +61,27 @@ abstract class SocketPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void bind() {
|
private void bind() {
|
||||||
SocketAddress addr;
|
ServerSocket ss;
|
||||||
ServerSocket ss = null;
|
|
||||||
try {
|
try {
|
||||||
addr = getLocalSocketAddress();
|
ss = new ServerSocket();
|
||||||
ss = createServerSocket();
|
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(addr == null || ss == null) return;
|
boolean found = false;
|
||||||
try {
|
for(SocketAddress addr : getLocalSocketAddresses()) {
|
||||||
ss.bind(addr);
|
try {
|
||||||
} catch(IOException e) {
|
ss.bind(addr);
|
||||||
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
found = true;
|
||||||
tryToClose(ss);
|
break;
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
tryToClose(ss);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found) {
|
||||||
|
if(LOG.isLoggable(INFO)) LOG.info("Could not bind server socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
@@ -98,6 +107,15 @@ abstract class SocketPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setLocalSocketAddress(SocketAddress s) {
|
||||||
|
InetSocketAddress i = (InetSocketAddress) s;
|
||||||
|
InetAddress addr = i.getAddress();
|
||||||
|
TransportProperties p = new TransportProperties();
|
||||||
|
p.put("address", addr.getHostAddress());
|
||||||
|
p.put("port", String.valueOf(i.getPort()));
|
||||||
|
callback.mergeLocalProperties(p);
|
||||||
|
}
|
||||||
|
|
||||||
private void acceptContactConnections(ServerSocket ss) {
|
private void acceptContactConnections(ServerSocket ss) {
|
||||||
while(true) {
|
while(true) {
|
||||||
Socket s;
|
Socket s;
|
||||||
@@ -109,7 +127,7 @@ abstract class SocketPlugin implements DuplexPlugin {
|
|||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SocketTransportConnection conn = new SocketTransportConnection(s);
|
TcpTransportConnection conn = new TcpTransportConnection(s);
|
||||||
callback.incomingConnectionCreated(conn);
|
callback.incomingConnectionCreated(conn);
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!running) return;
|
if(!running) return;
|
||||||
@@ -138,7 +156,7 @@ abstract class SocketPlugin implements DuplexPlugin {
|
|||||||
if(!running) return;
|
if(!running) 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()) {
|
||||||
if(connected.contains(c)) continue;
|
if(connected.contains(c)) continue;
|
||||||
pluginExecutor.execute(new Runnable() {
|
pluginExecutor.execute(new Runnable() {
|
||||||
@@ -160,13 +178,32 @@ abstract class SocketPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
SocketAddress addr = getRemoteSocketAddress(c);
|
SocketAddress addr = getRemoteSocketAddress(c);
|
||||||
try {
|
try {
|
||||||
Socket s = createClientSocket();
|
Socket s = new Socket();
|
||||||
if(addr == null || s == null) return null;
|
if(addr == null || s == null) return null;
|
||||||
s.connect(addr);
|
s.connect(addr);
|
||||||
return new SocketTransportConnection(s);
|
return new TcpTransportConnection(s);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(INFO)) LOG.info(e.toString());
|
if(LOG.isLoggable(INFO)) LOG.info(e.toString());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SocketAddress getRemoteSocketAddress(ContactId c) {
|
||||||
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
|
if(p == null) return null;
|
||||||
|
String addrString = p.get("address");
|
||||||
|
String portString = p.get("port");
|
||||||
|
if(addrString != null && portString != null) {
|
||||||
|
try {
|
||||||
|
InetAddress addr = InetAddress.getByName(addrString);
|
||||||
|
int port = Integer.valueOf(portString);
|
||||||
|
return new InetSocketAddress(addr, port);
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
} catch(UnknownHostException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package net.sf.briar.plugins.socket;
|
package net.sf.briar.plugins.tcp;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -7,11 +7,11 @@ import java.net.Socket;
|
|||||||
|
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
||||||
|
|
||||||
class SocketTransportConnection implements DuplexTransportConnection {
|
class TcpTransportConnection implements DuplexTransportConnection {
|
||||||
|
|
||||||
private final Socket socket;
|
private final Socket socket;
|
||||||
|
|
||||||
SocketTransportConnection(Socket socket) {
|
TcpTransportConnection(Socket socket) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
98
src/net/sf/briar/plugins/tcp/WanTcpPlugin.java
Normal file
98
src/net/sf/briar/plugins/tcp/WanTcpPlugin.java
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package net.sf.briar.plugins.tcp;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import net.sf.briar.api.TransportProperties;
|
||||||
|
import net.sf.briar.api.crypto.PseudoRandom;
|
||||||
|
import net.sf.briar.api.plugins.PluginExecutor;
|
||||||
|
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
||||||
|
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
||||||
|
import net.sf.briar.api.protocol.TransportId;
|
||||||
|
import net.sf.briar.util.StringUtils;
|
||||||
|
|
||||||
|
class WanTcpPlugin extends TcpPlugin {
|
||||||
|
|
||||||
|
public static final byte[] TRANSPORT_ID =
|
||||||
|
StringUtils.fromHexString("58c66d999e492b85065924acfd739d80"
|
||||||
|
+ "c65a62f87e5a4fc6c284f95908b9007d"
|
||||||
|
+ "512a93ebf89bf68f50a29e96eebf97b6");
|
||||||
|
|
||||||
|
private static final TransportId ID = new TransportId(TRANSPORT_ID);
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(WanTcpPlugin.class.getName());
|
||||||
|
|
||||||
|
WanTcpPlugin(@PluginExecutor Executor pluginExecutor,
|
||||||
|
DuplexPluginCallback callback, long pollingInterval) {
|
||||||
|
super(pluginExecutor, callback, pollingInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportId getId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<SocketAddress> getLocalSocketAddresses() {
|
||||||
|
List<SocketAddress> addrs = new ArrayList<SocketAddress>();
|
||||||
|
// Prefer a previously used address and port if available
|
||||||
|
TransportProperties p = callback.getLocalProperties();
|
||||||
|
String addrString = p.get("address");
|
||||||
|
String portString = p.get("port");
|
||||||
|
InetAddress addr = null;
|
||||||
|
if(addrString != null && portString != null) {
|
||||||
|
try {
|
||||||
|
addr = InetAddress.getByName(addrString);
|
||||||
|
int port = Integer.valueOf(portString);
|
||||||
|
addrs.add(new InetSocketAddress(addr, port));
|
||||||
|
addrs.add(new InetSocketAddress(addr, 0));
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
} catch(UnknownHostException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<NetworkInterface> ifaces;
|
||||||
|
try {
|
||||||
|
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||||
|
} catch(SocketException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
return addrs;
|
||||||
|
}
|
||||||
|
// Accept interfaces without link-local or site-local addresses
|
||||||
|
for(NetworkInterface iface : ifaces) {
|
||||||
|
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
||||||
|
if(addr != null && a.equals(addr)) continue;
|
||||||
|
if(a.isLoopbackAddress()) continue;
|
||||||
|
boolean link = a.isLinkLocalAddress();
|
||||||
|
boolean site = a.isSiteLocalAddress();
|
||||||
|
if(!link && !site) addrs.add(new InetSocketAddress(a, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supportsInvitations() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplexTransportConnection sendInvitation(PseudoRandom r,
|
||||||
|
long timeout) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplexTransportConnection acceptInvitation(PseudoRandom r,
|
||||||
|
long timeout) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package net.sf.briar.plugins.socket;
|
package net.sf.briar.plugins.tcp;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@@ -9,14 +9,13 @@ import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
|
|||||||
import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
|
import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
public class SimpleSocketPluginFactory implements DuplexPluginFactory {
|
public class WanTcpPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final long POLLING_INTERVAL = 5L * 60L * 1000L; // 5 mins
|
private static final long POLLING_INTERVAL = 5L * 60L * 1000L; // 5 minutes
|
||||||
|
|
||||||
public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
|
public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
|
||||||
AndroidExecutor androidExecutor, Context appContext,
|
AndroidExecutor androidExecutor, Context appContext,
|
||||||
DuplexPluginCallback callback) {
|
DuplexPluginCallback callback) {
|
||||||
return new SimpleSocketPlugin(pluginExecutor, callback,
|
return new WanTcpPlugin(pluginExecutor, callback, POLLING_INTERVAL);
|
||||||
POLLING_INTERVAL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user