SAMv3 : protocol better specified, and small changes in the code reflecting the new protocol

This commit is contained in:
mkvore-commit
2009-04-05 21:32:43 +00:00
parent 2cf5221620
commit 6b825fbe25
11 changed files with 180 additions and 121 deletions

View File

@ -23,7 +23,7 @@ sess = socket.socket(
sess.connect(("127.0.0.1",7656)); sess.connect(("127.0.0.1",7656));
sess.send("HELLO VERSION MIN=3.0 MAX=3.0\n") sess.send("HELLO VERSION MIN=3.0 MAX=3.0\n")
sys.stdout.write(sess.recv(1000)) sys.stdout.write(sess.recv(1000))
sess.send("SESSION CREATE STYLE=DATAGRAM PORT="+str(port)+" ID="+name+" DESTINATION=EYUpJFeW9tiubXR0aOjvCJ~ndj3xN0Wn-ljuGdbpOEttPg7nj0VCTOQDJ~FAolzn9FIDdmR3VjM0OFFDT46Q5HN4vShXFE2VNC8e3~GjzxJfaJhijRC2R9oIOzsNlzKtInD2o9lh0PxPioNMCigwmgWuqlQHs4tjWeaYRAtooHxbrtuoCIhIdGfyVV-nAcPiyYbouKq3leETXE~4kBXm-LfWfyPtrv6OuDk3GBVVcthv19GYBmnl2YI8HpJjc-G-TvNkgYishjzIJyEW-Xrpy43R4ZBXlyQqnheGLlbOEY8NLDbyNHLRMMOGbcr~67SVE3Iw3RqQ3Dhrkq2FCaQwcDucfIUCCbOfCZgu0hlnCkS42xsUvegQeiwMxbdI~h9v7vcR3yFFOrHX6WQvIZSbFLKNGArGJcfmOJVLqw1wTC4AgYXjk3csVDPd-QWbMXOuodyBgrg27Ds2BBYTsVXWskoo6ASsMIQZ6jMfL7PkY9dPLCRParIyzb9aPmf~MntNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHNqwgkhJnBW4ymaRsdVmITAha-ff0UiALfKSlznqp5HcSewgMHbzQ0I01TQytFnW\n") sess.send("SESSION CREATE STYLE=DATAGRAM PORT="+str(port)+" ID="+name+" DESTINATION=EYUpJFeW9tiubXR0aOjvCJ~ndj3xN0Wn-ljuGdbpOEttPg7nj0VCTOQDJ~FAolzn9FIDdmR3VjM0OFFDT46Q5HN4vShXFE2VNC8e3~GjzxJfaJhijRC2R9oIOzsNlzKtInD2o9lh0PxPioNMCigwmgWuqlQHs4tjWeaYRAtooHxbrtuoCIhIdGfyVV-nAcPiyYbouKq3leETXE~4kBXm-LfWfyPtrv6OuDk3GBVVcthv19GYBmnl2YI8HpJjc-G-TvNkgYishjzIJyEW-Xrpy43R4ZBXlyQqnheGLlbOEY8NLDbyNHLRMMOGbcr~67SVE3Iw3RqQ3Dhrkq2FCaQwcDucfIUCCbOfCZgu0hlnCkS42xsUvegQeiwMxbdI~h9v7vcR3yFFOrHX6WQvIZSbFLKNGArGJcfmOJVLqw1wTC4AgYXjk3csVDPd-QWbMXOuodyBgrg27Ds2BBYTsVXWskoo6ASsMIQZ6jMfL7PkY9dPLCRParIyzb9aPmf~MntNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHNqwgkhJnBW4ymaRsdVmITAha-ff0UiALfKSlznqp5HcSewgMHbzQ0I01TQytFnW outbound.nickname="+name+" inbound.nickname="+name+" outbound.length=0\n")
sys.stdout.write(sess.recv(10000)) sys.stdout.write(sess.recv(10000))
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

View File

@ -26,6 +26,6 @@ port = 7655
host = "localhost" host = "localhost"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", 0)) s.bind(("", 0))
s.sendto(name+" tYhjbFlFL38WFuO5eCzTvE0UBr4RfaqWMKlekGeMoB-Ouz7nYaWfiS-9j3jMiZT7FH~pwdmoSREOs2ZbXK84sR59P~pPfeCMxnJrk57f3U9uKzXkesjkKWYco3YAGs-G8sw8Fu2FBx0Do57yBdA9~j8Zq6pMjmgPBXCLuXG3vo0Z8zUWCjApJyFY6OXYopHck9Fz9vKy7YhC6zXFHfEuNHVkAooduiLd~aCoGij0TW3lH2rTVU-lx-DUdi6edxQ5-RvDNkXfikvytoCpRkivbNVytjCJLk~7RNU4FpBD20wTZWNJmEG3OY3cjNjawJVFdNjtgczh9K7gZ7ad-NjVjZVhXEj1lU8mk~vAH-2QE5om8dstWUwWoNDwmVDlvIJNKzQmahG~VrpFexFHXO0n3fKIXcSgWGOHDExM8w9neCt7AxUjxPDtXXuYNW~bRwcfiL-C9~z4K9rmwiTPZX0lmsToSXTF28l7WAoj~TMT9kZAjQeFRRWU5oW5oxVuonVvAAAA\n"+message, (host, port)) s.sendto("3.0 "+name+" tYhjbFlFL38WFuO5eCzTvE0UBr4RfaqWMKlekGeMoB-Ouz7nYaWfiS-9j3jMiZT7FH~pwdmoSREOs2ZbXK84sR59P~pPfeCMxnJrk57f3U9uKzXkesjkKWYco3YAGs-G8sw8Fu2FBx0Do57yBdA9~j8Zq6pMjmgPBXCLuXG3vo0Z8zUWCjApJyFY6OXYopHck9Fz9vKy7YhC6zXFHfEuNHVkAooduiLd~aCoGij0TW3lH2rTVU-lx-DUdi6edxQ5-RvDNkXfikvytoCpRkivbNVytjCJLk~7RNU4FpBD20wTZWNJmEG3OY3cjNjawJVFdNjtgczh9K7gZ7ad-NjVjZVhXEj1lU8mk~vAH-2QE5om8dstWUwWoNDwmVDlvIJNKzQmahG~VrpFexFHXO0n3fKIXcSgWGOHDExM8w9neCt7AxUjxPDtXXuYNW~bRwcfiL-C9~z4K9rmwiTPZX0lmsToSXTF28l7WAoj~TMT9kZAjQeFRRWU5oW5oxVuonVvAAAA\n"+message, (host, port))
s.sendto(name+" EYUpJFeW9tiubXR0aOjvCJ~ndj3xN0Wn-ljuGdbpOEttPg7nj0VCTOQDJ~FAolzn9FIDdmR3VjM0OFFDT46Q5HN4vShXFE2VNC8e3~GjzxJfaJhijRC2R9oIOzsNlzKtInD2o9lh0PxPioNMCigwmgWuqlQHs4tjWeaYRAtooHxbrtuoCIhIdGfyVV-nAcPiyYbouKq3leETXE~4kBXm-LfWfyPtrv6OuDk3GBVVcthv19GYBmnl2YI8HpJjc-G-TvNkgYishjzIJyEW-Xrpy43R4ZBXlyQqnheGLlbOEY8NLDbyNHLRMMOGbcr~67SVE3Iw3RqQ3Dhrkq2FCaQwcDucfIUCCbOfCZgu0hlnCkS42xsUvegQeiwMxbdI~h9v7vcR3yFFOrHX6WQvIZSbFLKNGArGJcfmOJVLqw1wTC4AgYXjk3csVDPd-QWbMXOuodyBgrg27Ds2BBYTsVXWskoo6ASsMIQZ6jMfL7PkY9dPLCRParIyzb9aPmf~MntNAAAA\n"+message, (host, port)) s.sendto("3.0 "+name+" EYUpJFeW9tiubXR0aOjvCJ~ndj3xN0Wn-ljuGdbpOEttPg7nj0VCTOQDJ~FAolzn9FIDdmR3VjM0OFFDT46Q5HN4vShXFE2VNC8e3~GjzxJfaJhijRC2R9oIOzsNlzKtInD2o9lh0PxPioNMCigwmgWuqlQHs4tjWeaYRAtooHxbrtuoCIhIdGfyVV-nAcPiyYbouKq3leETXE~4kBXm-LfWfyPtrv6OuDk3GBVVcthv19GYBmnl2YI8HpJjc-G-TvNkgYishjzIJyEW-Xrpy43R4ZBXlyQqnheGLlbOEY8NLDbyNHLRMMOGbcr~67SVE3Iw3RqQ3Dhrkq2FCaQwcDucfIUCCbOfCZgu0hlnCkS42xsUvegQeiwMxbdI~h9v7vcR3yFFOrHX6WQvIZSbFLKNGArGJcfmOJVLqw1wTC4AgYXjk3csVDPd-QWbMXOuodyBgrg27Ds2BBYTsVXWskoo6ASsMIQZ6jMfL7PkY9dPLCRParIyzb9aPmf~MntNAAAA\n"+message, (host, port))

View File

@ -26,6 +26,6 @@ port = 7655
host = "localhost" host = "localhost"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", 0)) s.bind(("", 0))
s.sendto(name+" tYhjbFlFL38WFuO5eCzTvE0UBr4RfaqWMKlekGeMoB-Ouz7nYaWfiS-9j3jMiZT7FH~pwdmoSREOs2ZbXK84sR59P~pPfeCMxnJrk57f3U9uKzXkesjkKWYco3YAGs-G8sw8Fu2FBx0Do57yBdA9~j8Zq6pMjmgPBXCLuXG3vo0Z8zUWCjApJyFY6OXYopHck9Fz9vKy7YhC6zXFHfEuNHVkAooduiLd~aCoGij0TW3lH2rTVU-lx-DUdi6edxQ5-RvDNkXfikvytoCpRkivbNVytjCJLk~7RNU4FpBD20wTZWNJmEG3OY3cjNjawJVFdNjtgczh9K7gZ7ad-NjVjZVhXEj1lU8mk~vAH-2QE5om8dstWUwWoNDwmVDlvIJNKzQmahG~VrpFexFHXO0n3fKIXcSgWGOHDExM8w9neCt7AxUjxPDtXXuYNW~bRwcfiL-C9~z4K9rmwiTPZX0lmsToSXTF28l7WAoj~TMT9kZAjQeFRRWU5oW5oxVuonVvAAAA\n"+message, (host, port)) s.sendto("3.0 "+name+" tYhjbFlFL38WFuO5eCzTvE0UBr4RfaqWMKlekGeMoB-Ouz7nYaWfiS-9j3jMiZT7FH~pwdmoSREOs2ZbXK84sR59P~pPfeCMxnJrk57f3U9uKzXkesjkKWYco3YAGs-G8sw8Fu2FBx0Do57yBdA9~j8Zq6pMjmgPBXCLuXG3vo0Z8zUWCjApJyFY6OXYopHck9Fz9vKy7YhC6zXFHfEuNHVkAooduiLd~aCoGij0TW3lH2rTVU-lx-DUdi6edxQ5-RvDNkXfikvytoCpRkivbNVytjCJLk~7RNU4FpBD20wTZWNJmEG3OY3cjNjawJVFdNjtgczh9K7gZ7ad-NjVjZVhXEj1lU8mk~vAH-2QE5om8dstWUwWoNDwmVDlvIJNKzQmahG~VrpFexFHXO0n3fKIXcSgWGOHDExM8w9neCt7AxUjxPDtXXuYNW~bRwcfiL-C9~z4K9rmwiTPZX0lmsToSXTF28l7WAoj~TMT9kZAjQeFRRWU5oW5oxVuonVvAAAA\n"+message, (host, port))
s.sendto(name+" EYUpJFeW9tiubXR0aOjvCJ~ndj3xN0Wn-ljuGdbpOEttPg7nj0VCTOQDJ~FAolzn9FIDdmR3VjM0OFFDT46Q5HN4vShXFE2VNC8e3~GjzxJfaJhijRC2R9oIOzsNlzKtInD2o9lh0PxPioNMCigwmgWuqlQHs4tjWeaYRAtooHxbrtuoCIhIdGfyVV-nAcPiyYbouKq3leETXE~4kBXm-LfWfyPtrv6OuDk3GBVVcthv19GYBmnl2YI8HpJjc-G-TvNkgYishjzIJyEW-Xrpy43R4ZBXlyQqnheGLlbOEY8NLDbyNHLRMMOGbcr~67SVE3Iw3RqQ3Dhrkq2FCaQwcDucfIUCCbOfCZgu0hlnCkS42xsUvegQeiwMxbdI~h9v7vcR3yFFOrHX6WQvIZSbFLKNGArGJcfmOJVLqw1wTC4AgYXjk3csVDPd-QWbMXOuodyBgrg27Ds2BBYTsVXWskoo6ASsMIQZ6jMfL7PkY9dPLCRParIyzb9aPmf~MntNAAAA\n"+message, (host, port)) s.sendto("3.0 "+name+" EYUpJFeW9tiubXR0aOjvCJ~ndj3xN0Wn-ljuGdbpOEttPg7nj0VCTOQDJ~FAolzn9FIDdmR3VjM0OFFDT46Q5HN4vShXFE2VNC8e3~GjzxJfaJhijRC2R9oIOzsNlzKtInD2o9lh0PxPioNMCigwmgWuqlQHs4tjWeaYRAtooHxbrtuoCIhIdGfyVV-nAcPiyYbouKq3leETXE~4kBXm-LfWfyPtrv6OuDk3GBVVcthv19GYBmnl2YI8HpJjc-G-TvNkgYishjzIJyEW-Xrpy43R4ZBXlyQqnheGLlbOEY8NLDbyNHLRMMOGbcr~67SVE3Iw3RqQ3Dhrkq2FCaQwcDucfIUCCbOfCZgu0hlnCkS42xsUvegQeiwMxbdI~h9v7vcR3yFFOrHX6WQvIZSbFLKNGArGJcfmOJVLqw1wTC4AgYXjk3csVDPd-QWbMXOuodyBgrg27Ds2BBYTsVXWskoo6ASsMIQZ6jMfL7PkY9dPLCRParIyzb9aPmf~MntNAAAA\n"+message, (host, port))

View File

@ -55,4 +55,10 @@ while 1 :
chunk = sock.recv(100) chunk = sock.recv(100)
sys.stdout.write(chunk) sys.stdout.write(chunk)
if not chunk : break if not chunk : break
print "Forward socket closed"
l=0
while 1 :
chunk = sess.recv(100)
sys.stdout.write(chunk)
if not chunk : break

View File

@ -44,16 +44,18 @@ def accept() :
sock.send("HELLO VERSION MIN=3.0 MAX=3.0\n") sock.send("HELLO VERSION MIN=3.0 MAX=3.0\n")
sys.stdout.write(sock.recv(1000)) sys.stdout.write(sock.recv(1000))
sock.send("STREAM ACCEPT ID=" + name + silent+"\n") sock.send("STREAM ACCEPT ID=" + name + silent+"\n")
print "STREAM ACCEPT ID="+name+silent+"\n" print "STREAM ACCEPT ID="+name+silent
if (silent==" SILENT=false") :
sys.stdout.write( sock.recv(100) )
return sock return sock
def echo( sock, lines ) : def echo( sock, lines ) :
l = 0 l = 0
while lines==-1 or l<lines : while lines==-1 or l<lines :
chunk = sock.recv(1000) chunk = sock.recv(1000)
sys.stdout.write(chunk)
if lines!=-1 : l = l + 1 if lines!=-1 : l = l + 1
if not chunk : break if not chunk : break
print chunk
sock.send(chunk) sock.send(chunk)
print print

View File

@ -280,33 +280,43 @@ public class SAMBridge implements Runnable {
+ s.socket().getInetAddress().toString() + ":" + s.socket().getInetAddress().toString() + ":"
+ s.socket().getPort()); + s.socket().getPort());
try { class HelloHandler implements Runnable {
SAMHandler handler = SAMHandlerFactory.createSAMHandler(s, i2cpProps); SocketChannel s ;
if (handler == null) { SAMBridge parent ;
if (_log.shouldLog(Log.DEBUG)) HelloHandler(SocketChannel s, SAMBridge parent) {
_log.debug("SAM handler has not been instantiated"); this.s = s ;
}
public void run() {
try { try {
s.close(); SAMHandler handler = SAMHandlerFactory.createSAMHandler(s, i2cpProps);
} catch (IOException e) {} if (handler == null) {
continue; if (_log.shouldLog(Log.DEBUG))
} _log.debug("SAM handler has not been instantiated");
handler.setBridge(this); try {
handler.startHandling(); s.close();
} catch (SAMException e) { } catch (IOException e) {}
if (_log.shouldLog(Log.ERROR)) return;
_log.error("SAM error: " + e.getMessage(), e); }
try { handler.setBridge(parent);
String reply = "HELLO REPLY RESULT=I2P_ERROR MESSAGE=\"" + e.getMessage() + "\"\n"; handler.startHandling();
s.write(ByteBuffer.wrap(reply.getBytes("ISO-8859-1"))); } catch (SAMException e) {
} catch (IOException ioe) { if (_log.shouldLog(Log.ERROR))
if (_log.shouldLog(Log.ERROR)) _log.error("SAM error: " + e.getMessage(), e);
_log.error("SAM Error sending error reply", ioe); try {
} String reply = "HELLO REPLY RESULT=I2P_ERROR MESSAGE=\"" + e.getMessage() + "\"\n";
try { s.close(); } catch (IOException ioe) {} s.write(ByteBuffer.wrap(reply.getBytes("ISO-8859-1")));
} catch (Exception ee) { } catch (IOException ioe) {
try { s.close(); } catch (IOException ioe) {} if (_log.shouldLog(Log.ERROR))
_log.log(Log.CRIT, "Unexpected error handling SAM connection", ee); _log.error("SAM Error sending error reply", ioe);
}
try { s.close(); } catch (IOException ioe) {}
} catch (Exception ee) {
try { s.close(); } catch (IOException ioe) {}
_log.log(Log.CRIT, "Unexpected error handling SAM connection", ee);
}
}
} }
new I2PAppThread(new HelloHandler(s,this), "HelloHandler").start();
} }
} catch (Exception e) { } catch (Exception e) {
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))

