/* Parse and execute a SESSION message */ protected boolean execSessionMessage(String opcode, Properties props) { String dest = "BUG!"; try { if (opcode.equals("CREATE")) { if ((getRawSession() != null) || (getDatagramSession() != null) || (getStreamSession() != null)) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Trying to create a session, but one still exists"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Session already exists\"\n"); } if (props.isEmpty()) { if (_log.shouldLog(Log.DEBUG)) _log.debug("No parameters specified in SESSION CREATE message"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No parameters for SESSION CREATE\"\n"); } dest = props.getProperty("DESTINATION"); if (dest == null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("SESSION DESTINATION parameter not specified"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"DESTINATION not specified\"\n"); } props.remove("DESTINATION"); String destKeystream = null; if (dest.equals("TRANSIENT")) { _log.debug("TRANSIENT destination requested"); ByteArrayOutputStream priv = new ByteArrayOutputStream(640); SAMUtils.genRandomKey(priv, null); destKeystream = Base64.encode(priv.toByteArray()); } else { destKeystream = bridge.getKeystream(dest); if (destKeystream == null) { if (_log.shouldLog(Log.DEBUG)) _log.debug( "Custom destination specified [" + dest + "] but it isn't known, creating a new one"); ByteArrayOutputStream baos = new ByteArrayOutputStream(640); SAMUtils.genRandomKey(baos, null); destKeystream = Base64.encode(baos.toByteArray()); bridge.addKeystream(dest, destKeystream); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Custom destination specified [" + dest + "] and it is already known"); } } String style = props.getProperty("STYLE"); if (style == null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("SESSION STYLE parameter not specified"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No SESSION STYLE specified\"\n"); } props.remove("STYLE"); // Unconditionally override what the client may have set // (iMule sets BestEffort) as None is more efficient // and the client has no way to access delivery notifications props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_NONE); if (style.equals("RAW")) { rawSession = new SAMRawSession(destKeystream, props, this); } else if (style.equals("DATAGRAM")) { datagramSession = new SAMDatagramSession(destKeystream, props, this); } else if (style.equals("STREAM")) { String dir = props.getProperty("DIRECTION"); if (dir == null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("No DIRECTION parameter in STREAM session, defaulting to BOTH"); dir = "BOTH"; } else if (!dir.equals("CREATE") && !dir.equals("RECEIVE") && !dir.equals("BOTH")) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Unknown DIRECTION parameter value: [" + dir + "]"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unknown DIRECTION parameter\"\n"); } else { props.remove("DIRECTION"); } streamSession = newSAMStreamSession(destKeystream, dir, props); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Unrecognized SESSION STYLE: \"" + style + "\""); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized SESSION STYLE\"\n"); } return writeString("SESSION STATUS RESULT=OK DESTINATION=" + dest + "\n"); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Unrecognized SESSION message opcode: \"" + opcode + "\""); return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized opcode\"\n"); } } catch (DataFormatException e) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Invalid destination specified"); return writeString( "SESSION STATUS RESULT=INVALID_KEY DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } catch (I2PSessionException e) { if (_log.shouldLog(Log.DEBUG)) _log.debug("I2P error when instantiating session", e); return writeString( "SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } catch (SAMException e) { _log.error("Unexpected SAM error", e); return writeString( "SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } catch (IOException e) { _log.error("Unexpected IOException", e); return writeString( "SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } }
/* Parse and execute a SESSION message */ @Override protected boolean execSessionMessage(String opcode, Properties props) { String dest = "BUG!"; String nick = null; boolean ok = false; try { if (opcode.equals("CREATE")) { if ((this.getRawSession() != null) || (this.getDatagramSession() != null) || (this.getStreamSession() != null)) { _log.debug("Trying to create a session, but one still exists"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Session already exists\"\n"); } if (props == null) { _log.debug("No parameters specified in SESSION CREATE message"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No parameters for SESSION CREATE\"\n"); } dest = props.getProperty("DESTINATION"); if (dest == null) { _log.debug("SESSION DESTINATION parameter not specified"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"DESTINATION not specified\"\n"); } props.remove("DESTINATION"); if (dest.equals("TRANSIENT")) { _log.debug("TRANSIENT destination requested"); ByteArrayOutputStream priv = new ByteArrayOutputStream(640); SAMUtils.genRandomKey(priv, null); dest = Base64.encode(priv.toByteArray()); } else { _log.debug("Custom destination specified [" + dest + "]"); } try { SAMUtils.checkPrivateDestination(dest); } catch (SAMUtils.InvalidDestination e) { return writeString("SESSION STATUS RESULT=INVALID_KEY\n"); } nick = props.getProperty("ID"); if (nick == null) { _log.debug("SESSION ID parameter not specified"); return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"ID not specified\"\n"); } props.remove("ID"); String style = props.getProperty("STYLE"); if (style == null) { _log.debug("SESSION STYLE parameter not specified"); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No SESSION STYLE specified\"\n"); } props.remove("STYLE"); // Unconditionally override what the client may have set // (iMule sets BestEffort) as None is more efficient // and the client has no way to access delivery notifications i2cpProps.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_NONE); // Record the session in the database sSessionsHash Properties allProps = new Properties(); allProps.putAll(i2cpProps); allProps.putAll(props); try { sSessionsHash.put(nick, new SessionRecord(dest, allProps, this)); } catch (SessionsDB.ExistingId e) { _log.debug("SESSION ID parameter already in use"); return writeString("SESSION STATUS RESULT=DUPLICATED_ID\n"); } catch (SessionsDB.ExistingDest e) { return writeString("SESSION STATUS RESULT=DUPLICATED_DEST\n"); } // Create the session if (style.equals("RAW")) { DatagramServer.getInstance(i2cpProps); rawSession = newSAMRawSession(nick); this.session = rawSession; } else if (style.equals("DATAGRAM")) { DatagramServer.getInstance(i2cpProps); datagramSession = newSAMDatagramSession(nick); this.session = datagramSession; } else if (style.equals("STREAM")) { streamSession = newSAMStreamSession(nick); this.session = streamSession; } else { _log.debug("Unrecognized SESSION STYLE: \"" + style + "\""); return writeString( "SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized SESSION STYLE\"\n"); } ok = true; return writeString("SESSION STATUS RESULT=OK DESTINATION=" + dest + "\n"); } else { _log.debug("Unrecognized SESSION message opcode: \"" + opcode + "\""); return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized opcode\"\n"); } } catch (DataFormatException e) { _log.debug("Invalid destination specified"); return writeString( "SESSION STATUS RESULT=INVALID_KEY DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } catch (I2PSessionException e) { _log.debug("I2P error when instantiating session", e); return writeString( "SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } catch (SAMException e) { _log.info("Funny SAM error", e); return writeString( "SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } catch (IOException e) { _log.error("Unexpected IOException", e); return writeString( "SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } finally { // unregister the session if it has not been created if (!ok && nick != null) { sSessionsHash.del(nick); session = null; } } }