allow the user to override the I2CP options (exposed on the command line, ala

SAMBridge [[listenHost ]listenPort[ name=val]*]
where listenHost defaults to localhost, listenPort defaults to 7656, and name=val
can be the I2CP options to override (e.g. i2cp.tcp.host=localhost i2cp.tcp.port=4001)
This commit is contained in:
jrandom
2004-04-20 07:26:34 +00:00
committed by zzz
parent bed7d09764
commit 203d0e870a
4 changed files with 144 additions and 65 deletions

View File

@ -12,6 +12,7 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
@ -25,81 +26,136 @@ public class SAMBridge implements Runnable {
private final static Log _log = new Log(SAMBridge.class);
private ServerSocket serverSocket;
private Properties i2cpProps;
private boolean acceptConnections = true;
private final static int SAM_LISTENPORT = 7656;
/**
* Build a new SAM bridge listening on 127.0.0.1.
*
* @param listenPort The port to listen on
*/
public SAMBridge(int listenPort) {
this((String)null, listenPort);
}
private SAMBridge() {}
/**
* Build a new SAM bridge.
*
* @param listenHost The network interface to listen on
* @param listenPort The port to listen on
* @param listenHost hostname to listen for SAM connections on ("0.0.0.0" for all)
* @param listenPort port number to listen for SAM connections on
* @param i2cpProps set of I2CP properties for finding and communicating with the router
*/
public SAMBridge(String listenHost, int listenPort) {
try {
if (listenHost != null) {
serverSocket = new ServerSocket(listenPort, 0,
InetAddress.getByName(listenHost));
_log.debug("SAM bridge listening on "
+ listenHost + ":" + listenPort);
} else {
serverSocket = new ServerSocket(listenPort);
_log.debug("SAM bridge listening on 0.0.0.0:" + listenPort);
}
} catch (Exception e) {
_log.error("Error starting SAM bridge on "
+ (listenHost == null ? "0.0.0.0" : listenHost)
+ ":" + listenPort, e);
}
public SAMBridge(String listenHost, int listenPort, Properties i2cpProps) {
try {
if ( (listenHost != null) && !("0.0.0.0".equals(listenHost)) ) {
serverSocket = new ServerSocket(listenPort, 0, InetAddress.getByName(listenHost));
if (_log.shouldLog(Log.DEBUG))
_log.debug("SAM bridge listening on "
+ listenHost + ":" + listenPort);
} else {
serverSocket = new ServerSocket(listenPort);
if (_log.shouldLog(Log.DEBUG))
_log.debug("SAM bridge listening on 0.0.0.0:" + listenPort);
}
} catch (Exception e) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error starting SAM bridge on "
+ (listenHost == null ? "0.0.0.0" : listenHost)
+ ":" + listenPort, e);
}
this.i2cpProps = i2cpProps;
}
/**
* Usage:
* <pre>SAMBridge [[listenHost ]listenPort[ name=val]*]</pre>
*
* name=val options are passed to the I2CP code to build a session,
* allowing the bridge to specify an alternate I2CP host and port, tunnel
* depth, etc.
*/
public static void main(String args[]) {
SAMBridge bridge = new SAMBridge(SAM_LISTENPORT);
I2PThread t = new I2PThread(bridge, "SAMListener");
t.start();
int port = SAM_LISTENPORT;
String host = "0.0.0.0";
Properties opts = null;
if (args.length > 0) {
int portIndex = 0;
try {
port = Integer.parseInt(args[portIndex]);
} catch (NumberFormatException nfe) {
host = args[0];
portIndex++;
try {
port = Integer.parseInt(args[portIndex]);
} catch (NumberFormatException nfe1) {
usage();
return;
}
}
opts = parseOptions(args, portIndex+1);
}
SAMBridge bridge = new SAMBridge(host, port, opts);
I2PThread t = new I2PThread(bridge, "SAMListener");
t.start();
}
private static Properties parseOptions(String args[], int startArgs) {
Properties props = new Properties();
// skip over first few options
for (int i = startArgs; i < args.length; i++) {
int eq = args[i].indexOf('=');
if (eq <= 0) continue;
if (eq >= args[i].length()-1) continue;
String key = args[i].substring(0, eq);
String val = args[i].substring(eq+1);
key = key.trim();
val = val.trim();
if ( (key.length() > 0) && (val.length() > 0) )
props.setProperty(key, val);
}
return props;
}
private static void usage() {
System.err.println("Usage: SAMBridge [listenHost listenPortNum[ name=val]*]");
System.err.println(" listenHost: interface to listen on (0.0.0.0 for all interfaces)");
System.err.println(" listenPort: port to listen for SAM connections on (default 7656)");
System.err.println(" name=val: options to pass when connecting via I2CP, such as ");
System.err.println(" i2cp.host=localhost and i2cp.port=7654");
}
public void run() {
try {
while (acceptConnections) {
Socket s = serverSocket.accept();
_log.debug("New connection from "
+ s.getInetAddress().toString() + ":"
+ s.getPort());
try {
SAMHandler handler = SAMHandlerFactory.createSAMHandler(s);
if (handler == null) {
_log.debug("SAM handler has not been instantiated");
try {
s.close();
} catch (IOException e) {}
continue;
}
handler.startHandling();
} catch (SAMException e) {
_log.error("SAM error: " + e.getMessage());
s.close();
}
}
} catch (Exception e) {
_log.error("Unexpected error while listening for connections", e);
} finally {
try {
_log.debug("Shutting down, closing server socket");
serverSocket.close();
} catch (IOException e) {}
}
try {
while (acceptConnections) {
Socket s = serverSocket.accept();
if (_log.shouldLog(Log.DEBUG))
_log.debug("New connection from "
+ s.getInetAddress().toString() + ":"
+ s.getPort());
try {
SAMHandler handler = SAMHandlerFactory.createSAMHandler(s, i2cpProps);
if (handler == null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("SAM handler has not been instantiated");
try {
s.close();
} catch (IOException e) {}
continue;
}
handler.startHandling();
} catch (SAMException e) {
if (_log.shouldLog(Log.ERROR))
_log.error("SAM error: " + e.getMessage(), e);
s.close();
}
}
} catch (Exception e) {
if (_log.shouldLog(Log.ERROR))
_log.error("Unexpected error while listening for connections", e);
} finally {
try {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Shutting down, closing server socket");
serverSocket.close();
} catch (IOException e) {}
}
}
}

