All Implemented Interfaces:
Runnable, Handler, SAMDatagramReceiver, SAMRawReceiver, SAMStreamReceiver

class SAMv3Handlerextends SAMv1Handler
Class able to handle a SAM version 3 client connection.
  • Field Details

    • session

      private Session session
      I2P session.
    • sSessionsHash

      public static final SessionsDB sSessionsHash
      Global session-id to handler map shared by every SAMv3 bridge.
    • stolenSocket

      volatile boolean stolenSocket
      Stolen socket.
    • streamForwardingSocket

      volatile boolean streamForwardingSocket
      Stream forwarding socket.
    • sessionReady

      private volatile boolean sessionReady
      True once the SESSION CREATE has fully initialized; guards against race in execStreamMessage.
    • sendPorts

      final boolean sendPorts
      Package-visible so SAMHandlerPool can read it.
    • AUTH_ERROR

      private static final String AUTH_ERROR
      Authentication error message.
      See Also:
  • Constructor Details

    • SAMv3Handler

      public SAMv3Handler(SocketChannel s, int verMajor, int verMinor, SAMBridge parent) throws SAMException, IOException
      Create a new SAM version 3 handler. This constructor expects that the SAM HELLO message has been still answered (and stripped) from the socket input stream.
      Parameters:
      s - Socket attached to a SAM client
      verMajor - SAM major version to manage (should be 3)
      verMinor - SAM minor version to manage
      parent - the bridge owning this handler and the handler pool it came from
      Throws:
      SAMException - if the version is not supported
      IOException - if an I/O error occurs
    • SAMv3Handler

      public SAMv3Handler(SocketChannel s, int verMajor, int verMinor, Properties i2cpProps, SAMBridge parent) throws SAMException, IOException
      Create a new SAM version 3 handler. This constructor expects that the SAM HELLO message has been still answered (and stripped) from the socket input stream.
      Parameters:
      s - Socket attached to a SAM client
      verMajor - SAM major version to manage (should be 3)
      verMinor - SAM minor version to manage
      i2cpProps - properties to configure the I2CP connection (host, port, etc)
      parent - the bridge owning this handler and the handler pool it came from
      Throws:
      SAMException - if the version is not supported
      IOException - if an I/O error occurs
  • Method Details

    • verifVersion

      public boolean verifVersion()
      Verify the SAM protocol version is supported by this handler.
      Overrides:
      verifVersion in class SAMv1Handler
      Returns:
      true if the major version matches this handler's version
    • getClientIP

      public String getClientIP()
      Get the IP address of the connected SAM client.
      Returns:
      the client's IP address as a string
    • hasActiveStream

      boolean hasActiveStream()
      Whether a client data stream has been taken over by this handler.
      Returns:
      true if the handler has an active data stream (stolen or forwarding)
    • stealSocket

      public void stealSocket()
      For SAMv3StreamSession connect and accept.
    • getBridge

      SAMBridge getBridge()
      For SAMv3StreamSession.
      Returns:
      the bridge owning this handler
    • getSession

      Session getSession()
      For SAMv3DatagramServer.
      Returns:
      may be null
    • setSession

      void setSession(SAMv3RawSession sess)
      For subsessions created by MasterSession.
      Parameters:
      sess - the raw session to route reply traffic to
    • setSession

      void setSession(SAMv3DatagramSession sess)
      For subsessions created by MasterSession.
      Parameters:
      sess - the datagram session to route reply traffic to
    • setSession

      void setSession(SAMv3StreamSession sess)
      For subsessions created by MasterSession.
      Parameters:
      sess - the stream session to route reply traffic to; setting it also marks the session ready
    • processLine

      boolean processLine(String line)
      Process a single complete command line dispatched by the pool or the legacy handle() loop. Returns false to signal the caller that the handler should stop.
      Parameters:
      line - the complete command line (without trailing newline)
      Returns:
      true if the handler should continue processing commands
    • handle

      public void handle()
      Legacy handle() method. Not used when the handler is managed by SAMHandlerPool, which dispatches via processLine(). Retained to fulfill the abstract contract in SAMHandler.
      Overrides:
      handle in class SAMv1Handler
    • stopHandling

      public void stopHandling()
      Stop the SAM handler, close the socket (unless stolen), unregister from the bridge and the handler pool.
      Specified by:
      stopHandling in interface Handler
      Overrides:
      stopHandling in class SAMHandler
    • die

      private void die()
      Terminate the handler.
    • execSessionMessage

      protected boolean execSessionMessage(String opcode, Properties props)
      Parse and execute a SESSION message.
      Overrides:
      execSessionMessage in class SAMv1Handler
      Parameters:
      opcode - the SESSION sub-command (e.g. CREATE, ADD, REMOVE)
      props - the parsed message properties
      Returns:
      true if the handler should continue processing commands
    • execSessionCreate

      private boolean execSessionCreate(String nick, Properties props)
      Execute SESSION CREATE — generates or validates a destination, registers the nick, builds tunnels, and creates the session object.
      Parameters:
      nick - validated session ID
      props - parsed message properties
      Returns:
      true if the handler should continue processing
    • initDestination

      private static String initDestination(String dest, Properties props) throws DataFormatException
      Resolve TRANSIENT or validate a user-supplied private key.
      Parameters:
      dest - DESTINATION value, may be "TRANSIENT"
      props - properties (SIGNATURE_TYPE consumed if TRANSIENT)
      Returns:
      Base64-encoded private key
      Throws:
      DataFormatException - if SIGNATURE_TYPE names an unsupported type, or the supplied DESTINATION is not a valid private destination
    • instantiateSession

      private void instantiateSession(String style, String nick, Properties allProps, Properties props) throws DataFormatException, I2PSessionException, IOException, SAMException
      Create and start the session object for the given style. Blocks in the session constructors while tunnels are built.
      Parameters:
      style - session style: RAW, DATAGRAM, STREAM, MASTER or PRIMARY
      nick - session nickname, used as the session ID
      allProps - all message properties, handed to a MASTER session
      props - message properties, used to build the datagram server
      Throws:
      DataFormatException - if stored destination or key data is malformed
      I2PSessionException - if the underlying I2P session cannot be created
      IOException - if the datagram server cannot bind its host and port, or the session constructors hit an I/O error
      SAMException - if the style is not one of the recognized values, or the I2P session cannot be created
    • execSessionAddRemove

      private boolean execSessionAddRemove(String opcode, String nick, Properties props)
      Execute SESSION ADD or REMOVE for MASTER sessions.
      Parameters:
      opcode - the sub-command, ADD or REMOVE
      nick - session ID of the sub-session to add or remove
      props - message properties, STYLE consumed when adding
      Returns:
      true if the handler should continue processing commands
    • newSAMStreamSession

      private static SAMv3StreamSession newSAMStreamSession(String login) throws IOException, DataFormatException, SAMException
      Create a stream session for a login.
      Parameters:
      login - nickname of the registered session to reuse
      Returns:
      the new, not yet started, stream session
      Throws:
      NullPointerException - if login nickname is not registered
      IOException - if the stored key stream cannot be read or the I2CP connection fails
      DataFormatException - if the stored destination or key data is malformed
      SAMException - if the I2CP port property is not a number, or the I2P session cannot be created
    • execStreamMessage

      protected boolean execStreamMessage(String opcode, Properties props)
      Parse and execute a STREAM message.
      Overrides:
      execStreamMessage in class SAMv1Handler
      Parameters:
      opcode - the STREAM sub-command (e.g. CONNECT, ACCEPT, FORWARD)
      props - the parsed message properties
      Returns:
      true if the handler should continue processing commands
    • execStreamConnect

      protected boolean execStreamConnect(Properties props)
      Parse and execute a STREAM CONNECT message. Dispatches the blocking I2P socket connect to a shared connector pool so the caller's worker thread is never blocked. Error responses (CONNECTION_REFUSED, CANT_REACH_PEER, TIMEOUT, etc.) are sent asynchronously by the ConnectTask.

      Supports SILENT mode to suppress status messages.

      Overrides:
      execStreamConnect in class SAMv1Handler
      Parameters:
      props - the parsed message properties
      Returns:
      true if the handler should continue processing commands
    • execStreamForwardIncoming

      private boolean execStreamForwardIncoming(Properties props)
      Exec stream forward incoming.
      Parameters:
      props - the parsed message properties, including the receiver PORT and SILENT flag
      Returns:
      true if forwarding was started, false when it failed
    • execStreamAccept

      private boolean execStreamAccept(Properties props)
      Execute STREAM ACCEPT. Sends "OK" synchronously and starts the blocking accept in a background thread. Result (TIMEOUT, I2P_ERROR, or the actual streaming data) arrives asynchronously.
      Parameters:
      props - the parsed message properties, SILENT flag read
      Returns:
      true if accept was launched, false on immediate error
    • notifyStreamResult

      public void notifyStreamResult(boolean verbose, String result, String message) throws IOException
      Send a STREAM STATUS RESULT line to the SAM client, unless verbose is false.
      Parameters:
      verbose - if false, does nothing
      result - non-null
      message - may be null
      Throws:
      IOException - if writing the status line to the SAM client socket fails
    • notifyStreamIncomingConnection

      public void notifyStreamIncomingConnection(Destination d, int fromPort, int toPort) throws IOException
      Tells the SAM client a new stream connection arrived, naming the ports when requested.
      Parameters:
      d - the destination of the incoming connection
      fromPort - the remote port the connection arrived on
      toPort - the local port the connection was accepted on
      Throws:
      IOException - if writing to the SAM client socket fails
    • notifyStreamIncomingConnection

      public static void notifyStreamIncomingConnection(SocketChannel client, Destination d) throws IOException
      Notify the SAM client of an incoming stream connection on a static channel.
      Parameters:
      client - the channel to the SAM client the notification is written to
      d - the destination of the remote peer
      Throws:
      IOException - if writing to the client socket fails
    • notifyStreamIncomingConnection

      public static void notifyStreamIncomingConnection(SocketChannel client, Destination d, int fromPort, int toPort) throws IOException
      Notify the SAM client of an incoming stream connection with port information.
      Parameters:
      client - the channel to the SAM client the notification is written to
      d - the destination of the remote peer
      fromPort - the source port
      toPort - the destination port
      Throws:
      IOException - if writing to the client socket fails
    • mayManageAuth

      boolean mayManageAuth()
      Determine whether this connection may change the bridge's authentication configuration. AUTH commands rewrite the credentials every future connection must present and are persisted to disk, so they are accepted only from the local host, or from a connection that authenticated when it connected.
      Returns:
      true if AUTH commands from this connection are accepted
    • mayManageAuth

      static boolean mayManageAuth(boolean fromLoopback, String authUser, boolean authEnabled)
      Decide whether an AUTH command may be issued from a connection.
      Parameters:
      fromLoopback - whether the connection is from the local host
      authUser - the user the connection authenticated as, may be null
      authEnabled - whether bridge authentication is currently enabled
      Returns:
      true if AUTH commands from such a connection are accepted
    • mayUseSession

      boolean mayUseSession(SessionRecord rec)
      Determine whether this connection may operate on a session created by another connection. STREAM commands are issued from a connection other than the one that created the session, and nicknames are shared by the whole bridge, so access is allowed to the owning connection itself and to connections belonging to the same client: the same authenticated user, or the same address when authentication is disabled.
      Parameters:
      rec - the looked-up session record, may be null
      Returns:
      true if this connection may use that session
    • execAuthMessage

      private boolean execAuthMessage(String opcode, Properties props)
      Handle the AUTH message.
      Parameters:
      opcode - the AUTH sub-command: ENABLE, DISABLE, ADD or REMOVE
      props - the parsed message properties, USER and PASSWORD read for ADD and REMOVE
      Returns:
      true if the handler should continue processing commands