mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 12:19:54 +01:00
UPnP port mapper using the Weupnp library (untested).
This commit is contained in:
BIN
libs/weupnp-0.1.1.jar
Normal file
BIN
libs/weupnp-0.1.1.jar
Normal file
Binary file not shown.
@@ -1,13 +1,10 @@
|
|||||||
package net.sf.briar;
|
package net.sf.briar;
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.Password;
|
import net.sf.briar.api.crypto.Password;
|
||||||
import net.sf.briar.api.db.DatabaseConfig;
|
import net.sf.briar.api.db.DatabaseConfig;
|
||||||
import net.sf.briar.api.ui.UiCallback;
|
import net.sf.briar.api.ui.UiCallback;
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
|
|
||||||
@@ -16,7 +13,7 @@ public class HelloWorldModule extends AbstractModule {
|
|||||||
private final DatabaseConfig config;
|
private final DatabaseConfig config;
|
||||||
private final UiCallback callback;
|
private final UiCallback callback;
|
||||||
|
|
||||||
public HelloWorldModule(final Context appContext) {
|
public HelloWorldModule(final File dir) {
|
||||||
final Password password = new Password() {
|
final Password password = new Password() {
|
||||||
|
|
||||||
public char[] getPassword() {
|
public char[] getPassword() {
|
||||||
@@ -26,7 +23,7 @@ public class HelloWorldModule extends AbstractModule {
|
|||||||
config = new DatabaseConfig() {
|
config = new DatabaseConfig() {
|
||||||
|
|
||||||
public File getDataDirectory() {
|
public File getDataDirectory() {
|
||||||
return appContext.getDir("db", MODE_PRIVATE);
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Password getPassword() {
|
public Password getPassword() {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.sf.briar;
|
|||||||
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.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -55,8 +56,8 @@ public class HelloWorldService extends Service implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
Injector i = Guice.createInjector(
|
File dir = getApplicationContext().getDir("db", MODE_PRIVATE);
|
||||||
new HelloWorldModule(getApplicationContext()),
|
Injector i = Guice.createInjector(new HelloWorldModule(dir),
|
||||||
new AndroidModule(), new ClockModule(), new CryptoModule(),
|
new AndroidModule(), new ClockModule(), new CryptoModule(),
|
||||||
new DatabaseModule(), new LifecycleModule(),
|
new DatabaseModule(), new LifecycleModule(),
|
||||||
new PluginsModule(), new ProtocolModule(),
|
new PluginsModule(), new ProtocolModule(),
|
||||||
@@ -77,7 +78,7 @@ public class HelloWorldService extends Service implements Runnable {
|
|||||||
LOG.info(pluginsStarted + " plugins started");
|
LOG.info(pluginsStarted + " plugins started");
|
||||||
// ...sleep...
|
// ...sleep...
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(30 * 1000);
|
||||||
} catch(InterruptedException ignored) {}
|
} catch(InterruptedException ignored) {}
|
||||||
// ...and stop
|
// ...and stop
|
||||||
if(LOG.isLoggable(INFO)) LOG.info("Shutting down");
|
if(LOG.isLoggable(INFO)) LOG.info("Shutting down");
|
||||||
|
|||||||
32
src/net/sf/briar/plugins/tcp/MappingResult.java
Normal file
32
src/net/sf/briar/plugins/tcp/MappingResult.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package net.sf.briar.plugins.tcp;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
class MappingResult {
|
||||||
|
|
||||||
|
private final InetAddress internal, external;
|
||||||
|
private final boolean succeeded;
|
||||||
|
|
||||||
|
MappingResult(InetAddress internal, InetAddress external,
|
||||||
|
boolean succeeded) {
|
||||||
|
this.internal = internal;
|
||||||
|
this.external = external;
|
||||||
|
this.succeeded = succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress getInternal() {
|
||||||
|
return internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress getExternal() {
|
||||||
|
return external;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean getSucceeded() {
|
||||||
|
return succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isUsable() {
|
||||||
|
return internal != null && external != null && succeeded;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/net/sf/briar/plugins/tcp/PortMapper.java
Normal file
10
src/net/sf/briar/plugins/tcp/PortMapper.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package net.sf.briar.plugins.tcp;
|
||||||
|
|
||||||
|
interface PortMapper {
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
MappingResult map(int port);
|
||||||
|
}
|
||||||
82
src/net/sf/briar/plugins/tcp/PortMapperImpl.java
Normal file
82
src/net/sf/briar/plugins/tcp/PortMapperImpl.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package net.sf.briar.plugins.tcp;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import org.wetorrent.upnp.GatewayDevice;
|
||||||
|
import org.wetorrent.upnp.GatewayDiscover;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
class PortMapperImpl implements PortMapper {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(PortMapperImpl.class.getName());
|
||||||
|
|
||||||
|
private final CountDownLatch started = new CountDownLatch(1);
|
||||||
|
private final Collection<Integer> ports =
|
||||||
|
new CopyOnWriteArrayList<Integer>();
|
||||||
|
|
||||||
|
private volatile GatewayDevice gateway = null;
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
GatewayDiscover d = new GatewayDiscover();
|
||||||
|
try {
|
||||||
|
d.discover();
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
} catch(SAXException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
} catch(ParserConfigurationException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
}
|
||||||
|
gateway = d.getValidGateway();
|
||||||
|
started.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if(gateway == null) return;
|
||||||
|
try {
|
||||||
|
for(Integer port: ports) gateway.deletePortMapping(port, "TCP");
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
} catch(SAXException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MappingResult map(int port) {
|
||||||
|
try {
|
||||||
|
started.await();
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(gateway == null) return null;
|
||||||
|
InetAddress internal = gateway.getLocalAddress();
|
||||||
|
if(internal == null) return null;
|
||||||
|
boolean succeeded = false;
|
||||||
|
InetAddress external = null;
|
||||||
|
try {
|
||||||
|
succeeded = gateway.addPortMapping(port, port,
|
||||||
|
internal.getHostAddress(), "TCP", "TCP");
|
||||||
|
String externalString = gateway.getExternalIPAddress();
|
||||||
|
if(externalString != null)
|
||||||
|
external = InetAddress.getByName(externalString);
|
||||||
|
} catch(IOException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
} catch(SAXException e) {
|
||||||
|
if(LOG.isLoggable(WARNING)) LOG.warning(e.toString());
|
||||||
|
}
|
||||||
|
if(succeeded) ports.add(port);
|
||||||
|
return new MappingResult(internal, external, succeeded);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,10 +91,11 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
socket = ss;
|
socket = ss;
|
||||||
}
|
}
|
||||||
if(LOG.isLoggable(INFO)) {
|
if(LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Listening on " + ss.getInetAddress().getHostAddress()
|
String addr = ss.getInetAddress().getHostAddress();
|
||||||
+ ":" + ss.getLocalPort());
|
int port = ss.getLocalPort();
|
||||||
|
LOG.info("Listening on " + addr + " " + port);
|
||||||
}
|
}
|
||||||
setLocalSocketAddress(ss.getLocalSocketAddress());
|
setLocalSocketAddress((InetSocketAddress) ss.getLocalSocketAddress());
|
||||||
acceptContactConnections(ss);
|
acceptContactConnections(ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,12 +107,11 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setLocalSocketAddress(SocketAddress s) {
|
protected void setLocalSocketAddress(InetSocketAddress a) {
|
||||||
InetSocketAddress i = (InetSocketAddress) s;
|
InetAddress addr = a.getAddress();
|
||||||
InetAddress addr = i.getAddress();
|
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("address", addr.getHostAddress());
|
p.put("address", addr.getHostAddress());
|
||||||
p.put("port", String.valueOf(i.getPort()));
|
p.put("port", String.valueOf(a.getPort()));
|
||||||
callback.mergeLocalProperties(p);
|
callback.mergeLocalProperties(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.sf.briar.plugins.tcp;
|
|||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
@@ -33,27 +34,54 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(WanTcpPlugin.class.getName());
|
Logger.getLogger(WanTcpPlugin.class.getName());
|
||||||
|
|
||||||
|
private final PortMapper portMapper;
|
||||||
|
|
||||||
|
private volatile MappingResult mappingResult;
|
||||||
|
|
||||||
WanTcpPlugin(@PluginExecutor Executor pluginExecutor,
|
WanTcpPlugin(@PluginExecutor Executor pluginExecutor,
|
||||||
DuplexPluginCallback callback, long pollingInterval) {
|
DuplexPluginCallback callback, long pollingInterval,
|
||||||
|
PortMapper portMapper) {
|
||||||
super(pluginExecutor, callback, pollingInterval);
|
super(pluginExecutor, callback, pollingInterval);
|
||||||
|
this.portMapper = portMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() throws IOException {
|
||||||
|
super.start();
|
||||||
|
pluginExecutor.execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
portMapper.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() throws IOException {
|
||||||
|
super.stop();
|
||||||
|
pluginExecutor.execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
portMapper.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<SocketAddress> getLocalSocketAddresses() {
|
protected List<SocketAddress> getLocalSocketAddresses() {
|
||||||
List<SocketAddress> addrs = new ArrayList<SocketAddress>();
|
List<SocketAddress> addrs = new ArrayList<SocketAddress>();
|
||||||
// Prefer a previously used address and port if available
|
// Prefer a previously used external address and port if available
|
||||||
TransportProperties p = callback.getLocalProperties();
|
TransportProperties p = callback.getLocalProperties();
|
||||||
String addrString = p.get("address");
|
String addrString = p.get("address");
|
||||||
String portString = p.get("port");
|
String portString = p.get("port");
|
||||||
InetAddress addr = null;
|
InetAddress addr = null;
|
||||||
|
int port = 0;
|
||||||
if(addrString != null && portString != null) {
|
if(addrString != null && portString != null) {
|
||||||
try {
|
try {
|
||||||
addr = InetAddress.getByName(addrString);
|
addr = InetAddress.getByName(addrString);
|
||||||
int port = Integer.valueOf(portString);
|
port = Integer.valueOf(portString);
|
||||||
addrs.add(new InetSocketAddress(addr, port));
|
addrs.add(new InetSocketAddress(addr, port));
|
||||||
addrs.add(new InetSocketAddress(addr, 0));
|
addrs.add(new InetSocketAddress(addr, 0));
|
||||||
} catch(NumberFormatException e) {
|
} catch(NumberFormatException e) {
|
||||||
@@ -79,9 +107,31 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
if(!link && !site) addrs.add(new InetSocketAddress(a, 0));
|
if(!link && !site) addrs.add(new InetSocketAddress(a, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Accept interfaces that can be port-mapped
|
||||||
|
if(port == 0) port = chooseEphemeralPort();
|
||||||
|
mappingResult = portMapper.map(port);
|
||||||
|
if(mappingResult != null && mappingResult.isUsable())
|
||||||
|
addrs.add(new InetSocketAddress(mappingResult.getInternal(), port));
|
||||||
return addrs;
|
return addrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int chooseEphemeralPort() {
|
||||||
|
return 32768 + (int) (Math.random() * 32768);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setLocalSocketAddress(InetSocketAddress a) {
|
||||||
|
InetAddress addr = a.getAddress();
|
||||||
|
if(mappingResult != null && mappingResult.isUsable()) {
|
||||||
|
if(addr.equals(mappingResult.getInternal()))
|
||||||
|
addr = mappingResult.getExternal();
|
||||||
|
}
|
||||||
|
TransportProperties p = new TransportProperties();
|
||||||
|
p.put("address", addr.getHostAddress());
|
||||||
|
p.put("port", String.valueOf(a.getPort()));
|
||||||
|
callback.mergeLocalProperties(p);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean supportsInvitations() {
|
public boolean supportsInvitations() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public class WanTcpPluginFactory implements DuplexPluginFactory {
|
|||||||
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 WanTcpPlugin(pluginExecutor, callback, POLLING_INTERVAL);
|
return new WanTcpPlugin(pluginExecutor, callback, POLLING_INTERVAL,
|
||||||
|
new PortMapperImpl());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user