diff --git a/apps/sam/java/src/net/i2p/sam/SAMBridge.java b/apps/sam/java/src/net/i2p/sam/SAMBridge.java index 8d38f4f579be8216e1c1f9bda4630cb00dfb4a87..018655d8b8a0e92763cf2f63a85dfd72d4b6a468 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMBridge.java +++ b/apps/sam/java/src/net/i2p/sam/SAMBridge.java @@ -13,6 +13,14 @@ import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.Properties; +import java.util.Map; +import java.util.HashMap; +import java.util.Collections; + +import net.i2p.data.Destination; +import net.i2p.data.DataFormatException; +import net.i2p.data.PrivateKey; +import net.i2p.data.SigningPrivateKey; import net.i2p.util.I2PThread; import net.i2p.util.Log; @@ -27,11 +35,16 @@ public class SAMBridge implements Runnable { private final static Log _log = new Log(SAMBridge.class); private ServerSocket serverSocket; private Properties i2cpProps; + /** + * app designated destination name to the base64 of the I2P formatted + * destination keys (Destination+PrivateKey+SigningPrivateKey) + */ + private Map nameToPrivKeys = Collections.synchronizedMap(new HashMap(8)); private boolean acceptConnections = true; private final static int SAM_LISTENPORT = 7656; - + private SAMBridge() {} /** @@ -63,6 +76,46 @@ public class SAMBridge implements Runnable { this.i2cpProps = i2cpProps; } + /** + * Retrieve the destination associated with the given name + * + * @return null if the name does not exist, or if it is improperly formatted + */ + public Destination getDestination(String name) { + String val = (String)nameToPrivKeys.get(name); + if (val == null) return null; + try { + Destination d = new Destination(); + d.fromBase64(val); + return d; + } catch (DataFormatException dfe) { + _log.error("Error retrieving the destination from " + name, dfe); + nameToPrivKeys.remove(name); + return null; + } + } + + /** + * Retrieve the I2P private keystream for the given name, formatted + * as a base64 string (Destination+PrivateKey+SessionPrivateKey, as I2CP + * stores it). + * + * @return null if the name does not exist, else the stream + */ + public String getKeystream(String name) { + String val = (String)nameToPrivKeys.get(name); + if (val == null) return null; + return val; + } + + /** + * Specify that the given keystream should be used for the given name + * + */ + public void addKeystream(String name, String stream) { + nameToPrivKeys.put(name, stream); + } + /** * Usage: * <pre>SAMBridge [[listenHost ]listenPort[ name=val]*]</pre> @@ -140,10 +193,18 @@ public class SAMBridge implements Runnable { } catch (IOException e) {} continue; } + handler.setBridge(this); handler.startHandling(); } catch (SAMException e) { if (_log.shouldLog(Log.ERROR)) _log.error("SAM error: " + e.getMessage(), e); + try { + String reply = "HELLO REPLY RESULT=I2P_ERROR MESSAGE=\"" + e.getMessage() + "\"\n"; + s.getOutputStream().write(reply.getBytes("ISO-8859-1")); + } catch (IOException ioe) { + if (_log.shouldLog(Log.ERROR)) + _log.error("SAM Error sending error reply", ioe); + } s.close(); } } diff --git a/apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java b/apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java index 3eb9492cc904d6d934b987d46cff3be9db009799..757f137f9e840058c20639edd601e8a5f014f2b6 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java +++ b/apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java @@ -30,6 +30,7 @@ import net.i2p.util.Log; public class SAMDatagramSession extends SAMMessageSession { private final static Log _log = new Log(SAMDatagramSession.class); + public static int DGRAM_SIZE_MAX = 31*1024; private SAMDatagramReceiver recv = null; @@ -43,7 +44,8 @@ public class SAMDatagramSession extends SAMMessageSession { * @param recv Object that will receive incoming data */ public SAMDatagramSession(String dest, Properties props, - SAMDatagramReceiver recv) throws IOException, DataFormatException, I2PSessionException { + SAMDatagramReceiver recv) throws IOException, + DataFormatException, I2PSessionException { super(dest, props); this.recv = recv; @@ -58,7 +60,8 @@ public class SAMDatagramSession extends SAMMessageSession { * @param recv Object that will receive incoming data */ public SAMDatagramSession(InputStream destStream, Properties props, - SAMDatagramReceiver recv) throws IOException, DataFormatException, I2PSessionException { + SAMDatagramReceiver recv) throws IOException, + DataFormatException, I2PSessionException { super(destStream, props); this.recv = recv; @@ -73,6 +76,9 @@ public class SAMDatagramSession extends SAMMessageSession { * @return True if the data was sent, false otherwise */ public boolean sendBytes(String dest, byte[] data) throws DataFormatException { + if (data.length > DGRAM_SIZE_MAX) + throw new DataFormatException("Datagram size exceeded (" + data.length + ")"); + byte[] dgram = dgramMaker.makeI2PDatagram(data); return sendBytesThroughMessageSession(dest, dgram); diff --git a/apps/sam/java/src/net/i2p/sam/SAMHandler.java b/apps/sam/java/src/net/i2p/sam/SAMHandler.java index f1084316c8f973ea0b7442dd656225223b191a71..bba48361a7fc1651fd068d9319325d1b2a43ca6c 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMHandler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMHandler.java @@ -30,6 +30,7 @@ public abstract class SAMHandler implements Runnable { private final static Log _log = new Log(SAMHandler.class); protected I2PThread thread = null; + protected SAMBridge bridge = null; private Object socketWLock = new Object(); // Guards writings on socket private Socket socket = null; @@ -71,6 +72,8 @@ public abstract class SAMHandler implements Runnable { thread.start(); } + public void setBridge(SAMBridge bridge) { this.bridge = bridge; } + /** * Actually handle the SAM protocol. * @@ -124,7 +127,9 @@ public abstract class SAMHandler implements Runnable { * */ protected final void closeClientSocket() throws IOException { - socket.close(); + if (socket != null) + socket.close(); + socket = null; } /** diff --git a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java index 6bb6f6d8642d170a852a849eff385e168c4dbfcc..8adb573fd3a27621a9182dca52c065275e4dde59 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java +++ b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java @@ -32,8 +32,8 @@ public class SAMHandlerFactory { * * @param s Socket attached to SAM client * @param i2cpProps config options for our i2cp connection - * - * @return A SAM protocol handler + * @throws SAMException if the connection handshake (HELLO message) was malformed + * @return A SAM protocol handler, or null if the client closed before the handshake */ public static SAMHandler createSAMHandler(Socket s, Properties i2cpProps) throws SAMException { BufferedReader br; @@ -66,8 +66,8 @@ public class SAMHandlerFactory { { String opcode; if (!(opcode = tok.nextToken()).equals("VERSION")) { - throw new SAMException("Unrecognized HELLO message opcode: \"" - + opcode + "\""); + throw new SAMException("Unrecognized HELLO message opcode: '" + + opcode + "'"); } } @@ -88,22 +88,8 @@ public class SAMHandlerFactory { } String ver = chooseBestVersion(minVer, maxVer); - if (ver == null) { - // Let's answer negatively - try { - OutputStream out = s.getOutputStream(); - out.write("HELLO REPLY RESULT=NOVERSION\n".getBytes("ISO-8859-1")); - return null; - } catch (UnsupportedEncodingException e) { - _log.error("Caught UnsupportedEncodingException (" - + e.getMessage() + ")"); - throw new SAMException("Character encoding error: " - + e.getMessage()); - } catch (IOException e) { - throw new SAMException("Error reading from socket: " - + e.getMessage()); - } - } + if (ver == null) + throw new SAMException("No version specified"); // Let's answer positively try { @@ -135,8 +121,8 @@ public class SAMHandlerFactory { throw new SAMException("BUG! (in handler instantiation)"); } } catch (IOException e) { - _log.error("IOException caught during SAM handler instantiation"); - return null; + _log.error("Error creating the v1 handler", e); + throw new SAMException("IOException caught during SAM handler instantiation"); } return handler; } diff --git a/apps/sam/java/src/net/i2p/sam/SAMRawSession.java b/apps/sam/java/src/net/i2p/sam/SAMRawSession.java index 13b4785c00cca2d028ecee577f6a78e5cbc53db0..33dbe37963ceebb6a4d3453ef55825e44f50ad19 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMRawSession.java +++ b/apps/sam/java/src/net/i2p/sam/SAMRawSession.java @@ -26,6 +26,7 @@ import net.i2p.util.Log; public class SAMRawSession extends SAMMessageSession { private final static Log _log = new Log(SAMRawSession.class); + public static final int RAW_SIZE_MAX = 32*1024; private SAMRawReceiver recv = null; /** @@ -64,6 +65,8 @@ public class SAMRawSession extends SAMMessageSession { * @return True if the data was sent, false otherwise */ public boolean sendBytes(String dest, byte[] data) throws DataFormatException { + if (data.length > RAW_SIZE_MAX) + throw new DataFormatException("Data size limit exceeded (" + data.length + ")"); return sendBytesThroughMessageSession(dest, data); } diff --git a/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java b/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java index f845b843354c07957debfe9bee45b89a2b1ab2c9..d3151a096b8b898813d58d0bbbd0a97cfd302f99 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java +++ b/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java @@ -101,7 +101,6 @@ public class SAMStreamSession { allprops.putAll(System.getProperties()); allprops.putAll(props); - // FIXME: we should setup I2CP host and port, too String i2cpHost = allprops.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1"); int i2cpPort = 7654; String port = allprops.getProperty(I2PClient.PROP_TCP_PORT, "7654"); @@ -113,6 +112,7 @@ public class SAMStreamSession { // streams MUST be mode=guaranteed (though i think the socket manager // enforces this anyway... allprops.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED); + _log.debug("Creating I2PSocketManager..."); socketMgr = I2PSocketManagerFactory.createManager(destStream, i2cpHost, diff --git a/apps/sam/java/src/net/i2p/sam/SAMUtils.java b/apps/sam/java/src/net/i2p/sam/SAMUtils.java index 09dce27f3d3dd9aaa06045cba63b893b5a81201c..0ae440764160b8026828133ea1c30c35dce1b3cd 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMUtils.java +++ b/apps/sam/java/src/net/i2p/sam/SAMUtils.java @@ -33,7 +33,6 @@ import net.i2p.I2PAppContext; public class SAMUtils { private final static Log _log = new Log(SAMUtils.class); - private static I2PAppContext _context = new I2PAppContext(); /** * Generate a random destination key @@ -86,7 +85,7 @@ public class SAMUtils { * @return the Destination for the specified hostname, or null if not found */ public static Destination lookupHost(String name, OutputStream pubKey) { - NamingService ns = _context.namingService(); + NamingService ns = I2PAppContext.getGlobalContext().namingService(); Destination dest = ns.lookup(name); if ((pubKey != null) && (dest != null)) { @@ -144,13 +143,13 @@ public class SAMUtils { /* Dump a Properties object in an human-readable form */ private static String dumpProperties(Properties props) { - Enumeration enum = props.propertyNames(); + Enumeration names = props.propertyNames(); String msg = ""; String key, val; boolean firstIter = true; - while (enum.hasMoreElements()) { - key = (String)enum.nextElement(); + while (names.hasMoreElements()) { + key = (String)names.nextElement(); val = props.getProperty(key); if (!firstIter) { diff --git a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java index d4fd7350b025f6b438b30158b5b3f5ee267ea420..b9eea3d353c340a9bb58514ab23a65eda6e84016 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java @@ -154,10 +154,10 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag } } catch (UnsupportedEncodingException e) { _log.error("Caught UnsupportedEncodingException (" - + e.getMessage() + ")"); + + e.getMessage() + ")", e); } catch (IOException e) { _log.debug("Caught IOException (" - + e.getMessage() + ")"); + + e.getMessage() + ")", e); } catch (Exception e) { _log.error("Unexpected exception", e); } finally { @@ -189,32 +189,47 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag if ((rawSession != null) || (datagramSession != null) || (streamSession != null)) { _log.debug("Trying to create a session, but one still exists"); - return false; + 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 false; + 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 false; + 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(); + ByteArrayOutputStream priv = new ByteArrayOutputStream(640); SAMUtils.genRandomKey(priv, null); - dest = Base64.encode(priv.toByteArray()); + 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 isnt know, 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) { _log.debug("SESSION STYLE parameter not specified"); - return false; + return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No SESSION STYLE specified\"\n"); } props.remove("STYLE"); @@ -231,34 +246,34 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag if (!dir.equals("CREATE") && !dir.equals("RECEIVE") && !dir.equals("BOTH")) { _log.debug("Unknow DIRECTION parameter value: [" + dir + "]"); - return false; + return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unknown DIRECTION parameter\"\n"); } props.remove("DIRECTION"); - streamSession = new SAMStreamSession(dest, dir,props,this); + streamSession = new SAMStreamSession(destKeystream, dir,props,this); } else { _log.debug("Unrecognized SESSION STYLE: \"" + style +"\""); - return false; + return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized SESSION STYLE\"\n"); } return writeString("SESSION STATUS RESULT=OK DESTINATION=" + dest + "\n"); } else { _log.debug("Unrecognized SESSION message opcode: \"" + opcode + "\""); - return false; + 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 + "\n"); + 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 + "\n"); + 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 + "\n"); + 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 + "\n"); + return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n"); } } @@ -483,158 +498,170 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag } if (opcode.equals("SEND")) { - if (props == null) { - _log.debug("No parameters specified in STREAM SEND message"); + return execStreamSend(props); + } else if (opcode.equals("CONNECT")) { + return execStreamConnect(props); + } else if (opcode.equals("CLOSE")) { + return execStreamClose(props); + } else { + _log.debug("Unrecognized RAW message opcode: \"" + + opcode + "\""); + return false; + } + } + + private boolean execStreamSend(Properties props) { + if (props == null) { + _log.debug("No parameters specified in STREAM SEND message"); + return false; + } + + int id; + { + String strid = props.getProperty("ID"); + if (strid == null) { + _log.debug("ID not specified in STREAM SEND message"); return false; } - - int id; - { - String strid = props.getProperty("ID"); - if (strid == null) { - _log.debug("ID not specified in STREAM SEND message"); - return false; - } - try { - id = Integer.parseInt(strid); - } catch (NumberFormatException e) { - _log.debug("Invalid STREAM SEND ID specified: " + strid); - return false; - } + try { + id = Integer.parseInt(strid); + } catch (NumberFormatException e) { + _log.debug("Invalid STREAM SEND ID specified: " + strid); + return false; } + } - int size; - { - String strsize = props.getProperty("SIZE"); - if (strsize == null) { - _log.debug("Size not specified in STREAM SEND message"); - return false; - } - try { - size = Integer.parseInt(strsize); - } catch (NumberFormatException e) { - _log.debug("Invalid STREAM SEND size specified: "+strsize); - return false; - } - if (!checkSize(size)) { - _log.debug("Specified size (" + size - + ") is out of protocol limits"); - return false; - } + int size; + { + String strsize = props.getProperty("SIZE"); + if (strsize == null) { + _log.debug("Size not specified in STREAM SEND message"); + return false; } - try { - DataInputStream in = new DataInputStream(getClientSocketInputStream()); - byte[] data = new byte[size]; + size = Integer.parseInt(strsize); + } catch (NumberFormatException e) { + _log.debug("Invalid STREAM SEND size specified: "+strsize); + return false; + } + if (!checkSize(size)) { + _log.debug("Specified size (" + size + + ") is out of protocol limits"); + return false; + } + } - in.readFully(data); + try { + DataInputStream in = new DataInputStream(getClientSocketInputStream()); + byte[] data = new byte[size]; - if (!streamSession.sendBytes(id, data)) { - _log.error("STREAM SEND failed"); - return false; - } + in.readFully(data); - return true; - } catch (EOFException e) { - _log.debug("Too few bytes with RAW SEND message (expected: " - + size); + if (!streamSession.sendBytes(id, data)) { + _log.error("STREAM SEND failed"); return false; - } catch (IOException e) { - _log.debug("Caught IOException while parsing RAW SEND message", - e); + } + + return true; + } catch (EOFException e) { + _log.debug("Too few bytes with RAW SEND message (expected: " + + size); + return false; + } catch (IOException e) { + _log.debug("Caught IOException while parsing RAW SEND message", + e); + return false; + } + } + + private boolean execStreamConnect(Properties props) { + if (props == null) { + _log.debug("No parameters specified in STREAM CONNECT message"); + return false; + } + + int id; + { + String strid = props.getProperty("ID"); + if (strid == null) { + _log.debug("ID not specified in STREAM SEND message"); return false; } - } else if (opcode.equals("CONNECT")) { - if (props == null) { - _log.debug("No parameters specified in STREAM CONNECT message"); + try { + id = Integer.parseInt(strid); + } catch (NumberFormatException e) { + _log.debug("Invalid STREAM CONNECT ID specified: " +strid); return false; } - - int id; - { - String strid = props.getProperty("ID"); - if (strid == null) { - _log.debug("ID not specified in STREAM SEND message"); - return false; - } - try { - id = Integer.parseInt(strid); - } catch (NumberFormatException e) { - _log.debug("Invalid STREAM CONNECT ID specified: " +strid); - return false; - } - if (id < 1) { - _log.debug("Invalid STREAM CONNECT ID specified: " +strid); - return false; - } - props.remove("ID"); + if (id < 1) { + _log.debug("Invalid STREAM CONNECT ID specified: " +strid); + return false; } + props.remove("ID"); + } - String dest = props.getProperty("DESTINATION"); - if (dest == null) { - _log.debug("Destination not specified in RAW SEND message"); + String dest = props.getProperty("DESTINATION"); + if (dest == null) { + _log.debug("Destination not specified in RAW SEND message"); + return false; + } + props.remove("DESTINATION"); + + try { + if (!streamSession.connect(id, dest, props)) { + _log.debug("STREAM connection failed"); return false; } - props.remove("DESTINATION"); + return writeString("STREAM STATUS RESULT=OK ID=" + id + "\n"); + } catch (DataFormatException e) { + _log.debug("Invalid destination in STREAM CONNECT message"); + return writeString("STREAM STATUS RESULT=INVALID_KEY ID=" + + id + "\n"); + } catch (SAMInvalidDirectionException e) { + _log.debug("STREAM CONNECT failed: " + e.getMessage()); + return writeString("STREAM STATUS RESULT=INVALID_DIRECTION ID=" + + id + "\n"); + } catch (ConnectException e) { + _log.debug("STREAM CONNECT failed: " + e.getMessage()); + return writeString("STREAM STATUS RESULT=CONNECTION_REFUSED ID=" + + id + "\n"); + } catch (NoRouteToHostException e) { + _log.debug("STREAM CONNECT failed: " + e.getMessage()); + return writeString("STREAM STATUS RESULT=CANT_REACH_PEER ID=" + + id + "\n"); + } catch (InterruptedIOException e) { + _log.debug("STREAM CONNECT failed: " + e.getMessage()); + return writeString("STREAM STATUS RESULT=TIMEOUT ID=" + + id + "\n"); + } catch (I2PException e) { + _log.debug("STREAM CONNECT failed: " + e.getMessage()); + return writeString("STREAM STATUS RESULT=I2P_ERROR ID=" + + id + "\n"); + } + } + + private boolean execStreamClose(Properties props) { + if (props == null) { + _log.debug("No parameters specified in STREAM CLOSE message"); + return false; + } - try { - if (!streamSession.connect(id, dest, props)) { - _log.debug("STREAM connection failed"); - return false; - } - return writeString("STREAM STATUS RESULT=OK ID=" + id + "\n"); - } catch (DataFormatException e) { - _log.debug("Invalid destination in STREAM CONNECT message"); - return writeString("STREAM STATUS RESULT=INVALID_KEY ID=" - + id + "\n"); - } catch (SAMInvalidDirectionException e) { - _log.debug("STREAM CONNECT failed: " + e.getMessage()); - return writeString("STREAM STATUS RESULT=INVALID_DIRECTION ID=" - + id + "\n"); - } catch (ConnectException e) { - _log.debug("STREAM CONNECT failed: " + e.getMessage()); - return writeString("STREAM STATUS RESULT=CONNECTION_REFUSED ID=" - + id + "\n"); - } catch (NoRouteToHostException e) { - _log.debug("STREAM CONNECT failed: " + e.getMessage()); - return writeString("STREAM STATUS RESULT=CANT_REACH_PEER ID=" - + id + "\n"); - } catch (InterruptedIOException e) { - _log.debug("STREAM CONNECT failed: " + e.getMessage()); - return writeString("STREAM STATUS RESULT=TIMEOUT ID=" - + id + "\n"); - } catch (I2PException e) { - _log.debug("STREAM CONNECT failed: " + e.getMessage()); - return writeString("STREAM STATUS RESULT=I2P_ERROR ID=" - + id + "\n"); - } - } else if (opcode.equals("CLOSE")) { - if (props == null) { - _log.debug("No parameters specified in STREAM CLOSE message"); + int id; + { + String strid = props.getProperty("ID"); + if (strid == null) { + _log.debug("ID not specified in STREAM CLOSE message"); return false; } - - int id; - { - String strid = props.getProperty("ID"); - if (strid == null) { - _log.debug("ID not specified in STREAM CLOSE message"); - return false; - } - try { - id = Integer.parseInt(strid); - } catch (NumberFormatException e) { - _log.debug("Invalid STREAM CLOSE ID specified: " +strid); - return false; - } + try { + id = Integer.parseInt(strid); + } catch (NumberFormatException e) { + _log.debug("Invalid STREAM CLOSE ID specified: " +strid); + return false; } - - return streamSession.closeConnection(id); - } else { - _log.debug("Unrecognized RAW message opcode: \"" - + opcode + "\""); - return false; } + + return streamSession.closeConnection(id); } /* Check whether a size is inside the limits allowed by this protocol */