java.lang.Object
net.i2p.sam.SAMStreamSession
net.i2p.sam.SAMv3StreamSession
All Implemented Interfaces:
Closeable, AutoCloseable, SAMMessageSess, Session
Direct Known Subclasses:
MasterSession

class SAMv3StreamSessionextends SAMStreamSession implements Session
SAMv3 STREAM session class.

Manages I2P streaming connections via the SAM v3 bridge. Supports three modes: outgoing CONNECT, incoming ACCEPT (via a queue fed by MasterSession), and FORWARD (proxy to a local host:port).

For subsessions created under a MasterSession, incoming I2P sockets are placed on _acceptQueue by the master's acceptor thread and consumed by dedicated per-subsession accept threads. This decouples the I2P accept loop from the per-client SAM handler and allows multiple concurrent ACCEPT commands.

  • Field Details

    • BUFFER_SIZE

      private static final int BUFFER_SIZE
      Buffer size for the stream forwarding, in bytes.
      See Also:
    • MAX_ACCEPT_QUEUE

      private static final int MAX_ACCEPT_QUEUE
      Largest accept queue allowed.
      See Also:
    • ACCEPT_POLL_TIMEOUT_SECS

      private static final int ACCEPT_POLL_TIMEOUT_SECS
      Seconds to wait for a queued socket before returning null.
      See Also:
    • socketServerLock

      private final Object socketServerLock
      Lock for the socket server state.
    • socketServer

      private I2PServerSocket socketServer
      This is ONLY set for FORWARD, not for ACCEPT.
    • _acceptors

      private final AtomicInteger _acceptors
      This is the count of active ACCEPT sockets.
    • _acceptQueue

      private final LinkedBlockingQueue<I2PSocket> _acceptQueue
      For subsession only, null otherwise.
    • sslSocketFactory

      private static I2PSSLSocketFactory sslSocketFactory
      Shared factory for the SSL forwarder sockets.
    • nick

      private final String nick
      Nickname of the session, for the logs.
  • Constructor Details

    • SAMv3StreamSession

      public SAMv3StreamSession(String login) throws IOException, DataFormatException, SAMException
      Create a new SAM STREAM session, according to information registered with the given nickname

      Caller MUST call start().

      Parameters:
      login - the nickname this session is registered under
      Throws:
      IOException - declared on this constructor, but not raised by the body
      DataFormatException - likewise declared, but not raised by the body
      SAMException - if the destination or properties read from the record name no known direction or cannot build a session
      NullPointerException - if the login nickname is not registered
    • SAMv3StreamSession

      public SAMv3StreamSession(String login, Properties props, SAMv3Handler handler, I2PSocketManager mgr, int listenPort)
      Build a Stream Session on an existing I2P session registered with the given nickname

      Caller MUST call start().

      Parameters:
      login - nickname of the session
      props - STREAM command arguments, read by the superclass
      handler - handler used to send STREAM replies back to the client
      mgr - socket manager used to create the stream sockets
      listenPort - local port to accept on, 0 for any port
  • Method Details

    • getNick

      public String getNick()
      Return the nickname this session is registered under.
      Specified by:
      getNick in interface Session
      Returns:
      the nick, the name the client registered this STREAM session under
    • queueSocket

      public boolean queueSocket(I2PSocket sock)
      Put a socket on the accept queue. Called by MasterSession.StreamAcceptor when an I2P connection arrives and matches this subsession's listen protocol and port.

      Only for subsessions created with the 5-arg constructor; the 1-arg constructor sets _acceptQueue to null and this method throws IllegalStateException.

      Parameters:
      sock - the accepted I2P socket
      Returns:
      true if queued; false if the queue is full (caller must reset the socket)
      Throws:
      IllegalStateException - if called on a non-subsession
    • getAcceptQueueSize

      public int getAcceptQueueSize()
      Return how many accepted sockets are waiting to be handed to the client.
      Returns:
      the number of sockets waiting in the accept queue, 0 if not a subsession
    • acceptSocket

      private I2PSocket acceptSocket() throws ConnectException
      Take a socket from the accept queue, with a timeout to avoid indefinite blocking on stale connections. Under heavy tracker traffic, sockets may accumulate faster than the client can consume them. A timeout ensures the acceptor thread can check for shutdown and avoid leaking threads on idle sessions.
      Returns:
      the next queued socket, or null if the queue is empty after the timeout (caller must handle null)
      Throws:
      ConnectException - if the thread is interrupted
    • getDB

      public static SessionsDB getDB()
      Get the global sessions database shared by all SAM handlers.
      Returns:
      the sessions database
    • connectAsync

      public void connectAsync(SAMv3Handler handler, String dest, Properties props) throws DataFormatException
      Initiate an async STREAM CONNECT. Validates parameters synchronously, unregisters from the pool, then hands the blocking connect to a shared connector thread pool. Returns immediately — the caller's worker is never blocked by an I2P connection attempt.

      The ConnectTask handles all error reporting and pipe setup so the calling worker is free to process other commands immediately.

      Parameters:
      handler - handler whose socket becomes the I2P data pipe
      dest - the Base64-encoded destination to connect to
      props - the connection options read from the STREAM CONNECT command
      Throws:
      DataFormatException - if dest is invalid
    • truncNick

      private static String truncNick(String n)
      Nickname truncated to four characters.
      Parameters:
      n - the session nickname, any length
      Returns:
      first 4 chars of the session nickname for thread names
    • accept

      public void accept(SAMv3Handler handler, boolean verbose) throws SAMException, InterruptedIOException
      Accept a single incoming I2P stream and pipe data through the handler's socket. Validation is synchronous; the blocking accept runs in a dedicated thread so pool workers are never blocked waiting for an incoming I2P connection.

      Multiple simultaneous accepts are allowed (v3.2+). Accepts and forwarding may not be done at the same time.

      Parameters:
      handler - handler whose socket becomes the I2P data pipe
      verbose - if true, send peer Destination as first line
      Throws:
      SAMException - if a forwarding server is already active
      InterruptedIOException - if session is gone
    • doAccept

      private void doAccept(SAMv3Handler handler, boolean verbose)
      Blocking accept executed in a dedicated thread so pool workers are never blocked waiting for incoming I2P connections.
      Parameters:
      handler - the handler whose bridge accepts the connection
      verbose - true to report the incoming connection back to the SAM client
    • startForwardingIncoming

      public void startForwardingIncoming(Properties props, boolean sendPorts) throws SAMException, InterruptedIOException
      Forward sockets from I2P to the host/port provided. Accepts and forwarding may not be done at the same time.
      Parameters:
      props - session properties supplying HOST, PORT, SSL, and SILENT
      sendPorts - true to report the local port back to the client
      Throws:
      SAMException - if PORT is missing or invalid, or a server is already defined
      InterruptedIOException - if this session is no longer registered
    • getSocketServer

      protected I2PServerSocket getSocketServer()
      Return the server socket this session accepts incoming I2P connections on.
      Returns:
      the socket server
    • stopForwardingIncoming

      public void stopForwardingIncoming() throws SAMException, InterruptedIOException
      Stop forwarding an incoming connection coming from I2P.
      Throws:
      SAMException - if no socket server has been defined for this destination
      InterruptedIOException - if the session record for this nickname has already been removed
    • close

      public void close()
      Close the stream session.
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Specified by:
      close in interface SAMMessageSess
      Overrides:
      close in class SAMStreamSession