diff --git a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java index b814124f84..d40b5352e9 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java +++ b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java @@ -62,12 +62,10 @@ class SAMHandlerFactory { // Message format: HELLO VERSION [MIN=v1] [MAX=v2] Properties props = SAMUtils.parseParams(line); - if (!"HELLO".equals(props.getProperty(SAMUtils.COMMAND)) || - !"VERSION".equals(props.getProperty(SAMUtils.OPCODE))) { + if (!"HELLO".equals(props.remove(SAMUtils.COMMAND)) || + !"VERSION".equals(props.remove(SAMUtils.OPCODE))) { throw new SAMException("Must start with HELLO VERSION"); } - props.remove(SAMUtils.COMMAND); - props.remove(SAMUtils.OPCODE); String minVer = props.getProperty("MIN"); if (minVer == null) { diff --git a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java index e779e05fa1..d2cba4b82d 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java @@ -15,6 +15,8 @@ import java.io.IOException; import java.io.InterruptedIOException; import java.net.ConnectException; import java.net.NoRouteToHostException; +import java.net.Socket; +import java.net.SocketTimeoutException; import java.nio.channels.SocketChannel; import java.nio.ByteBuffer; import java.util.Properties; @@ -48,6 +50,7 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece protected final long _id; private static final AtomicLong __id = new AtomicLong(); + private static final int FIRST_READ_TIMEOUT = 60*1000; /** * Create a new SAM version 1 handler. This constructor expects @@ -105,6 +108,7 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece _log.debug("SAM handling started"); try { + boolean gotFirstLine = false; while (true) { if (shouldStop()) { if (_log.shouldLog(Log.DEBUG)) @@ -122,33 +126,38 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece break; } buf.setLength(0); - // TODO set timeout first time - ReadLine.readLine(clientSocketChannel.socket(), buf, 0); + // first time, set a timeout + try { + Socket sock = clientSocketChannel.socket(); + ReadLine.readLine(sock, buf, gotFirstLine ? 0 : FIRST_READ_TIMEOUT); + sock.setSoTimeout(0); + } catch (SocketTimeoutException ste) { + writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"command timeout, bye\"\n"); + break; + } msg = buf.toString(); if (_log.shouldLog(Log.DEBUG)) { _log.debug("New message received: [" + msg + ']'); } props = SAMUtils.parseParams(msg); - domain = props.getProperty(SAMUtils.COMMAND); + domain = (String) props.remove(SAMUtils.COMMAND); if (domain == null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Ignoring newline"); continue; } - opcode = props.getProperty(SAMUtils.OPCODE); + opcode = (String) props.remove(SAMUtils.OPCODE); if (opcode == null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Error in message format"); break; } - props.remove(SAMUtils.COMMAND); - props.remove(SAMUtils.OPCODE); if (_log.shouldLog(Log.DEBUG)) { _log.debug("Parsing (domain: \"" + domain + "\"; opcode: \"" + opcode + "\")"); } - + gotFirstLine = true; if (domain.equals("STREAM")) { canContinue = execStreamMessage(opcode, props); } else if (domain.equals("DATAGRAM")) { @@ -360,16 +369,11 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece /* Parse and execute a NAMING message */ protected boolean execNamingMessage(String opcode, Properties props) { if (opcode.equals("LOOKUP")) { - if (props.isEmpty()) { - _log.debug("No parameters specified in NAMING LOOKUP message"); - return false; - } - String name = props.getProperty("NAME"); if (name == null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Name to resolve not specified in NAMING message"); - return false; + return writeString("NAMING REPLY RESULT=KEY_NOT_FOUND NAME=\"\" MESSAGE=\"Must specify NAME\"\n"); } Destination dest = null ; diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java index 6723c2624e..032538b0c8 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java @@ -54,6 +54,7 @@ class SAMv3Handler extends SAMv1Handler private volatile boolean streamForwardingSocket; private final boolean sendPorts; private long _lastPing; + private static final int FIRST_READ_TIMEOUT = 60*1000; private static final int READ_TIMEOUT = 3*60*1000; interface Session { @@ -272,6 +273,7 @@ class SAMv3Handler extends SAMv1Handler InputStream in = socket.getInputStream(); StringBuilder buf = new StringBuilder(1024); + boolean gotFirstLine = false; while (true) { if (shouldStop()) { if (_log.shouldLog(Log.DEBUG)) @@ -329,23 +331,28 @@ class SAMv3Handler extends SAMv1Handler } } else { buf.setLength(0); - // TODO first time, set a timeout - ReadLine.readLine(socket, buf, 0); + // first time, set a timeout + try { + ReadLine.readLine(socket, buf, gotFirstLine ? 0 : FIRST_READ_TIMEOUT); + socket.setSoTimeout(0); + } catch (SocketTimeoutException ste) { + writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"command timeout, bye\"\n"); + break; + } line = buf.toString(); } if (_log.shouldLog(Log.DEBUG)) _log.debug("New message received: [" + line + ']'); props = SAMUtils.parseParams(line); - domain = props.getProperty(SAMUtils.COMMAND); + domain = (String) props.remove(SAMUtils.COMMAND); if (domain == null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Ignoring newline"); continue; } - opcode = props.getProperty(SAMUtils.OPCODE); - props.remove(SAMUtils.COMMAND); - props.remove(SAMUtils.OPCODE); + gotFirstLine = true; + opcode = (String) props.remove(SAMUtils.OPCODE); if (_log.shouldLog(Log.DEBUG)) { _log.debug("Parsing (domain: \"" + domain + "\"; opcode: \"" + opcode + "\")");