diff --git a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java index 56757acde..8fb040076 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java +++ b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java @@ -17,12 +17,14 @@ import java.util.StringTokenizer; import net.i2p.data.DataHelper; import net.i2p.util.Log; +import net.i2p.util.VersionComparator; /** * SAM handler factory class. */ class SAMHandlerFactory { + private static final String VERSION = "3.0"; /** * Return the right SAM handler depending on the protocol version @@ -66,9 +68,8 @@ class SAMHandlerFactory { } } - Properties props; - props = SAMUtils.parseParams(tok); - if (props == null) { + Properties props = SAMUtils.parseParams(tok); + if (props.isEmpty()) { throw new SAMException("No parameters in HELLO VERSION message"); } @@ -79,7 +80,9 @@ class SAMHandlerFactory { String maxVer = props.getProperty("MAX"); if (maxVer == null) { - throw new SAMException("Missing MAX parameter in HELLO VERSION message"); + //throw new SAMException("Missing MAX parameter in HELLO VERSION message"); + // MAX optional as of 0.9.14 + maxVer = "99.99"; } String ver = chooseBestVersion(minVer, maxVer); @@ -119,30 +122,28 @@ class SAMHandlerFactory { return handler; } - /* Return the best version we can use, or null on failure */ + /* + * @return "x.y" the best version we can use, or null on failure + */ private static String chooseBestVersion(String minVer, String maxVer) { - - int minMajor = getMajor(minVer), minMinor = getMinor(minVer); - int maxMajor = getMajor(maxVer), maxMinor = getMinor(maxVer); - - // Consistency checks - if ((minMajor == -1) || (minMinor == -1) - || (maxMajor == -1) || (maxMinor == -1)) { - return null; + // in VersionComparator, "3" < "3.0" so + // use comparisons carefully + if (VersionComparator.comp("3.0", minVer) >= 0) { + // Documentation said: + // In order to force protocol version 3.0, the values of $min and $max + // must be "3.0". + int maxcomp = VersionComparator.comp("3", maxVer); + if (maxcomp == 0 || maxVer.equals("3.0")) + return "3.0"; // spoof version + if (maxcomp < 0) + return VERSION; } - - if ((minMinor >= 10) || (maxMinor >= 10)) return null ; - - float fminVer = minMajor + (float) minMinor / 10 ; - float fmaxVer = maxMajor + (float) maxMinor / 10 ; - - - if ( ( fminVer <= 3.0 ) && ( fmaxVer >= 3.0 ) ) return "3.0" ; - - if ( ( fminVer <= 2.0 ) && ( fmaxVer >= 2.0 ) ) return "2.0" ; - - if ( ( fminVer <= 1.0 ) && ( fmaxVer >= 1.0 ) ) return "1.0" ; - + if (VersionComparator.comp("2.0", minVer) >= 0 && + VersionComparator.comp("2", maxVer) <= 0) + return "2.0"; + if (VersionComparator.comp("1.0", minVer) >= 0 && + VersionComparator.comp("1", maxVer) <= 0) + return "1.0"; return null; } diff --git a/apps/sam/java/src/net/i2p/sam/SAMUtils.java b/apps/sam/java/src/net/i2p/sam/SAMUtils.java index d08af7d03..f80948232 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMUtils.java +++ b/apps/sam/java/src/net/i2p/sam/SAMUtils.java @@ -159,26 +159,34 @@ class SAMUtils { * @param tok A StringTokenizer pointing to the SAM parameters * * @throws SAMException if the data was formatted incorrectly - * @return Properties with the parsed SAM params + * @return Properties with the parsed SAM params, never null */ public static Properties parseParams(StringTokenizer tok) throws SAMException { - int pos, ntoks = tok.countTokens(); - String token, param; + int ntoks = tok.countTokens(); Properties props = new Properties(); StringBuilder value = new StringBuilder(); for (int i = 0; i < ntoks; ++i) { - token = tok.nextToken(); + String token = tok.nextToken(); - pos = token.indexOf("="); - if (pos == -1) { + int pos = token.indexOf("="); + if (pos <= 0) { //_log.debug("Error in params format"); - throw new SAMException("Bad formatting for param [" + token + "]"); + if (pos == 0) { + throw new SAMException("No param specified [" + token + "]"); + } else { + throw new SAMException("Bad formatting for param [" + token + "]"); + } } - param = token.substring(0, pos); + + String param = token.substring(0, pos); value.append(token.substring(pos+1)); if (value.length() == 0) - throw new SAMException("Empty value for param "+param); + throw new SAMException("Empty value for param " + param); + + // FIXME: The following code does not take into account that there + // may have been multiple subsequent space chars in the input that + // StringTokenizer treates as one. if (value.charAt(0) == '"') { while ( (i < ntoks) && (value.lastIndexOf("\"") <= 0) ) { value.append(' ').append(tok.nextToken()); diff --git a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java index eab3740f7..9b4bc1184 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java @@ -85,9 +85,9 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece } } - public boolean verifVersion() { - return ( verMajor == 1 && verMinor == 0 ) ; - } + public boolean verifVersion() { + return (verMajor == 1); + } public void handle() { String msg = null; diff --git a/apps/sam/java/src/net/i2p/sam/SAMv2Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv2Handler.java index 2a76b9da3..3b4c21680 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv2Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv2Handler.java @@ -55,9 +55,10 @@ class SAMv2Handler extends SAMv1Handler implements SAMRawReceiver, SAMDatagramRe super ( s, verMajor, verMinor, i2cpProps ); } + @Override public boolean verifVersion() { - return (verMajor == 2 && verMinor == 0) ; + return (verMajor == 2); } SAMStreamSession newSAMStreamSession(String destKeystream, String direction, Properties props ) diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java index 9020e55af..b56a164e3 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java @@ -88,9 +88,10 @@ class SAMv3Handler extends SAMv1Handler _log.debug("SAM version 3 handler instantiated"); } + @Override public boolean verifVersion() { - return (verMajor == 3 && verMinor == 0) ; + return (verMajor == 3); } public static class DatagramServer {