diff --git a/apps/sam/doc/sam.3.0-protocol.txt b/apps/sam/doc/sam.3.0-protocol.txt index c544068dbd4e310e583596b95d5d8caa9b904b59..7d8871dca04d6d69d40b51ea6c83b34c2d294f2b 100644 --- a/apps/sam/doc/sam.3.0-protocol.txt +++ b/apps/sam/doc/sam.3.0-protocol.txt @@ -135,7 +135,7 @@ Streams are bidirectional communication sockets between two I2P destinations, but their opening has to be requested by one of them. Hereafter, CONNECT commands are used by the SAM client for such a request. FORWARD / ACCEPT commands are used by the SAM client when -it wants to listen to requests coming from other I2P destinations. +he wants to listen to requests coming from other I2P destinations. ----------------------------- @@ -231,10 +231,11 @@ I2P destination peer, until one of the peer closes the socket. SAM virtual streams : FORWARD ----------------------------- -A client waits for an incoming connection request by : - * opening a new socket with the SAM bridge - * passing the same HELLO handshake as above - * sending the forward command : +A client can use a regular socket server and wait for connection requests +coming from I2P. For that, the client has to : + * open a new socket with the SAM bridge + * pass the same HELLO handshake as above + * send the forward command : -> STREAM FORWARD ID={$nickname} @@ -242,7 +243,7 @@ A client waits for an incoming connection request by : [HOST={$host}] [SILENCE={true,false}] -This makes the session ${nickname} listen forever for incoming +This makes the session ${nickname} listen for incoming connection requests from the I2P network. The SAM bridge answers with : @@ -257,16 +258,12 @@ The RESULT value may be one of: I2P_ERROR INVALID_ID -The socket is closed immediately after the message by the SAM -bridge. If the result is OK, the SAM bridge starts waiting for -incoming connection requests from other I2P peers. - * {$host} is the hostname or IP address of the socket server to which SAM will forward connection requests. If not given, SAM takes the IP of the socket that issued the forward command. * {$port} is the port number of the socket server to which SAM will -forward connection requests. Is is mandatory. +forward connection requests. It is mandatory. When a connexion request arrives from I2P, the SAM bridge requests a socket connexion from {$host}:{$port}. If it is accepted after no more @@ -284,6 +281,11 @@ socket. +The I2P router will stop listening to incoming connection requests as +soon as the "forwarding" socket is closed. + + + ---------------------------------------------------------------------- SAM repliable datagrams : sending a datagram diff --git a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java index e7d192aadd9ccf9694b62d53b39daf40ce0f0341..7734ea5749c7dafc71c5a08d779d5081f87b7495 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java @@ -42,8 +42,9 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag protected SAMRawSession rawSession = null; protected SAMDatagramSession datagramSession = null; protected SAMStreamSession streamSession = null; - protected SAMDatagramSession getDatagramSession() {return datagramSession ;} protected SAMRawSession getRawSession() {return rawSession ;} + protected SAMDatagramSession getDatagramSession() {return datagramSession ;} + protected SAMStreamSession getStreamSession() {return streamSession ;} protected long _id; protected static volatile long __id = 0; @@ -331,8 +332,8 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag if (name.equals("ME")) { if (getRawSession() != null) { dest = getRawSession().getDestination(); - } else if (streamSession != null) { - dest = streamSession.getDestination(); + } else if (getStreamSession() != null) { + dest = getStreamSession().getDestination(); } else if (getDatagramSession() != null) { dest = getDatagramSession().getDestination(); } else { diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3DatagramSession.java b/apps/sam/java/src/net/i2p/sam/SAMv3DatagramSession.java index dcca03c141c5a6d41296fa49392a5fda29383322..c933e77cc341e23081c34c1d801f7bde5475f9e5 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv3DatagramSession.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv3DatagramSession.java @@ -61,10 +61,9 @@ public class SAMv3DatagramSession extends SAMDatagramSession implements SAMv3Han int port = Integer.parseInt(portStr); String host = props.getProperty("HOST"); - if ( host==null ) { - _log.debug("no host specified. Take from the client socket"); - + if ( host==null ) { host = rec.getHandler().getClientIP(); + _log.debug("no host specified. Taken from the client socket : " + host+':'+port); } diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java index f439b1253b115668b866b7c8844585b57bf3b020..b6a03a9ebfcd39faaae787eaff89875046486222 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java @@ -44,16 +44,18 @@ public class SAMv3Handler extends SAMv1Handler { private final static Log _log = new Log ( SAMv3Handler.class ); - protected SAMv3StreamSession streamSession = null ; protected SAMv3RawSession rawSession = null ; protected SAMv3DatagramSession datagramSession = null ; + protected SAMv3StreamSession streamSession = null ; + protected SAMRawSession getRawSession() { + return rawSession ; + } protected SAMDatagramSession getDatagramSession() { return datagramSession ; } - - protected SAMRawSession getRawSession() { - return rawSession ; + protected SAMStreamSession getStreamSession() { + return streamSession ; } protected Session session = null ; @@ -321,6 +323,8 @@ public class SAMv3Handler extends SAMv1Handler boolean stolenSocket = false ; + boolean streamForwardingSocket = false ; + public void stealSocket() { stolenSocket = true ; @@ -412,6 +416,20 @@ public class SAMv3Handler extends SAMv1Handler _log.error("Error closing socket: " + e.getMessage()); } } + if (streamForwardingSocket) + { + if (this.streamSession!=null) { + try { + this.streamSession.stopForwardingIncoming(); + } catch (SAMException e) { + _log.error("Error while stopping forwarding connections: " + e.getMessage()); + } catch (InterruptedIOException e) { + _log.error("Interrupted while stopping forwarding connections: " + e.getMessage()); + } + } + } + + die(); } @@ -690,9 +708,10 @@ public class SAMv3Handler extends SAMv1Handler protected boolean execStreamForwardIncoming( Properties props ) { try { try { + streamForwardingSocket = true ; streamSession.startForwardingIncoming(props); notifyStreamResult( true, "OK", null ); - return false ; + return true ; } catch (SAMException e) { _log.debug("Forwarding STREAM connections failed: " + e.getMessage()); notifyStreamResult ( true, "I2P_ERROR", "Forwarding failed : " + e.getMessage() ); diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3RawSession.java b/apps/sam/java/src/net/i2p/sam/SAMv3RawSession.java index 1bf7d18a0bea571947a7cdc2f925ec3a90665573..085293565a6b0bf278b79867382cf27bd87d5c67 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv3RawSession.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv3RawSession.java @@ -63,9 +63,9 @@ public class SAMv3RawSession extends SAMRawSession implements SAMv3Handler.Sess String host = props.getProperty("HOST"); if ( host==null ) { - _log.debug("no host specified. Take from the client socket"); - host = rec.getHandler().getClientIP(); + + _log.debug("no host specified. Taken from the client socket : " + host +':'+port); } diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3StreamSession.java b/apps/sam/java/src/net/i2p/sam/SAMv3StreamSession.java index f02591bb6eb6e03b97557381513c57af63c0574b..0d5615abe87d0a8dc15d6384071f5c02d040b896 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMv3StreamSession.java +++ b/apps/sam/java/src/net/i2p/sam/SAMv3StreamSession.java @@ -156,8 +156,8 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle WritableByteChannel toClient = handler.getClientSocket(); WritableByteChannel toI2P = Channels.newChannel(i2ps.getOutputStream()); - (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromClient,toI2P), "SAMPipeClientToI2P"))).start(); - (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromI2P,toClient), "SAMPipeClientToI2P"))).start(); + (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromClient,toI2P, "SAMPipeClientToI2P"), "SAMPipeClientToI2P"), "SAMPipeClientToI2P")).start(); + (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromI2P,toClient, "SAMPipeI2PToClient"), "SAMPipeI2PToClient"), "SAMPipeI2PToClient")).start(); } @@ -209,8 +209,8 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle WritableByteChannel toClient = handler.getClientSocket(); WritableByteChannel toI2P = Channels.newChannel(i2ps.getOutputStream()); - (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromClient,toI2P), "SAMPipeClientToI2P"))).start(); - (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromI2P,toClient), "SAMPipeClientToI2P"))).start(); + (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromClient,toI2P, "SAMPipeClientToI2P"), "SAMPipeClientToI2P"), "SAMPipeClientToI2P")).start(); + (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromI2P,toClient, "SAMPipeI2PToClient"), "SAMPipeI2PToClient"), "SAMPipeI2PToClient")).start(); } @@ -230,9 +230,8 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle String host = props.getProperty("HOST"); if ( host==null ) { - _log.debug("no host specified. Take from the client socket"); - host = rec.getHandler().getClientIP(); + _log.debug("no host specified. Taken from the client socket : " + host +':'+port); } @@ -246,8 +245,7 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle } SocketForwarder forwarder = new SocketForwarder(host, port, this, verbose); - (new Thread(rec.getThreadGroup(), new I2PAppThread(forwarder, "SAMStreamForwarder"))).start(); - + (new Thread(rec.getThreadGroup(), new I2PAppThread(forwarder, "SAMStreamForwarder"), "SAMStreamForwarder")).start(); } public class SocketForwarder extends Thread @@ -310,9 +308,11 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle ReadableByteChannel fromI2P = Channels.newChannel(i2ps.getInputStream()); WritableByteChannel toClient = clientServerSock ; WritableByteChannel toI2P = Channels.newChannel(i2ps.getOutputStream()); - new I2PAppThread(new Pipe(fromClient,toI2P), "SAMPipeClientToI2P").start(); - new I2PAppThread(new Pipe(fromI2P,toClient), "SAMPipeClientToI2P").start(); - + I2PAppThread send = new I2PAppThread(new Pipe(fromClient,toI2P, "SAMPipeClientToI2P"), "SAMPipeClientToI2P"); + I2PAppThread recv = new I2PAppThread(new Pipe(fromI2P,toClient, "SAMPipeI2PToClient"), "SAMPipeI2PToClient"); + send.start(); + recv.start(); + } catch (IOException e) { try { clientServerSock.close(); @@ -331,8 +331,9 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle WritableByteChannel out ; ByteBuffer buf ; - public Pipe(ReadableByteChannel in, WritableByteChannel out) + public Pipe(ReadableByteChannel in, WritableByteChannel out, String name) { + super(name); this.in = in ; this.out = out ; this.buf = ByteBuffer.allocate(BUFFER_SIZE) ; @@ -368,7 +369,32 @@ public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handle } } - + /** + * + * @param props + * @throws SAMException + * @throws InterruptedIOException + */ + public void stopForwardingIncoming() throws SAMException, InterruptedIOException + { + SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick); + + if ( rec==null ) throw new InterruptedIOException() ; + + I2PServerSocket server = null ; + synchronized( this.socketServerLock ) + { + if (this.socketServer==null) { + _log.debug("no socket server is defined for this destination"); + throw new SAMException("no socket server is defined for this destination"); + } + server = this.socketServer ; + this.socketServer = null ; + } + try { + server.close(); + } catch ( I2PException e) {} + } /** * Close the stream session