SAM: Timeout for first command after HELLO

Better removal of command and opcode from properties
Send error message if no NAME key in LOOKUP
This commit is contained in:
zzz
2015-11-30 21:57:55 +00:00
parent 3c8cc16273
commit f778c23f0b
3 changed files with 32 additions and 23 deletions

View File

@@ -62,12 +62,10 @@ class SAMHandlerFactory {
// Message format: HELLO VERSION [MIN=v1] [MAX=v2] // Message format: HELLO VERSION [MIN=v1] [MAX=v2]
Properties props = SAMUtils.parseParams(line); Properties props = SAMUtils.parseParams(line);
if (!"HELLO".equals(props.getProperty(SAMUtils.COMMAND)) || if (!"HELLO".equals(props.remove(SAMUtils.COMMAND)) ||
!"VERSION".equals(props.getProperty(SAMUtils.OPCODE))) { !"VERSION".equals(props.remove(SAMUtils.OPCODE))) {
throw new SAMException("Must start with HELLO VERSION"); throw new SAMException("Must start with HELLO VERSION");
} }
props.remove(SAMUtils.COMMAND);
props.remove(SAMUtils.OPCODE);
String minVer = props.getProperty("MIN"); String minVer = props.getProperty("MIN");
if (minVer == null) { if (minVer == null) {

View File

@@ -15,6 +15,8 @@ import java.io.IOException;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.NoRouteToHostException; import java.net.NoRouteToHostException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Properties; import java.util.Properties;
@@ -48,6 +50,7 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
protected final long _id; protected final long _id;
private static final AtomicLong __id = new AtomicLong(); 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 * 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"); _log.debug("SAM handling started");
try { try {
boolean gotFirstLine = false;
while (true) { while (true) {
if (shouldStop()) { if (shouldStop()) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
@@ -122,33 +126,38 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
break; break;
} }
buf.setLength(0); buf.setLength(0);
// TODO set timeout first time // first time, set a timeout
ReadLine.readLine(clientSocketChannel.socket(), buf, 0); 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(); msg = buf.toString();
if (_log.shouldLog(Log.DEBUG)) { if (_log.shouldLog(Log.DEBUG)) {
_log.debug("New message received: [" + msg + ']'); _log.debug("New message received: [" + msg + ']');
} }
props = SAMUtils.parseParams(msg); props = SAMUtils.parseParams(msg);
domain = props.getProperty(SAMUtils.COMMAND); domain = (String) props.remove(SAMUtils.COMMAND);
if (domain == null) { if (domain == null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Ignoring newline"); _log.debug("Ignoring newline");
continue; continue;
} }
opcode = props.getProperty(SAMUtils.OPCODE); opcode = (String) props.remove(SAMUtils.OPCODE);
if (opcode == null) { if (opcode == null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Error in message format"); _log.debug("Error in message format");
break; break;
} }
props.remove(SAMUtils.COMMAND);
props.remove(SAMUtils.OPCODE);
if (_log.shouldLog(Log.DEBUG)) { if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Parsing (domain: \"" + domain _log.debug("Parsing (domain: \"" + domain
+ "\"; opcode: \"" + opcode + "\")"); + "\"; opcode: \"" + opcode + "\")");
} }
gotFirstLine = true;
if (domain.equals("STREAM")) { if (domain.equals("STREAM")) {
canContinue = execStreamMessage(opcode, props); canContinue = execStreamMessage(opcode, props);
} else if (domain.equals("DATAGRAM")) { } else if (domain.equals("DATAGRAM")) {
@@ -360,16 +369,11 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
/* Parse and execute a NAMING message */ /* Parse and execute a NAMING message */
protected boolean execNamingMessage(String opcode, Properties props) { protected boolean execNamingMessage(String opcode, Properties props) {
if (opcode.equals("LOOKUP")) { if (opcode.equals("LOOKUP")) {
if (props.isEmpty()) {
_log.debug("No parameters specified in NAMING LOOKUP message");
return false;
}
String name = props.getProperty("NAME"); String name = props.getProperty("NAME");
if (name == null) { if (name == null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Name to resolve not specified in NAMING message"); _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 ; Destination dest = null ;

View File

@@ -54,6 +54,7 @@ class SAMv3Handler extends SAMv1Handler
private volatile boolean streamForwardingSocket; private volatile boolean streamForwardingSocket;
private final boolean sendPorts; private final boolean sendPorts;
private long _lastPing; private long _lastPing;
private static final int FIRST_READ_TIMEOUT = 60*1000;
private static final int READ_TIMEOUT = 3*60*1000; private static final int READ_TIMEOUT = 3*60*1000;
interface Session { interface Session {
@@ -272,6 +273,7 @@ class SAMv3Handler extends SAMv1Handler
InputStream in = socket.getInputStream(); InputStream in = socket.getInputStream();
StringBuilder buf = new StringBuilder(1024); StringBuilder buf = new StringBuilder(1024);
boolean gotFirstLine = false;
while (true) { while (true) {
if (shouldStop()) { if (shouldStop()) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
@@ -329,23 +331,28 @@ class SAMv3Handler extends SAMv1Handler
} }
} else { } else {
buf.setLength(0); buf.setLength(0);
// TODO first time, set a timeout // first time, set a timeout
ReadLine.readLine(socket, buf, 0); 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(); line = buf.toString();
} }
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("New message received: [" + line + ']'); _log.debug("New message received: [" + line + ']');
props = SAMUtils.parseParams(line); props = SAMUtils.parseParams(line);
domain = props.getProperty(SAMUtils.COMMAND); domain = (String) props.remove(SAMUtils.COMMAND);
if (domain == null) { if (domain == null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Ignoring newline"); _log.debug("Ignoring newline");
continue; continue;
} }
opcode = props.getProperty(SAMUtils.OPCODE); gotFirstLine = true;
props.remove(SAMUtils.COMMAND); opcode = (String) props.remove(SAMUtils.OPCODE);
props.remove(SAMUtils.OPCODE);
if (_log.shouldLog(Log.DEBUG)) { if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Parsing (domain: \"" + domain _log.debug("Parsing (domain: \"" + domain
+ "\"; opcode: \"" + opcode + "\")"); + "\"; opcode: \"" + opcode + "\")");