From edde533e1b2cf7ae541350b72fe8de3a5ff5b9e4 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Sat, 6 Feb 2016 16:56:37 +0000 Subject: [PATCH] SAM v3.3: Fixes after testing - More error checking - Better error responses - Fix listen port and protocol for DATAGRAM and RAW - Fix adding sessions with duplicate dests to DB - Add more sessions in SAMStreamSink --- .../java/src/net/i2p/sam/MasterSession.java | 16 +++++++++------ .../src/net/i2p/sam/SAMMessageSession.java | 10 ++++------ .../src/net/i2p/sam/SAMStreamSession.java | 2 +- .../java/src/net/i2p/sam/SAMv3Handler.java | 14 ++++++------- apps/sam/java/src/net/i2p/sam/SessionsDB.java | 20 +++++++++++-------- .../src/net/i2p/sam/client/SAMReader.java | 4 ++++ .../src/net/i2p/sam/client/SAMStreamSink.java | 19 ++++++++++++++++-- 7 files changed, 55 insertions(+), 30 deletions(-) diff --git a/apps/sam/java/src/net/i2p/sam/MasterSession.java b/apps/sam/java/src/net/i2p/sam/MasterSession.java index ba64e9255a..76ba6ab3a4 100644 --- a/apps/sam/java/src/net/i2p/sam/MasterSession.java +++ b/apps/sam/java/src/net/i2p/sam/MasterSession.java @@ -42,6 +42,7 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S private final SAMv3DatagramServer dgs; private final Map<String, SAMMessageSess> sessions; private final StreamAcceptor streamAcceptor; + private static final String[] INVALID_OPTS = { "PORT", "HOST", "FROM_PORT", "TO_PORT", "PROTOCOL" }; /** * Build a Session according to information @@ -57,6 +58,11 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S public MasterSession(String nick, SAMv3DatagramServer dgServer, SAMv3Handler handler, Properties props) throws IOException, DataFormatException, SAMException { super(nick); + for (int i = 0; i < INVALID_OPTS.length; i++) { + String p = INVALID_OPTS[i]; + if (props.containsKey(p)) + throw new SAMException("MASTER session options may not contain " + p); + } dgs = dgServer; sessions = new ConcurrentHashMap<String, SAMMessageSess>(4); this.handler = handler; @@ -162,15 +168,13 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S rec = new SessionRecord(getDestination().toBase64(), props, subhandler); try { - if (!SAMv3Handler.sSessionsHash.put(nick, rec)) - return "Duplicate ID " + nick; + SAMv3Handler.sSessionsHash.putDupDestOK(nick, rec); sessions.put(nick, sess); } catch (SessionsDB.ExistingIdException e) { - return e.toString(); - } catch (SessionsDB.ExistingDestException e) { - // fixme need new db method for dup dests + return "Duplicate ID " + nick; } - // listeners etc + if (_log.shouldWarn()) + _log.warn("added " + style + " proto " + listenProtocol + " port " + listenPort); sess.start(); // all ok diff --git a/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java b/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java index a65f387cf1..328749afb4 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java +++ b/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java @@ -67,11 +67,10 @@ abstract class SAMMessageSession implements SAMMessageSess { _log = I2PAppContext.getGlobalContext().logManager().getLog(getClass()); if (_log.shouldLog(Log.DEBUG)) _log.debug("Initializing SAM message-based session"); - - handler = new SAMMessageSessionHandler(destStream, props); - session = handler.getSession(); listenProtocol = I2PSession.PROTO_ANY; listenPort = I2PSession.PORT_ANY; + handler = new SAMMessageSessionHandler(destStream, props); + session = handler.getSession(); } /** @@ -89,11 +88,10 @@ abstract class SAMMessageSession implements SAMMessageSess { _log = I2PAppContext.getGlobalContext().logManager().getLog(getClass()); if (_log.shouldLog(Log.DEBUG)) _log.debug("Initializing SAM message-based session"); - - session = sess; - handler = new SAMMessageSessionHandler(session); this.listenProtocol = listenProtocol; this.listenPort = listenPort; + session = sess; + handler = new SAMMessageSessionHandler(session); } /* diff --git a/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java b/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java index 42edac0b58..6cebed71da 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java +++ b/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java @@ -368,7 +368,7 @@ class SAMStreamSession implements SAMMessageSess { * @since 0.9.25 moved from subclass SAMv3StreamSession to implement SAMMessageSess */ public boolean sendBytes(String s, byte[] b, int pr, int fp, int tp) throws I2PSessionException { - throw new I2PSessionException("Unsupported in stream or master session"); + throw new I2PSessionException("Unsupported in STREAM or MASTER session"); } /** diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java index e8284964ff..48774d5652 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java @@ -314,10 +314,13 @@ class SAMv3Handler extends SAMv1Handler } catch (IOException e) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Caught IOException in handler", e); + writeString(SESSION_ERROR, e.getMessage()); } catch (SAMException e) { _log.error("Unexpected exception for message [" + msg + ']', e); + writeString(SESSION_ERROR, e.getMessage()); } catch (RuntimeException e) { _log.error("Unexpected exception for message [" + msg + ']', e); + writeString(SESSION_ERROR, e.getMessage()); } finally { if (_log.shouldLog(Log.DEBUG)) _log.debug("Stopping handler"); @@ -467,8 +470,6 @@ class SAMv3Handler extends SAMv1Handler // SAMStreamSession constructor. allProps.setProperty("i2p.streaming.enforceProtocol", "true"); allProps.setProperty("i2cp.dontPublishLeaseSet", "false"); - allProps.setProperty("FROM_PORT", Integer.toString(I2PSession.PORT_UNSPECIFIED)); - allProps.setProperty("TO_PORT", Integer.toString(I2PSession.PORT_UNSPECIFIED)); } try { @@ -530,9 +531,9 @@ class SAMv3Handler extends SAMv1Handler msg = msess.remove(nick, props); } if (msg == null) - return writeString("SESSION STATUS RESULT=OK", opcode + ' ' + nick); + return writeString("SESSION STATUS RESULT=OK ID=\"" + nick + '"', opcode + ' ' + nick); else - return writeString(SESSION_ERROR, msg); + return writeString(SESSION_ERROR + " ID=\"" + nick + '"', msg); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Unrecognized SESSION message opcode: \"" @@ -581,10 +582,9 @@ class SAMv3Handler extends SAMv1Handler if ( session != null ) { - _log.error ( "STREAM message received, but this session is a master session" ); - + _log.error("v3 control socket cannot be used for STREAM"); try { - notifyStreamResult(true, "I2P_ERROR", "master session cannot be used for streams"); + notifyStreamResult(true, "I2P_ERROR", "v3 control socket cannot be used for STREAM"); } catch (IOException e) {} return false; } diff --git a/apps/sam/java/src/net/i2p/sam/SessionsDB.java b/apps/sam/java/src/net/i2p/sam/SessionsDB.java index 21876d7cc6..dfdc3c0041 100644 --- a/apps/sam/java/src/net/i2p/sam/SessionsDB.java +++ b/apps/sam/java/src/net/i2p/sam/SessionsDB.java @@ -32,8 +32,7 @@ class SessionsDB { map = new HashMap<String, SessionRecord>() ; } - /** @return success */ - synchronized public boolean put( String nick, SessionRecord session ) + public synchronized void put(String nick, SessionRecord session) throws ExistingIdException, ExistingDestException { if ( map.containsKey(nick) ) { @@ -44,14 +43,19 @@ class SessionsDB { throw new ExistingDestException(); } } + session.createThreadGroup("SAM session "+nick); + map.put(nick, session) ; + } - if ( !map.containsKey(nick) ) { - session.createThreadGroup("SAM session "+nick); - map.put(nick, session) ; - return true ; + /** @since 0.9.25 */ + public synchronized void putDupDestOK(String nick, SessionRecord session) + throws ExistingIdException + { + if (map.containsKey(nick)) { + throw new ExistingIdException(); } - else - return false ; + session.createThreadGroup("SAM session "+nick); + map.put(nick, session) ; } /** @return true if removed */ diff --git a/apps/sam/java/src/net/i2p/sam/client/SAMReader.java b/apps/sam/java/src/net/i2p/sam/client/SAMReader.java index 0ab88cfcee..7153998e94 100644 --- a/apps/sam/java/src/net/i2p/sam/client/SAMReader.java +++ b/apps/sam/java/src/net/i2p/sam/client/SAMReader.java @@ -137,6 +137,10 @@ public class SAMReader { if ( (eq > 0) && (eq < pair.length() - 1) ) { String name = pair.substring(0, eq); String val = pair.substring(eq+1); + if (val.length() <= 0) { + _log.error("Empty value for " + name); + continue; + } while ( (val.charAt(0) == '\"') && (val.length() > 0) ) val = val.substring(1); while ( (val.length() > 0) && (val.charAt(val.length()-1) == '\"') ) diff --git a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java index a0d5d15607..4314965414 100644 --- a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java +++ b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java @@ -702,8 +702,7 @@ public class SAMStreamSink { samOut.flush(); if (_log.shouldLog(Log.DEBUG)) _log.debug("SESSION " + command + " sent"); - if (mode == STREAM) { - // why only waiting in stream mode? + //if (mode == STREAM) { boolean ok; if (masterMode) ok = eventHandler.waitForSessionAddReply(); @@ -713,6 +712,22 @@ public class SAMStreamSink { throw new IOException("SESSION " + command + " failed"); if (_log.shouldLog(Log.DEBUG)) _log.debug("SESSION " + command + " reply found: " + ok); + //} + if (masterMode) { + // do a bunch more + req = "SESSION ADD STYLE=STREAM FROM_PORT=99 ID=stream99\n"; + samOut.write(req.getBytes("UTF-8")); + req = "SESSION ADD STYLE=STREAM FROM_PORT=98 ID=stream98\n"; + samOut.write(req.getBytes("UTF-8")); + req = "SESSION ADD STYLE=DATAGRAM PORT=9997 LISTEN_PORT=97 ID=dg97\n"; + samOut.write(req.getBytes("UTF-8")); + req = "SESSION ADD STYLE=DATAGRAM PORT=9996 FROM_PORT=96 ID=dg96\n"; + samOut.write(req.getBytes("UTF-8")); + req = "SESSION ADD STYLE=RAW PORT=9995 LISTEN_PORT=95 ID=raw95\n"; + samOut.write(req.getBytes("UTF-8")); + req = "SESSION ADD STYLE=RAW PORT=9994 FROM_PORT=94 LISTEN_PROTOCOL=222 ID=raw94\n"; + samOut.write(req.getBytes("UTF-8")); + samOut.flush(); } req = "NAMING LOOKUP NAME=ME\n"; samOut.write(req.getBytes("UTF-8")); -- GitLab