* I2PTunnel standard, HTTP, and IRC servers:

Route connections to specific targets based on incoming I2P port
   with custom option targetForPort.xxxx=myserver:yyyy
   This allows multiple services on a single server tunnel (ticket #1066)
This commit is contained in:
zzz
2013-10-24 11:38:28 +00:00
parent 8f7b31aed3
commit 35a86e603b
5 changed files with 73 additions and 5 deletions

View File

@ -150,7 +150,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
setEntry(headers, "Accept-encoding", ""); setEntry(headers, "Accept-encoding", "");
socket.setReadTimeout(readTimeout); socket.setReadTimeout(readTimeout);
Socket s = getSocket(remoteHost, remotePort); Socket s = getSocket(socket.getLocalPort());
long afterSocket = getTunnel().getContext().clock().now(); long afterSocket = getTunnel().getContext().clock().now();
// instead of i2ptunnelrunner, use something that reads the HTTP // instead of i2ptunnelrunner, use something that reads the HTTP
// request from the socket, modifies the headers, sends the request to the // request from the socket, modifies the headers, sends the request to the

View File

@ -137,7 +137,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
buf.append("\r\n"); buf.append("\r\n");
modifiedRegistration = buf.toString(); modifiedRegistration = buf.toString();
} }
Socket s = getSocket(remoteHost, remotePort); Socket s = getSocket(socket.getLocalPort());
new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null); new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
} catch (SocketException ex) { } catch (SocketException ex) {
try { try {

View File

@ -11,12 +11,15 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue; import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
@ -74,6 +77,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
protected I2PTunnelTask task; protected I2PTunnelTask task;
protected boolean bidir; protected boolean bidir;
private ThreadPoolExecutor _executor; private ThreadPoolExecutor _executor;
private final Map<Integer, InetSocketAddress> _socketMap = new ConcurrentHashMap(4);
/** unused? port should always be specified */ /** unused? port should always be specified */
private int DEFAULT_LOCALPORT = 4488; private int DEFAULT_LOCALPORT = 4488;
@ -95,6 +99,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
this.remoteHost = host; this.remoteHost = host;
this.remotePort = port; this.remotePort = port;
_usePool = getUsePool(); _usePool = getUsePool();
buildSocketMap(tunnel.getClientOptions());
sockMgr = createManager(bais); sockMgr = createManager(bais);
} }
@ -115,6 +120,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
this.remoteHost = host; this.remoteHost = host;
this.remotePort = port; this.remotePort = port;
_usePool = getUsePool(); _usePool = getUsePool();
buildSocketMap(tunnel.getClientOptions());
FileInputStream fis = null; FileInputStream fis = null;
try { try {
fis = new FileInputStream(privkey); fis = new FileInputStream(privkey);
@ -145,6 +151,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
this.remoteHost = host; this.remoteHost = host;
this.remotePort = port; this.remotePort = port;
_usePool = getUsePool(); _usePool = getUsePool();
buildSocketMap(tunnel.getClientOptions());
sockMgr = createManager(privData); sockMgr = createManager(privData);
} }
@ -162,6 +169,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
this.remotePort = port; this.remotePort = port;
_log = tunnel.getContext().logManager().getLog(getClass()); _log = tunnel.getContext().logManager().getLog(getClass());
_usePool = false; _usePool = false;
buildSocketMap(tunnel.getClientOptions());
sockMgr = sktMgr; sockMgr = sktMgr;
open = true; open = true;
} }
@ -348,6 +356,37 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
return; return;
Properties props = tunnel.getClientOptions(); Properties props = tunnel.getClientOptions();
sockMgr.setDefaultOptions(sockMgr.buildOptions(props)); sockMgr.setDefaultOptions(sockMgr.buildOptions(props));
buildSocketMap(props);
}
/**
* Update the ports map.
*
* @since 0.9.9
*/
private void buildSocketMap(Properties props) {
_socketMap.clear();
for (Map.Entry e : props.entrySet()) {
String key = (String) e.getKey();
if (key.startsWith("targetForPort.")) {
key = key.substring("targetForPort.".length());
try {
int myPort = Integer.parseInt(key);
String host = (String) e.getValue();
int colon = host.indexOf(":");
int port = Integer.parseInt(host.substring(colon + 1));
host = host.substring(0, colon);
InetSocketAddress isa = new InetSocketAddress(host, port);
if (isa.isUnresolved())
l.log("Warning - cannot resolve address for port " + key + ": " + host);
_socketMap.put(Integer.valueOf(myPort), isa);
} catch (NumberFormatException nfe) {
l.log("Bad socket spec for port " + key + ": " + e.getValue());
} catch (IndexOutOfBoundsException ioobe) {
l.log("Bad socket spec for port " + key + ": " + e.getValue());
}
}
}
} }
protected int getHandlerCount() { protected int getHandlerCount() {
@ -473,7 +512,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
//threads. //threads.
try { try {
socket.setReadTimeout(readTimeout); socket.setReadTimeout(readTimeout);
Socket s = getSocket(remoteHost, remotePort); Socket s = getSocket(socket.getLocalPort());
afterSocket = getTunnel().getContext().clock().now(); afterSocket = getTunnel().getContext().clock().now();
new I2PTunnelRunner(s, socket, slock, null, null); new I2PTunnelRunner(s, socket, slock, null, null);
@ -494,7 +533,30 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
} }
/** /**
* Get a regular or SSL socket depending on config * Get a regular or SSL socket depending on config and the incoming port.
* To configure a specific host:port as the server for incoming port xx,
* set option targetForPort.xx=host:port
*
* @since 0.9.9
*/
protected Socket getSocket(int incomingPort) throws IOException {
InetAddress host = remoteHost;
int port = remotePort;
if (incomingPort != 0 && !_socketMap.isEmpty()) {
InetSocketAddress isa = _socketMap.get(Integer.valueOf(incomingPort));
if (isa != null) {
host = isa.getAddress();
if (host == null)
throw new IOException("Cannot resolve " + isa.getHostName());
port = isa.getPort();
}
}
return getSocket(host, port);
}
/**
* Get a regular or SSL socket depending on config.
* The SSL config applies to all hosts/ports.
* *
* @since 0.9.9 * @since 0.9.9
*/ */

View File

@ -1,3 +1,9 @@
2013-10-24 zzz
* I2PTunnel standard, HTTP, and IRC servers:
Route connections to specific targets based on incoming I2P port
with custom option targetForPort.xxxx=myserver:yyyy
This allows multiple services on a single server tunnel (ticket #1066)
2013-10-23 zzz 2013-10-23 zzz
* I2PTunnel standard and IRC clients: * I2PTunnel standard and IRC clients:
- Allow host:port targets; set defaults in i2ptunnel.config (ticket #1066) - Allow host:port targets; set defaults in i2ptunnel.config (ticket #1066)

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 8; public final static long BUILD = 9;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = ""; public final static String EXTRA = "";