View File

@ -84,11 +84,13 @@ public class SAMHandlerFactory {
} }
String ver = chooseBestVersion(minVer, maxVer); String ver = chooseBestVersion(minVer, maxVer);
if (ver == null)
throw new SAMException("No version specified");
// Let's answer positively
try { try {
if (ver == null) {
s.write(ByteBuffer.wrap(("HELLO REPLY RESULT=NOVERSION\n").getBytes("ISO-8859-1")));
return null ;
}
// Let's answer positively
s.write(ByteBuffer.wrap(("HELLO REPLY RESULT=OK VERSION=" s.write(ByteBuffer.wrap(("HELLO REPLY RESULT=OK VERSION="
+ ver + "\n").getBytes("ISO-8859-1"))); + ver + "\n").getBytes("ISO-8859-1")));
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {

View File

@ -8,6 +8,7 @@ package net.i2p.sam;
* *
*/ */
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Enumeration; import java.util.Enumeration;
@ -19,8 +20,11 @@ import net.i2p.I2PException;
import net.i2p.client.I2PClient; import net.i2p.client.I2PClient;
import net.i2p.client.I2PClientFactory; import net.i2p.client.I2PClientFactory;
import net.i2p.client.naming.NamingService; import net.i2p.client.naming.NamingService;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.data.PrivateKey;
import net.i2p.data.SigningPrivateKey;
import net.i2p.util.Log; import net.i2p.util.Log;
/** /**
@ -74,6 +78,22 @@ public class SAMUtils {
} }
} }
public static class InvalidDestination extends Exception {
static final long serialVersionUID = 0x1 ;
}
public static void checkPrivateDestination(String dest) throws InvalidDestination {
ByteArrayInputStream destKeyStream = new ByteArrayInputStream(Base64.decode(dest));
try {
new Destination().readBytes(destKeyStream);
new PrivateKey().readBytes(destKeyStream);
new SigningPrivateKey().readBytes(destKeyStream);
} catch (Exception e) {
throw new InvalidDestination();
}
}
/** /**
* Resolved the specified hostname. * Resolved the specified hostname.
* *
@ -108,15 +128,18 @@ public class SAMUtils {
* *
* @return the Destination for the specified hostname, or null if not found * @return the Destination for the specified hostname, or null if not found
*/ */
public static Destination getDest(String s) public static Destination getDest(String s) throws DataFormatException
{ {
Destination d = new Destination() ; Destination d = new Destination() ;
try { try {
d.fromBase64(s); d.fromBase64(s);
return d ; } catch (DataFormatException e) {
} catch (DataFormatException e) { d = lookupHost(s, null);
return lookupHost(s, null); if ( d==null ) {
} throw e ;
}
}
return d ;
} }
/** /**

View File

@ -327,7 +327,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
return false; return false;
} }
Destination dest; Destination dest = null ;
if (name.equals("ME")) { if (name.equals("ME")) {
if (getRawSession() != null) { if (getRawSession() != null) {
dest = getRawSession().getDestination(); dest = getRawSession().getDestination();
@ -340,7 +340,10 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
return false; return false;
} }
} else { } else {
dest = SAMUtils.getDest(name); try {
dest = SAMUtils.getDest(name);
} catch (DataFormatException e) {
}
} }
if (dest == null) { if (dest == null) {

View File

@ -32,7 +32,6 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.data.VerifiedDestination;
import net.i2p.util.I2PAppThread; import net.i2p.util.I2PAppThread;
/** /**
@ -182,15 +181,18 @@ public class SAMv3Handler extends SAMv1Handler
String header = null ; String header = null ;
String nick ; String nick ;
String dest ; String dest ;
String version ;
try { try {
header = DataHelper.readLine(is).trim(); header = DataHelper.readLine(is).trim();
StringTokenizer tok = new StringTokenizer(header, " "); StringTokenizer tok = new StringTokenizer(header, " ");
if (tok.countTokens() != 2) { if (tok.countTokens() != 3) {
// This is not a correct message, for sure // This is not a correct message, for sure
_log.debug("Error in message format"); _log.debug("Error in message format");
return; return;
} }
version = tok.nextToken();
if (!"3.0".equals(version)) return ;
nick = tok.nextToken(); nick = tok.nextToken();
dest = tok.nextToken(); dest = tok.nextToken();
@ -257,14 +259,30 @@ public class SAMv3Handler extends SAMv1Handler
{ {
static final long serialVersionUID = 0x1 ; static final long serialVersionUID = 0x1 ;
class ExistingId extends Exception {
static final long serialVersionUID = 0x1 ;
}
class ExistingDest extends Exception {
static final long serialVersionUID = 0x1 ;
}
HashMap<String, SessionRecord> map ; HashMap<String, SessionRecord> map ;
public SessionsDB() { public SessionsDB() {
map = new HashMap<String, SessionRecord>() ; map = new HashMap<String, SessionRecord>() ;
} }
synchronized public boolean put( String nick, SessionRecord session ) synchronized public boolean put( String nick, SessionRecord session ) throws ExistingId, ExistingDest
{ {
if ( map.containsKey(nick) ) {
throw new ExistingId();
}
for ( SessionRecord r : map.values() ) {
if (r.getDest().equals(session.getDest())) {
throw new ExistingDest();
}
}
if ( !map.containsKey(nick) ) { if ( !map.containsKey(nick) ) {
session.createThreadGroup("SAM session "+nick); session.createThreadGroup("SAM session "+nick);
map.put(nick, session) ; map.put(nick, session) ;
@ -455,16 +473,10 @@ public class SAMv3Handler extends SAMv1Handler
_log.debug("Custom destination specified [" + dest + "]"); _log.debug("Custom destination specified [" + dest + "]");
} }
boolean good_key = false ;
try { try {
good_key = (new VerifiedDestination(dest)).verifyCert(true); SAMUtils.checkPrivateDestination(dest);
} catch (DataFormatException e) { } catch ( SAMUtils.InvalidDestination e ) {
good_key = false ; return writeString("SESSION STATUS RESULT=INVALID_KEY\n");
}
if (!good_key)
{
_log.debug("Bad destination key");
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"bad destination key\"\n");
} }
nick = props.getProperty("ID"); nick = props.getProperty("ID");
@ -489,12 +501,17 @@ public class SAMv3Handler extends SAMv1Handler
allProps.putAll(i2cpProps); allProps.putAll(i2cpProps);
allProps.putAll(props); allProps.putAll(props);
if (! sSessionsHash.put( nick, new SessionRecord(dest, allProps, this) ) ) {
try {
sSessionsHash.put( nick, new SessionRecord(dest, allProps, this) ) ;
} catch (SessionsDB.ExistingId e) {
_log.debug("SESSION ID parameter already in use"); _log.debug("SESSION ID parameter already in use");
String n = nick ; return writeString("SESSION STATUS RESULT=DUPLICATED_ID\n");
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"ID "+n+" already in use\"\n"); } catch (SessionsDB.ExistingDest e) {
return writeString("SESSION STATUS RESULT=DUPLICATED_DEST\n");
} }
// Create the session // Create the session
if (style.equals("RAW")) { if (style.equals("RAW")) {
@ -568,14 +585,19 @@ public class SAMv3Handler extends SAMv1Handler
if ( session != null ) if ( session != null )
{ {
_log.error ( "STREAM message received, but this session is a master session" ); _log.error ( "STREAM message received, but this session is a master session" );
writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"master session cannot be used for streams");
try {
notifyStreamResult(true, "I2P_ERROR", "master session cannot be used for streams");
} catch (IOException e) {}
return false; return false;
} }
nick = props.getProperty("ID"); nick = props.getProperty("ID");
if (nick == null) { if (nick == null) {
_log.debug("SESSION ID parameter not specified"); _log.debug("SESSION ID parameter not specified");
writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"ID not specified\"\n"); try {
notifyStreamResult(true, "I2P_ERROR", "ID not specified");
} catch (IOException e) {}
return false ; return false ;
} }
props.remove("ID"); props.remove("ID");
@ -584,7 +606,9 @@ public class SAMv3Handler extends SAMv1Handler
if ( rec==null ) { if ( rec==null ) {
_log.debug("STREAM SESSION ID does not exist"); _log.debug("STREAM SESSION ID does not exist");
writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"STREAM SESSION ID does not exist\"\n"); try {
notifyStreamResult(true, "INVALID_ID", "STREAM SESSION ID does not exist");
} catch (IOException e) {}
return false ; return false ;
} }
@ -592,7 +616,9 @@ public class SAMv3Handler extends SAMv1Handler
if (streamSession==null) { if (streamSession==null) {
_log.debug("specified ID is not a stream session"); _log.debug("specified ID is not a stream session");
writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"specified ID is not a STREAM session\"\n"); try {
notifyStreamResult(true, "I2P_ERROR", "specified ID is not a STREAM session");
} catch (IOException e) {}
return false ; return false ;
} }
@ -612,45 +638,49 @@ public class SAMv3Handler extends SAMv1Handler
{ {
_log.debug ( "Unrecognized RAW message opcode: \"" _log.debug ( "Unrecognized RAW message opcode: \""
+ opcode + "\"" ); + opcode + "\"" );
writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized RAW message opcode: \"" try {
+ opcode + "\"" ); notifyStreamResult(true, "I2P_ERROR", "Unrecognized RAW message opcode: "+opcode );
} catch (IOException e) {}
return false; return false;
} }
} }
protected boolean execStreamConnect( Properties props) { protected boolean execStreamConnect( Properties props) {
if (props == null) {
_log.debug("No parameters specified in STREAM CONNECT message");
return false;
}
boolean verbose = props.getProperty("SILENT","false").equals("false");
String dest = props.getProperty("DESTINATION");
if (dest == null) {
_log.debug("Destination not specified in RAW SEND message");
return false;
}
props.remove("DESTINATION");
try { try {
if (props == null) {
notifyStreamResult(true,"I2P_ERROR","No parameters specified in STREAM CONNECT message");
_log.debug("No parameters specified in STREAM CONNECT message");
return false;
}
boolean verbose = props.getProperty("SILENT","false").equals("false");
String dest = props.getProperty("DESTINATION");
if (dest == null) {
notifyStreamResult(verbose, "I2P_ERROR", "Destination not specified in RAW SEND message");
_log.debug("Destination not specified in RAW SEND message");
return false;
}
props.remove("DESTINATION");
try { try {
streamSession.connect( this, dest, props ); streamSession.connect( this, dest, props );
return true ; return true ;
} catch (DataFormatException e) { } catch (DataFormatException e) {
_log.debug("Invalid destination in STREAM CONNECT message"); _log.debug("Invalid destination in STREAM CONNECT message");
if (verbose) notifyStreamAccept ( "INVALID_KEY" ); notifyStreamResult ( verbose, "INVALID_KEY", null );
} catch (ConnectException e) { } catch (ConnectException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage()); _log.debug("STREAM CONNECT failed: " + e.getMessage());
if (verbose) notifyStreamAccept ( "CONNECTION_REFUSED" ); notifyStreamResult ( verbose, "CONNECTION_REFUSED", null );
} catch (NoRouteToHostException e) { } catch (NoRouteToHostException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage()); _log.debug("STREAM CONNECT failed: " + e.getMessage());
if (verbose) notifyStreamAccept ( "CANT_REACH_PEER" ); notifyStreamResult ( verbose, "CANT_REACH_PEER", null );
} catch (InterruptedIOException e) { } catch (InterruptedIOException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage()); _log.debug("STREAM CONNECT failed: " + e.getMessage());
if (verbose) notifyStreamAccept ( "TIMEOUT" ); notifyStreamResult ( verbose, "TIMEOUT", null );
} catch (I2PException e) { } catch (I2PException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage()); _log.debug("STREAM CONNECT failed: " + e.getMessage());
if (verbose) notifyStreamAccept ( "I2P_ERROR" ); notifyStreamResult ( verbose, "I2P_ERROR", e.getMessage() );
} }
} catch (IOException e) { } catch (IOException e) {
} }
@ -661,11 +691,11 @@ public class SAMv3Handler extends SAMv1Handler
try { try {
try { try {
streamSession.startForwardingIncoming(props); streamSession.startForwardingIncoming(props);
notifyStreamAccept("OK"); notifyStreamResult( true, "OK", null );
return true ; return false ;
} catch (SAMException e) { } catch (SAMException e) {
_log.debug("Forwarding STREAM connections failed: " + e.getMessage()); _log.debug("Forwarding STREAM connections failed: " + e.getMessage());
notifyStreamAccept ( "FORWARDER_FAILED" ); notifyStreamResult ( true, "I2P_ERROR", "Forwarding failed : " + e.getMessage() );
} }
} catch (IOException e) { } catch (IOException e) {
} }
@ -677,17 +707,18 @@ public class SAMv3Handler extends SAMv1Handler
boolean verbose = props.getProperty( "SILENT", "false").equals("false"); boolean verbose = props.getProperty( "SILENT", "false").equals("false");
try { try {
try { try {
notifyStreamResult(verbose, "OK", null);
streamSession.accept(this, verbose); streamSession.accept(this, verbose);
return true ; return true ;
} catch (InterruptedIOException e) { } catch (InterruptedIOException e) {
_log.debug("STREAM ACCEPT failed: " + e.getMessage()); _log.debug("STREAM ACCEPT failed: " + e.getMessage());
if (verbose) notifyStreamAccept( "TIMEOUT" ); notifyStreamResult( verbose, "TIMEOUT", e.getMessage() );
} catch (I2PException e) { } catch (I2PException e) {
_log.debug("STREAM ACCEPT failed: " + e.getMessage()); _log.debug("STREAM ACCEPT failed: " + e.getMessage());
if (verbose) notifyStreamAccept ( "I2P_ERROR" ); notifyStreamResult ( verbose, "I2P_ERROR", e.getMessage() );
} catch (SAMException e) { } catch (SAMException e) {
_log.debug("STREAM ACCEPT failed: " + e.getMessage()); _log.debug("STREAM ACCEPT failed: " + e.getMessage());
if (verbose) notifyStreamAccept ( "ALREADY_ACCEPTING" ); notifyStreamResult ( verbose, "ALREADY_ACCEPTING", null );
} }
} catch (IOException e) { } catch (IOException e) {
} }
@ -695,33 +726,16 @@ public class SAMv3Handler extends SAMv1Handler
} }
public void notifyStreamAccept(String status) throws IOException public void notifyStreamResult(boolean verbose, String result, String message) throws IOException
{ {
if ( streamSession == null ) if (!verbose) return ;
{
_log.error ( "BUG! Received stream connection, but session is null!" );
throw new NullPointerException ( "BUG! STREAM session is null!" );
}
if ( !writeString ( "STREAM STATUS RESULT=" String out = "STREAM STATUS RESULT="+result;
+ status if (message!=null)
+ "\n" ) ) out = out + " MESSAGE=\"" + message + "\"";
{ out = out + '\n';
throw new IOException ( "Error notifying connection to SAM client" );
}
}
public void notifyStreamOutgoingConnection(String result) throws IOException if ( !writeString ( out ) )
{
if ( streamSession == null )
{
_log.error ( "BUG! Received stream connection, but session is null!" );
throw new NullPointerException ( "BUG! STREAM session is null!" );
}
if ( !writeString ( "STREAM STATUS RESULT="
+ result
+ "\n" ) )
{ {
throw new IOException ( "Error notifying connection to SAM client" ); throw new IOException ( "Error notifying connection to SAM client" );
} }

View File

@ -77,7 +77,7 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle
} }
private void initSAMStreamSession(String login) private void initSAMStreamSession(String login)
throws IOException, DataFormatException, SAMException{ throws IOException, DataFormatException, SAMException {
SAMv3Handler.SessionRecord rec = getDB().get(login); SAMv3Handler.SessionRecord rec = getDB().get(login);
String dest = rec.getDest() ; String dest = rec.getDest() ;
@ -131,8 +131,7 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle
public void connect ( SAMv3Handler handler, String dest, Properties props ) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, IOException { public void connect ( SAMv3Handler handler, String dest, Properties props ) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, IOException {
boolean verbose = (props.getProperty("SILENT", "false").equals("false")); boolean verbose = (props.getProperty("SILENT", "false").equals("false"));
Destination d = new Destination(); Destination d = SAMUtils.getDest(dest);
d = SAMUtils.getDest(dest);
I2PSocketOptions opts = socketMgr.buildOptions(props); I2PSocketOptions opts = socketMgr.buildOptions(props);
if (props.getProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT) == null) if (props.getProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT) == null)
@ -148,7 +147,7 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle
if ( rec==null ) throw new InterruptedIOException() ; if ( rec==null ) throw new InterruptedIOException() ;
if (verbose) handler.notifyStreamOutgoingConnection("OK") ; handler.notifyStreamResult(verbose, "OK", null) ;
handler.stealSocket() ; handler.stealSocket() ;