mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +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;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.sf.briar.api.crypto.Password;
|
||||
import net.sf.briar.api.db.DatabaseConfig;
|
||||
import net.sf.briar.api.ui.UiCallback;
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
@@ -16,7 +13,7 @@ public class HelloWorldModule extends AbstractModule {
|
||||
private final DatabaseConfig config;
|
||||
private final UiCallback callback;
|
||||
|
||||
public HelloWorldModule(final Context appContext) {
|
||||
public HelloWorldModule(final File dir) {
|
||||
final Password password = new Password() {
|
||||
|
||||
public char[] getPassword() {
|
||||
@@ -26,7 +23,7 @@ public class HelloWorldModule extends AbstractModule {
|
||||
config = new DatabaseConfig() {
|
||||
|
||||
public File getDataDirectory() {
|
||||
return appContext.getDir("db", MODE_PRIVATE);
|
||||
return dir;
|
||||
}
|
||||
|
||||
public Password getPassword() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.sf.briar;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -55,8 +56,8 @@ public class HelloWorldService extends Service implements Runnable {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Injector i = Guice.createInjector(
|
||||
new HelloWorldModule(getApplicationContext()),
|
||||
File dir = getApplicationContext().getDir("db", MODE_PRIVATE);
|
||||
Injector i = Guice.createInjector(new HelloWorldModule(dir),
|
||||
new AndroidModule(), new ClockModule(), new CryptoModule(),
|
||||
new DatabaseModule(), new LifecycleModule(),
|
||||
new PluginsModule(), new ProtocolModule(),
|
||||
@@ -77,7 +78,7 @@ public class HelloWorldService extends Service implements Runnable {
|
||||
LOG.info(pluginsStarted + " plugins started");
|
||||
// ...sleep...
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
Thread.sleep(30 * 1000);
|
||||
} catch(InterruptedException ignored) {}
|
||||
// ...and stop
|
||||
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;
|
||||
}
|
||||
if(LOG.isLoggable(INFO)) {
|
||||
LOG.info("Listening on " + ss.getInetAddress().getHostAddress()
|
||||
+ ":" + ss.getLocalPort());
|
||||
String addr = ss.getInetAddress().getHostAddress();
|
||||
int port = ss.getLocalPort();
|
||||
LOG.info("Listening on " + addr + " " + port);
|
||||
}
|
||||
setLocalSocketAddress(ss.getLocalSocketAddress());
|
||||
setLocalSocketAddress((InetSocketAddress) ss.getLocalSocketAddress());
|
||||
acceptContactConnections(ss);
|
||||
}
|
||||
|
||||
@@ -106,12 +107,11 @@ abstract class TcpPlugin implements DuplexPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
private void setLocalSocketAddress(SocketAddress s) {
|
||||
InetSocketAddress i = (InetSocketAddress) s;
|
||||
InetAddress addr = i.getAddress();
|
||||
protected void setLocalSocketAddress(InetSocketAddress a) {
|
||||
InetAddress addr = a.getAddress();
|
||||
TransportProperties p = new TransportProperties();
|
||||
p.put("address", addr.getHostAddress());
|
||||
p.put("port", String.valueOf(i.getPort()));
|
||||
p.put("port", String.valueOf(a.getPort()));
|
||||
callback.mergeLocalProperties(p);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.sf.briar.plugins.tcp;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
@@ -33,27 +34,54 @@ class WanTcpPlugin extends TcpPlugin {
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(WanTcpPlugin.class.getName());
|
||||
|
||||
private final PortMapper portMapper;
|
||||
|
||||
private volatile MappingResult mappingResult;
|
||||
|
||||
WanTcpPlugin(@PluginExecutor Executor pluginExecutor,
|
||||
DuplexPluginCallback callback, long pollingInterval) {
|
||||
DuplexPluginCallback callback, long pollingInterval,
|
||||
PortMapper portMapper) {
|
||||
super(pluginExecutor, callback, pollingInterval);
|
||||
this.portMapper = portMapper;
|
||||
}
|
||||
|
||||
public TransportId getId() {
|
||||
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
|
||||
protected List<SocketAddress> getLocalSocketAddresses() {
|
||||
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();
|
||||
String addrString = p.get("address");
|
||||
String portString = p.get("port");
|
||||
InetAddress addr = null;
|
||||
int port = 0;
|
||||
if(addrString != null && portString != null) {
|
||||
try {
|
||||
addr = InetAddress.getByName(addrString);
|
||||
int port = Integer.valueOf(portString);
|
||||
port = Integer.valueOf(portString);
|
||||
addrs.add(new InetSocketAddress(addr, port));
|
||||
addrs.add(new InetSocketAddress(addr, 0));
|
||||
} catch(NumberFormatException e) {
|
||||
@@ -79,9 +107,31 @@ class WanTcpPlugin extends TcpPlugin {
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public class WanTcpPluginFactory implements DuplexPluginFactory {
|
||||
public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
|
||||
AndroidExecutor androidExecutor, Context appContext,
|
||||
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