View File

@ -13,6 +13,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Properties;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
@ -35,6 +37,9 @@ public abstract class SAMHandler implements Runnable {
protected int verMajor = 0;
protected int verMinor = 0;
/** I2CP options configuring the I2CP connection (port, host, numHops, etc) */
protected Properties i2cpProps = null;
private Object stopLock = new Object();
private boolean stopHandler = false;
@ -45,14 +50,16 @@ public abstract class SAMHandler implements Runnable {
* @param s Socket attached to a SAM client
* @param verMajor SAM major version to manage
* @param verMinor SAM minor version to manage
* @param i2cpProps properties to configure the I2CP connection (host, port, etc)
*/
protected SAMHandler(Socket s,
int verMajor, int verMinor) throws IOException {
int verMajor, int verMinor, Properties i2cpProps) throws IOException {
socket = s;
socketOS = socket.getOutputStream();
this.verMajor = verMajor;
this.verMinor = verMinor;
this.i2cpProps = i2cpProps;
}
/**

View File

@ -31,10 +31,11 @@ public class SAMHandlerFactory {
* required by the client.
*
* @param s Socket attached to SAM client
* @param i2cpProps config options for our i2cp connection
*
* @return A SAM protocol handler
*/
public static SAMHandler createSAMHandler(Socket s) throws SAMException {
public static SAMHandler createSAMHandler(Socket s, Properties i2cpProps) throws SAMException {
BufferedReader br;
String line;
StringTokenizer tok;
@ -127,7 +128,7 @@ public class SAMHandlerFactory {
try {
switch (verMajor) {
case 1:
handler = new SAMv1Handler(s, verMajor, verMinor);
handler = new SAMv1Handler(s, verMajor, verMinor, i2cpProps);
break;
default:
_log.error("BUG! Trying to initialize the wrong SAM version!");

View File

@ -55,7 +55,20 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
* @param verMinor SAM minor version to manage
*/
public SAMv1Handler(Socket s, int verMajor, int verMinor) throws SAMException, IOException {
super(s, verMajor, verMinor);
this(s, verMajor, verMinor, new Properties());
}
/**
* Create a new SAM version 1 handler. This constructor expects
* that the SAM HELLO message has been still answered (and
* stripped) from the socket input stream.
*
* @param s Socket attached to a SAM client
* @param verMajor SAM major version to manage (should be 1)
* @param verMinor SAM minor version to manage
* @param i2cpProps properties to configure the I2CP connection (host, port, etc)
*/
public SAMv1Handler(Socket s, int verMajor, int verMinor, Properties i2cpProps) throws SAMException, IOException {
super(s, verMajor, verMinor, i2cpProps);
_log.debug("SAM version 1 handler instantiated");
if ((this.verMajor != 1) || (this.verMinor != 0)) {
@ -113,6 +126,8 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
+ "\"; opcode: \"" + opcode + "\")");
}
props = SAMUtils.parseParams(tok);
if (i2cpProps != null)
props.putAll(i2cpProps); // make sure we've got the i2cp settings
if (domain.equals("STREAM")) {
canContinue = execStreamMessage(opcode, props);