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:
@ -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) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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!");
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user