java.lang.Object
net.i2p.sam.SAMBridge
All Implemented Interfaces:
Runnable, ClientApp

public class SAMBridgeextends Object implements Runnable, ClientApp
SAM bridge — listens on TCP, dispatches each client to a SAMHandlerFactory handler via SAMHandlerPool, and tracks sessions in SessionsDB. Entry point for all SAM v1/v2/v3 STREAM/DATAGRAM/RAW/MASTER sessions.
  • Field Details

    • _logStatic

      private static final Log _logStatic
      Logger usable before the context exists.
    • _log

      private final Log _log
      Logger for the SAM bridge.
    • _started

      private final long _started
      When this bridge was instantiated, for the session-error grace window.
    • serverSocket

      private volatile ServerSocketChannel serverSocket
      The listening channel for client connections.
    • _listenHost

      private final String _listenHost
      Host the bridge listens on.
    • _listenPort

      private final int _listenPort
      Port the bridge listens on.
    • i2cpProps

      private final Properties i2cpProps
      I2CP properties passed to the sessions.
    • _useSSL

      private final boolean _useSSL
      True if the bridge connections use SSL.
    • _configFile

      private final File _configFile
      Config file holding the SAM keys.
    • _runner

      private volatile Thread _runner
      The thread running the accept loop.
    • _v3DGServerLock

      private final Object _v3DGServerLock
      Lock for the v3 datagram server state.
    • _v3DGServer

      private SAMv3DatagramServer _v3DGServer
      The v3 datagram server, while running.
    • _secureSession

      private final SAMSecureSessionInterface _secureSession
      Pluggable "Secure Session Manager" for interactive, GUI-based session confirmation. This will block the SAM Handler Factory at the HELLO phase. during the createSAMHandler call. If it's null, then no interactive session will be used and SAM will work without it.
    • persistFilename

      private final String persistFilename
      Filename in which the name to private key mapping should be stored (and loaded from).
    • nameToPrivKeys

      private final Map<String,String> nameToPrivKeys
      App designated destination name to the base64 of the I2P formatted destination keys (Destination+PrivateKey+SigningPrivateKey).
    • _handlers

      private final Set<Handler> _handlers
      The handlers serving open connections.
    • _handlerPool

      private volatile SAMHandlerPool _handlerPool
      The shared handler pool, while in use.
    • acceptConnections

      private volatile boolean acceptConnections
      True while the bridge accepts new connections.
    • _mgr

      private final ClientAppManager _mgr
      The app manager that started the bridge.
    • _state

      private volatile ClientAppState _state
      Current state of the bridge app.
    • DEFAULT_SAM_KEYFILE

      public static final String DEFAULT_SAM_KEYFILE
      Default filename for persistent SAM private key storage.
      See Also:
    • DEFAULT_SAM_CONFIGFILE

      static final String DEFAULT_SAM_CONFIGFILE
      Default filename for the SAM configuration file.
      See Also:
    • PROP_SAM_KEYFILE

      private static final String PROP_SAM_KEYFILE
      Config key naming the SAM key file.
      See Also:
    • PROP_SAM_SSL

      private static final String PROP_SAM_SSL
      Config key enabling SSL for the bridge.
      See Also:
    • PROP_TCP_HOST

      public static final String PROP_TCP_HOST
      Property for the SAM TCP listen address.
      See Also:
    • PROP_TCP_PORT

      public static final String PROP_TCP_PORT
      Property for the SAM TCP listen port.
      See Also:
    • PROP_AUTH

      public static final String PROP_AUTH
      Property to enable SAM bridge authentication.
      See Also:
    • PROP_PW_PREFIX

      public static final String PROP_PW_PREFIX
      Property prefix for SAM password hash entries.
      See Also:
    • PROP_PW_SUFFIX

      public static final String PROP_PW_SUFFIX
      Property suffix for SAM password hash entries.
      See Also:
    • DEFAULT_TCP_HOST

      protected static final String DEFAULT_TCP_HOST
      Default listen address for the SAM TCP socket.
      See Also:
    • DEFAULT_TCP_PORT

      protected static final String DEFAULT_TCP_PORT
      Default port for the SAM TCP socket.
      See Also:
    • PROP_DATAGRAM_HOST

      public static final String PROP_DATAGRAM_HOST
      Property for the SAM datagram listen address.
      See Also:
    • PROP_DATAGRAM_PORT

      public static final String PROP_DATAGRAM_PORT
      Property for the SAM datagram listen port.
      See Also:
    • DEFAULT_DATAGRAM_HOST

      protected static final String DEFAULT_DATAGRAM_HOST
      Default listen address for the SAM datagram socket.
      See Also:
    • DEFAULT_DATAGRAM_PORT_INT

      protected static final int DEFAULT_DATAGRAM_PORT_INT
      Default port for the SAM datagram socket.
      See Also:
    • DEFAULT_DATAGRAM_PORT

      protected static final String DEFAULT_DATAGRAM_PORT
      Default port string for the SAM datagram socket.
  • Constructor Details

    • SAMBridge

      public SAMBridge(I2PAppContext context, ClientAppManager mgr, String[] args) throws Exception
      For ClientApp interface. Recommended constructor for external use. Does NOT open the listener socket or start threads; caller must call startup().
      Parameters:
      context - the client context the bridge runs in, supplying the log
      mgr - may be null
      args - non-null
      Throws:
      Exception - on bad args
    • SAMBridge

      public SAMBridge(String listenHost, int listenPort, boolean isSSL, Properties i2cpProps, String persistFile, File configFile)
      Build a new SAM bridge. NOT recommended for external use.

      Opens the listener socket but does NOT start the thread, and there's no way to do that externally. Use main(String[]), or use the other constructor and call startup().

      Deprecated for external use, to be made private.

      Parameters:
      listenHost - hostname to listen for SAM connections on ("0.0.0.0" for all)
      listenPort - port number to listen for SAM connections on
      isSSL - true to serve SAM connections over TLS
      i2cpProps - set of I2CP properties for finding and communicating with the router
      persistFile - location to store/load named keys to/from
      configFile - location of the config file to load settings from
      Throws:
      RuntimeException - if a server socket can't be opened
    • SAMBridge

      public SAMBridge(String listenHost, int listenPort, boolean isSSL, Properties i2cpProps, String persistFile, File configFile, SAMSecureSessionInterface secureSession)
      Build a new SAM bridge. NOT recommended for external use.

      Opens the listener socket but does NOT start the thread, and there's no way to do that externally. Use main(), or use the other constructor and call startup().

      Deprecated for external use, to be made private.

      Parameters:
      listenHost - hostname to listen for SAM connections on ("0.0.0.0" for all)
      listenPort - port number to listen for SAM connections on
      isSSL - true to serve SAM connections over TLS
      i2cpProps - set of I2CP properties for finding and communicating with the router
      persistFile - location to store/load named keys to/from
      configFile - location of the config file to load settings from
      secureSession - an instance of a Secure Session to use
      Throws:
      RuntimeException - if a server socket can't be opened
  • Method Details

    • openSocket

      private void openSocket() throws IOException
      Open and bind the server socket (TCP or SSL).
      Throws:
      IOException - if the socket cannot be bound to the host and port
    • getKeystream

      public String getKeystream(String name)
      Retrieve the I2P private keystream for the given name, formatted as a base64 string (Destination+PrivateKey+SessionPrivateKey, as I2CP stores it).
      Parameters:
      name - Name of the destination
      Returns:
      null if the name does not exist, else the stream
    • addKeystream

      public void addKeystream(String name, String stream)
      Specify that the given keystream should be used for the given name.
      Parameters:
      name - Name of the destination
      stream - Base64-encoded private key stream (Destination+PrivateKey+SigningPrivateKey)
    • loadKeys

      private void loadKeys()
      Load up the keys from the persistFilename.
    • storeKeys

      private void storeKeys()
      Store the current keys to disk in the location specified on creation.
    • register

      public void register(Handler handler)
      Handlers must call on startup.
      Parameters:
      handler - the connection handler to add to the set stopped and started with this bridge
    • unregister

      public void unregister(Handler handler)
      Handlers must call on stop.
      Parameters:
      handler - the connection handler to drop from the set of handlers started and stopped with this bridge
    • getHandlerPool

      SAMHandlerPool getHandlerPool()
      Access the shared handler pool for v3 connections.
      Returns:
      the handler pool, or null if not started
    • getSessionCount

      public int getSessionCount()
      Count the named v3 sessions held in the SessionsDB, for the console status page.
      Returns:
      number of registered streams from SessionsDB
    • getHandlerCount

      public int getHandlerCount()
      Count the handlers currently serving a SAM connection, for the console status page.
      Returns:
      number of connected handlers
    • getPoolActiveCount

      public int getPoolActiveCount()
      Count the handler-pool threads running a command, for the console status page. Zero until the pool has been started.
      Returns:
      active pool worker threads, or 0 if pool not started
    • getPoolSize

      public int getPoolSize()
      Count every thread in the handler pool, busy or not, for the console status page. Zero until the pool has been started.
      Returns:
      total pool worker threads, or 0 if pool not started
    • getQueueSize

      public int getQueueSize()
      Count the commands waiting for a free pool thread, for the console status page. Zero until the pool has been started.
      Returns:
      commands queued in the pool, or 0 if pool not started
    • getPoolRegisteredCount

      public int getPoolRegisteredCount()
      Count the handlers registered with the pool, whether or not they are currently running. Zero until the pool has been started.
      Returns:
      handlers registered in the pool, or 0 if pool not started
    • getStolenSocketCount

      public int getStolenSocketCount()
      Count handlers whose socket has been stolen for data streaming.
      Returns:
      the stolen socket count
    • unregisterHandlerFromPool

      void unregisterHandlerFromPool(SAMv3Handler handler)
      Remove a v3 handler from the shared handler pool. Called by SAMv3Handler.stopHandling().
      Parameters:
      handler - non-null
    • stopHandlers

      private void stopHandlers()
      Stop all the handlers.
    • getV3DatagramServer

      SAMv3DatagramServer getV3DatagramServer(Properties props) throws IOException
      Was a static singleton, now a singleton for this bridge. Instantiate and start server if it doesn't exist. We only listen on one host and port, as specified in the sam.udp.host and sam.udp.port properties.
      Parameters:
      props - non-null instantiate and start server if it doesn't exist
      Returns:
      non-null
      Throws:
      IOException - if can't bind to host/port, or if different than existing
    • getUptime

      public long getUptime()
      Milliseconds since this bridge was instantiated, minimum 1000 while racing on startup, mirroring Router.getUptime(). The bridge is started by the router app manager during router startup, so this is a close proxy for router uptime.
      Returns:
      the uptime in ms, minimum 1000
    • startup

      public void startup() throws IOException
      Start the bridge.
      Specified by:
      startup in interface ClientApp
      Throws:
      IOException
    • shutdown

      public void shutdown(String[] args)
      Stop the bridge, shutting down the handler pool and the handlers and sessions running on it.
      Specified by:
      shutdown in interface ClientApp
      Parameters:
      args - generally null but could be stopArgs from clients.config
    • getState

      public ClientAppState getState()
      Report the bridge's position in the ClientApp lifecycle.
      Specified by:
      getState in interface ClientApp
      Returns:
      the current ClientAppState
    • getName

      public String getName()
      Report the constant service name, without the listen address.
      Specified by:
      getName in interface ClientApp
      Returns:
      "SAM", the registration key for this bridge, never null and not translated
    • getDisplayName

      public String getDisplayName()
      Return the display name.
      Specified by:
      getDisplayName in interface ClientApp
      Returns:
      the display name
    • changeState

      private void changeState(ClientAppState state)
      Record a state change with no associated error.
      Parameters:
      state - the new state of this client app
    • changeState

      private void changeState(ClientAppState state, Exception e)
      Record the new state and tell the ClientAppManager about it, if there is one.
      Parameters:
      state - the new state of this client app
      e - the error associated with the change, or null if none
    • main

      public static void main(String[] args)
      Usage:
      SAMBridge [ keyfile [listenHost ] listenPort [ name=val ]* ]
      

      or:

      SAMBridge [ name=val ]*
      

      name=val options are passed to the I2CP code to build a session, allowing the bridge to specify an alternate I2CP host and port, tunnel depth, etc.

      Parameters:
      args - [ keyfile [ listenHost ] listenPort [ name=val ]* ]
    • startThread

      private void startThread()
      Start the listener thread and schedule periodic stale-session sweeps.
    • getOptions

      private static SAMBridge.Options getOptions(String[] args) throws Exception
      Usage:
      SAMBridge [ keyfile [listenHost ] listenPort [ name=val ]* ]
      

      or:

      SAMBridge [ name=val ]*
      

      name=val options are passed to the I2CP code to build a session, allowing the bridge to specify an alternate I2CP host and port, tunnel depth, etc.

      Parameters:
      args - [ keyfile [ listenHost ] listenPort [ name=val ]* ]
      Returns:
      non-null Options or throws Exception
      Throws:
      SAMBridge.HelpRequestedException - on command line problems
      IllegalArgumentException - if specified config file does not exist
      IOException - if specified config file cannot be read, or on SSL keystore problems
      Exception
    • parseOptions

      private static void parseOptions(String[] args, int startArgs, Properties props) throws SAMBridge.HelpRequestedException
      Parse key=value options starting at startArgs.
      Parameters:
      args - the command line arguments to parse
      startArgs - index of the first option to parse
      props - out parameter, any options found are added
      Throws:
      SAMBridge.HelpRequestedException - on any item not of the form key=value.
    • usage

      private static void usage()
      Prints the command line usage text.
    • run

      public void run()
      Accept incoming SAM connections and dispatch to handlers.
      Specified by:
      run in interface Runnable
    • saveConfig

      public void saveConfig() throws IOException
      Save the current configuration to disk.
      Throws:
      IOException - if the config file cannot be written
    • renderSessionTableHTML

      public void renderSessionTableHTML(Writer out) throws IOException
      Render the session table and handler summary as HTML. Called by the router console debug page.
      Parameters:
      out - non-null
      Throws:
      IOException - if the writer fails
    • buildSessionTable

      static String buildSessionTable(List<String[]> rows)
      Build the session table from rows of {nickname, style, destination, handler IP, state, last accessed}. The state cell carries a colored dot so the table reads at a glance. Package-visible for testing.
      Parameters:
      rows - one entry per session
      Returns:
      the table html, never null
    • stateDotClass

      static String stateDotClass(String state)
      Dot color for a session state: control is a live session, forwarding and stolen are data paths, idle has no session yet, orphan lost its handler.
      Parameters:
      state - one of control, forwarding, stolen, idle, orphan
      Returns:
      the css modifier class, empty for the grey default
    • secureSession

      public SAMSecureSessionInterface secureSession()
      Returns the interactive Secure Session manager which requires SAM applications to seek "approval" for their initial connections from the user before they can start the session.
      Returns:
      the secure session interface, or null if not configured