All Implemented Interfaces:
Runnable, EventDispatcher
Direct Known Subclasses:
I2PTunnelDCCServer, I2PTunnelHTTPServer, I2PTunnelIRCServer

public class I2PTunnelServerextends I2PTunnelTask implements Runnable
Base I2P tunnel server for handling incoming connections.

I2PTunnelServer is the foundation for all I2P server tunnels that accept incoming I2P connections and forward them to local TCP services. It manages the lifecycle of I2PSocketManager, handles connection acceptance, and provides connection forwarding to configured local destinations.

Key Features:

  • Accepts incoming I2P connections via I2PServerSocket
  • Forwards connections to configurable local TCP destinations
  • Supports SSL/TLS connections via I2PSSLSocketFactory
  • Provides port-based destination mapping (targetForPort.xx)
  • Implements connection filtering via StatefulConnectionFilter
  • Uses thread pool for concurrent connection handling

Connection Flow:

  1. Client connects to I2P destination via I2PServerSocket
  2. blockingHandle(I2PSocket) is called with the I2PSocket
  3. Local TCP socket is created via getSocket(Hash, int)
  4. I2PTunnelRunner handles bidirectional data streaming

Subclasses: I2PTunnelHTTPServer, I2PTunnelIRCServer, and others extend this class to provide protocol-specific handling while reusing the core connection management infrastructure.

See Also:
  • Field Details

    • _log

      protected final Log _log
      Logger for this tunnel server.
    • sockMgr

      protected final I2PSocketManager sockMgr
      Builds the outbound sockets used to reach each configured destination.
    • i2pss

      protected volatile I2PServerSocket i2pss
      The listening server socket, null until the tunnel is started.
    • lock

      private final Object lock
      Guards the server socket and the running flag across shutdown.
    • slock

      protected final Object slock
      Passed to each I2PTunnelRunner so connection teardown serializes on it.
    • sslLock

      protected final Object sslLock
      Guards lazy creation of _sslFactory.
    • remoteHost

      protected volatile InetAddress remoteHost
      Remote endpoint of the current connection, null for the listening server.
    • remotePort

      protected volatile int remotePort
      Remote port of the current connection, 0 for the listening server.
    • l

      protected final Logging l
      Client-visible log channel: every lifecycle notice and warning reported to the I2P client (bad option values, unresolvable hosts, lingering connections).
    • _sslFactory

      private I2PSSLSocketFactory _sslFactory
      SSL factory for the client connections.
    • DEFAULT_READ_TIMEOUT

      private static final long DEFAULT_READ_TIMEOUT
      Default read timeout, negative for no timeout.
      See Also:
    • readTimeout

      protected volatile long readTimeout
      Default timeout - override if desired.
    • PROP_USE_SSL

      public static final String PROP_USE_SSL
      Config key to enable SSL.
      See Also:
    • PROP_UNIQUE_LOCAL

      public static final String PROP_UNIQUE_LOCAL
      Config key to enable unique local address.
      See Also:
    • PROP_ALT_PKF

      public static final String PROP_ALT_PKF
      Config key naming an alternate private key file. When set and readable, an EdDSA_SHA512_Ed25519 subsession is added alongside a DSA_SHA1 primary session; the primary is left alone if it is already not DSA_SHA1.
      See Also:
    • PROP_MAX_CONNECTIONS

      public static final String PROP_MAX_CONNECTIONS
      Config key to cap concurrent inbound connections; 0 (default) = unlimited. When the cap is reached, new connections are rejected promptly (HTTP: 503) instead of being queued behind a saturated pool. This is the last-resort governor under duress; normal operation should not reach it. Key: tunnel.N.option.i2ptunnel.server.maxConnections.
      See Also:
    • PROP_READ_TIMEOUT

      public static final String PROP_READ_TIMEOUT
      Config key to override the socket read timeout in ms; 0 (default) = shut down silent connections promptly (HTTP server falls back to SERVER_READ_TIMEOUT_GET). Key: tunnel.N.option.i2ptunnel.server.readTimeout.
      See Also:
    • DEFAULT_WRITE_TIMEOUT

      private static final long DEFAULT_WRITE_TIMEOUT
      Default write timeout for the outbound I2P stream (ms). Without a bounded value, a stalled peer (send window not advancing, e.g. under a SYN flood) holds a server handler thread for the full streaming disconnect timeout (default 120s) inside MessageOutputStream#flush or close(). A bounded write timeout fails when there is no ACK progress instead of blocking the handler. It does not cap throughput for a peer that is progressing, so it is safe for legitimate slow transfers. 60s is long enough that a normal I2P RTO blip (~30s avgRTO) with no other forward-ACK progress does not fail the write, while still bounding a dead peer well under the 120s disconnect timeout. A tighter default (15s) was tried and false-failed mid-body downloads whenever a single lost ACK spanned the window.
      See Also:
    • PROP_WRITE_TIMEOUT

      public static final String PROP_WRITE_TIMEOUT
      Config key to override the outbound write timeout in ms (0 = use the streaming default, which can be the full 120s disconnect timeout with no ACK progress). Key: tunnel.N.option.i2ptunnel.server.writeTimeout.
      See Also:
    • PROP_SERVER_THREADS

      public static final String PROP_SERVER_THREADS
      Config key to cap this tunnel's private server handler pool in threads. Each server tunnel owns a per-port pool summed under the global i2ptunnel.serverHandler.threads budget; unset or < 2 follows the Tuner-managed default (i2ptunnel.server.threads). Key: tunnel.N.option.i2ptunnel.server.threads.
      See Also:
    • RECONNECT_DELAY_2MIN

      private static final long RECONNECT_DELAY_2MIN
      Delay before recreating the server socket.
      See Also:
    • RECONNECT_DELAY_10S

      private static final long RECONNECT_DELAY_10S
      Delay before the short recovery attempt.
      See Also:
    • _clientExecutor

      protected volatile ThreadPoolExecutor _clientExecutor
      Pool running the per-connection client handlers, taken from the TunnelControllerGroup so server load stays inside its own thread budget. Created in run(); null until then.
    • _tcg

      protected volatile TunnelControllerGroup _tcg
      The controller group that owns this tunnel's runner pool, cached from TunnelControllerGroup.getInstance() once in run(). Cached because the singleton accessor synchronizes on the class object, which a per-request call would turn into contention across every tunnel thread.
    • _socketMap

      private final Map<Integer, InetSocketAddress> _socketMap
      The open client connections, by hash.
    • _filter

      private volatile StatefulConnectionFilter _filter
      Filter deciding which connections to accept.
    • _maxConnections

      private volatile int _maxConnections
      Concurrent inbound connection cap, 0 = unlimited. Read from PROP_MAX_CONNECTIONS.
    • _activeConnections

      private final AtomicInteger _activeConnections
      Active connection count used by the gate above.
    • _serverThreadOverride

      private volatile int _serverThreadOverride
      Per-tunnel server handler pool cap, -1 = Tuner-managed default. Read from PROP_SERVER_THREADS; re-applied live in optionsUpdated(I2PTunnel).
    • task

      protected I2PTunnelTask task
      HTTP bidirectional server task, null for standard tunnel server.
    • bidir

      protected boolean bidir
      True for HTTP bidirectional server mode.
    • serverId

      protected static volatile long serverId
      Server ID for HTTP bidirectional proxies; not incremented, always 0.
    • DEFAULT_LOCAL_PORT

      private static final int DEFAULT_LOCAL_PORT
      Default port of the client socket.
      See Also:
    • localPort

      protected int localPort
      Local port a HTTP bidir subclass hands to its proxy, replacing the DEFAULT_LOCAL_PORT placeholder. Unused by a standard server.
    • RETRY_DELAY

      private static final int RETRY_DELAY
      Delay between the connection retries.
      See Also:
    • MAX_RETRIES

      private static final int MAX_RETRIES
      Connection attempts before giving up.
      See Also:
    • DEFAULT_HANDLE_MS

      static final long DEFAULT_HANDLE_MS
      Fallback average handler time (ms) when no recent blockingHandleTime sample is available for the drain estimate.
      See Also:
    • MAX_QUEUE_DRAIN_MS

      static final long MAX_QUEUE_DRAIN_MS
      Reject only when a fully busy pool would need longer than this to drain the queue. Generous enough that normal bursts queue and complete (minimal drops) without pinning sockets indefinitely.
      See Also:
    • REJECT_WARN_MS

      private static final long REJECT_WARN_MS
      Minimum interval between gate-rejection warnings. @since 0.9.71+.
      See Also:
    • _lastRejectWarn

      private final AtomicLong _lastRejectWarn
      Last gate-rejection warning timestamp for rate limiting. @since 0.9.71+.
  • Constructor Details

    • I2PTunnelServer

      public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel)
      Non-blocking: the key is decoded and a disconnected socket manager is built here; the session is only connected, and the server socket only opened, by startRunning().
      Parameters:
      host - server hostname, kept as the remote host and named in the display name
      port - server port, kept as the remote port and named in the display name
      privData - Base64-encoded private key data, format is specified in PrivateKeyFile
      l - logger receiving the client-visible notices and warnings
      notifyThis - dispatcher notified of this server's events, e.g. openServerResult
      tunnel - owning tunnel, supplying the RouterContext, client options and host
      Throws:
      IllegalArgumentException - if the I2CP configuration is b0rked so badly that we cant create a socketManager
    • I2PTunnelServer

      public I2PTunnelServer(InetAddress host, int port, File privkey, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel)
      Non-blocking: the key file is read and a disconnected socket manager built here; the session is only connected, and the server socket only opened, by startRunning(). An unreadable file posts openServerResult "error" and throws.
      Parameters:
      host - server hostname, kept as the remote host and named in the display name
      port - server port, kept as the remote port and named in the display name
      privkey - file containing the private key data, format is specified in PrivateKeyFile
      privkeyname - the name of the privKey file, just for logging
      l - logger receiving the client-visible notices and warnings
      notifyThis - dispatcher notified of this server's events, e.g. openServerResult
      tunnel - owning tunnel, supplying the RouterContext, client options and host
      Throws:
      IllegalArgumentException - if the I2CP configuration is b0rked so badly that we cant create a socketManager
    • I2PTunnelServer

      public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel)
      Non-blocking: a disconnected socket manager is built from the already-open key stream here; the session is only connected, and the server socket only opened, by startRunning(). The stream is not closed by this constructor.
      Parameters:
      host - server hostname, kept as the remote host and named in the display name
      port - server port, kept as the remote port and named in the display name
      privData - stream containing the private key data, format is specified in PrivateKeyFile
      privkeyname - the name of the privKey file, just for logging
      l - logger receiving the client-visible notices and warnings
      notifyThis - dispatcher notified of this server's events, e.g. openServerResult
      tunnel - owning tunnel, supplying the RouterContext, client options and host
      Throws:
      IllegalArgumentException - if the I2CP configuration is b0rked so badly that we cant create a socketManager
    • I2PTunnelServer

      public I2PTunnelServer(InetAddress host, int port, I2PSocketManager sktMgr, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel)
      Non-blocking: wraps a socket manager the caller has already built and connected, and marks the server open, so the caller is responsible for the session rather than this constructor.
      Parameters:
      host - server hostname, kept as the remote host and named in the display name
      port - server port, kept as the remote port and named in the display name
      sktMgr - the existing socket manager
      l - logger receiving the client-visible notices and warnings
      notifyThis - dispatcher notified of this server's events, e.g. openServerResult
      tunnel - owning tunnel, supplying the RouterContext, client options and host
  • Method Details

    • init

      private void init(InetAddress host, int port, I2PTunnel tunnel)
      Opens the client socket and starts serving.
      Parameters:
      host - the host to bind to
      port - the port to bind to
      tunnel - the tunnel to connect through
    • createManager

      private I2PSocketManager createManager(InputStream privData)
      Create the socket manager from the private key data.
      Parameters:
      privData - the stream to read the destination and private key from
      Returns:
      the new socket manager
      Throws:
      IllegalArgumentException - if the I2CP configuration is b0rked so badly that we cant create a socketManager
    • addSubsession

      private I2PSession addSubsession(I2PSocketManager sMgr, String alt)
      Add an alternate EdDSA_SHA512_Ed25519 subsession alongside a DSA_SHA1 primary session.

      Runs only when PROP_ALT_PKF names a resolvable key file and the primary session's destination really is DSA_SHA1; a primary session of any other signature type is left alone. Any failure to read the file or add the subsession is logged and null is returned, leaving the primary session and its tunnel running without the alternate destination. The signature type is declared here rather than read back from the key file, so the nickname labels below assume an EdDSA key file.

      Parameters:
      sMgr - the primary session's socket manager
      alt - value of PROP_ALT_PKF, a key file path
      Returns:
      the subsession, or null if none was added
    • connectSessionWithRetry

      private void connectSessionWithRetry()
      Connect the session and subsessions with retries.
      Throws:
      IllegalArgumentException - if max retries reached
    • connectManager

      private void connectManager()
      Warning, blocks while connecting to router and building tunnels;
      Throws:
      IllegalArgumentException - if the I2CP configuration is b0rked so badly that we can't create a socketManager
    • startRunning

      public void startRunning()
      Start running the I2PTunnelServer. Warning, blocks while connecting to router and building tunnels;
      Throws:
      IllegalArgumentException - if the I2CP configuration is b0rked so badly that we cant create a socketManager
    • checkOfflineExpiration

      private void checkOfflineExpiration(I2PSession session, String name, String detail)
      Check if the session's offline signature is about to expire. Throws if expiration is imminent, logs a warning if soon.
      Parameters:
      session - the I2P session to check
      name - the tunnel name for log messages
      detail - extra text in log messages (e.g. " alternate destination")
    • setReadTimeout

      public void setReadTimeout(long ms)
      Set the read idle timeout for newly-created connections (in milliseconds). After this time expires without data being reached from the I2P network, the connection itself will be closed.

      Less than or equal to 0 means forever. Default -1 (forever) as of 0.9.36 for standard tunnels, but extending classes may override. Prior to that, default was 5 minutes, but did not work due to streaming bugs.

      Applies only to future connections; calling this does not affect existing connections.

      Parameters:
      ms - socket read idle timeout in milliseconds; zero or less means no timeout, the -1 default
    • tryAcquireConnection

      protected boolean tryAcquireConnection()
      Try to reserve a slot in the concurrent-connection gate. Call right after accept(), before dispatching the handler. When this returns false the connection must be rejected (rejectConnection) and never dispatched. The reserved slot is released by releaseConnection(), which runs in the handler's finally block so it also fires on early returns and exceptions.
      Returns:
      true if under the cap (or unlimited), false if the cap is exceeded
    • releaseConnection

      protected void releaseConnection()
      Release a reservation taken by tryAcquireConnection(). Idempotent-safe only when paired with the acquire; must run exactly once per accepted connection.
    • acquireConnectionSlot

      static boolean acquireConnectionSlot(int maxConnections, AtomicInteger active)
      Decide whether a concurrent-connection slot is available and, if so, reserve it. Pure decision, no router context: called by the accept loop right after accept(), before a handler thread is consumed. Cap 0 = unlimited = always available and no reservation is recorded. The caller MUST pair a successful reservation with releaseConnectionSlot(AtomicInteger) (normally from the handler's finally block).
      Parameters:
      maxConnections - the configured cap; <= 0 means unlimited
      active - the live reservation counter shared by all connections of the tunnel
      Returns:
      true if a slot was reserved (or the cap is unlimited); false if over the cap
    • releaseConnectionSlot

      static void releaseConnectionSlot(AtomicInteger active)
      Release a slot reserved by acquireConnectionSlot(int, AtomicInteger). Clamped at zero so a config change mid-flight (cap turned on while unlimited connections are live) can never push the counter negative and permanently disable the gate.
      Parameters:
      active - the reservation counter shared by all connections of the tunnel
    • parseServerThreadOverride

      static int parseServerThreadOverride(String st)
      Parse the per-tunnel server handler pool override. Pure decision: null or non-numeric values yield -1 (use the Tuner-managed default); values below the floor (< 2) are also treated as "no override" to match TunnelControllerGroup.normalizeThreadOverride(int).
      Parameters:
      st - the raw option value; may be null
      Returns:
      the override thread count, or -1 for the default
    • shouldRejectOnQueue

      static boolean shouldRejectOnQueue(int queueDepth, int capacity, int active, int threads, long avgHandleMs)
      Decide whether a connection should be rejected because the handler queue is already drowning. Pure decision, no router context: called from the accept loop after accept() and before a handler thread is consumed.

      Admission policy (high throughput, minimal drops):

      • Hard stop near queue capacity (would hit AbortPolicy anyway).
      • If any handler thread is free, admit — the backlog drains as soon as work is submitted; rejecting while capacity exists only creates empty responses the browser reports as failures.
      • Only when the pool is fully busy is a drain-time estimate applied: queueDepth * avgHandleMs / threads. Reject only when that exceeds MAX_QUEUE_DRAIN_MS, so short bursts queue and drain instead of being dropped, while a hopeless backlog fails fast rather than pinning sockets for minutes.
      Parameters:
      queueDepth - current queued task count
      capacity - total queue capacity; <= 0 disables this gate
      active - currently busy handler threads
      threads - pool max threads; <= 0 disables this gate
      avgHandleMs - average handler time in ms; <= 0 uses DEFAULT_HANDLE_MS
      Returns:
      true if the connection should be rejected with a 503
    • shouldRejectOnQueue

      static boolean shouldRejectOnQueue(int queueDepth, int capacity, int active, int threads)
      Back-compat overload when the caller has no handle-time sample yet. Uses DEFAULT_HANDLE_MS for the drain estimate.
      Parameters:
      queueDepth - current queued task count
      capacity - total queue capacity; <= 0 disables this gate
      active - currently busy handler threads
      threads - pool max threads; <= 0 disables this gate
      Returns:
      true if the connection should be rejected
    • rejectConnection

      protected void rejectConnection(I2PSocket socket)
      Refuse an inbound connection when the gate cap is exceeded. Base implementation closes the socket; I2PTunnelHTTPServer overrides to send a 503 first. Warnings are rate-limited so a flood of rejections cannot spam the log.
      Parameters:
      socket - the accepted but undelivered I2PSocket to reject
    • rejectConnection

      protected void rejectConnection(I2PSocket socket, boolean queueFull)
      Refuse an inbound connection with an accurate reason. Queue-depth rejects are not connection-cap rejects. Conflating them made every saturated-queue drop look like a maxConnections trip (and logged maxConnections=0 when the cap was unlimited).

      The queue-full metrics line is emitted by warnQueueFull(ThreadPoolExecutor, int, int, int) with real pool active/max/queue values; this method only rate-limits and closes so a flood cannot spam the log.

      Parameters:
      socket - the accepted but undelivered I2PSocket to reject
      queueFull - true if the handler queue gate rejected, false for the connection cap
    • warnQueueFull

      private void warnQueueFull(ThreadPoolExecutor ex, int queueDepth, int active, int threads)
      Rate-limited queue-full warning with the real pool metrics that drove the gate (not the connection-slot counter, which is often 0 here).
      Parameters:
      ex - the saturated handler pool
      queueDepth - queued task count at reject time
      active - busy handler threads at reject time
      threads - pool maximum at reject time
    • avgHandleMs

      private long avgHandleMs()
      60s average handler time in ms for the queue drain estimate, or 0 when no recent sample exists (caller falls back to the default).
      Returns:
      average blockingHandleTime, or 0 if unavailable
    • getReadTimeout

      public long getReadTimeout()
      Get the read idle timeout for newly-created connections (in milliseconds).

      Less than or equal to 0 means forever. Default -1 (forever) as of 0.9.36 for standard tunnels, but extending classes may override. Prior to that, default was 5 minutes, but did not work due to streaming bugs.

      Returns:
      The read timeout used for connections
    • getSocketManager

      public I2PSocketManager getSocketManager()
      Return the socket manager, or null if destroyed.
      Overrides:
      getSocketManager in class I2PTunnelTask
      Returns:
      the socket manager, or null
    • close

      public boolean close(boolean forced)
      Note that the tunnel can be reopened after this by calling startRunning(). This does not release all resources. In particular, the I2PSocketManager remains and it may have timer threads that continue running.

      To release all resources permanently, call destroy().

      Specified by:
      close in class I2PTunnelTask
      Parameters:
      forced - true to interrupt an in-progress build, false to close gracefully
      Returns:
      true if the tunnel was closed successfully, false if connections exist and forced is false
    • destroy

      public boolean destroy()
      Note that the tunnel cannot be reopened after this by calling startRunning(), as it will destroy the underlying socket manager. This releases all resources.
      Overrides:
      destroy in class I2PTunnelTask
      Returns:
      true if every resource was released
    • optionsUpdated

      public void optionsUpdated(I2PTunnel tunnel)
      Update the I2PSocketManager. And since 0.9.15, the target host and port.
      Overrides:
      optionsUpdated in class I2PTunnelTask
      Parameters:
      tunnel - the tunnel whose client options were updated
    • effectiveWriteTimeout

      static long effectiveWriteTimeout(Properties props)
      Determine the write timeout to bind the outbound I2P stream to, in ms.

      A stalled peer (send window not advancing, e.g. under a SYN flood) otherwise holds a server handler thread for the full streaming disconnect timeout (default 120s) inside MessageOutputStream#flush or close(). Bounding the write timeout fails when there is no ACK progress rather than blocking the handler; it does not cap throughput for a peer that is progressing, so it is safe for legitimate slow transfers.

      If either the tunnel's own key (PROP_WRITE_TIMEOUT) or the streaming standard key (I2PSocketOptions.PROP_WRITE_TIMEOUT) is present, honor it: return a negative value so the caller leaves the socket options' value untouched (explicit tuning wins, including 0 meaning the unbounded streaming default). Otherwise return the bounded default so unconfigured tunnels are protected.

      Parameters:
      props - the tunnel's client options; may be null
      Returns:
      the write timeout in ms to apply, or negative to apply none
    • buildSocketMap

      private void buildSocketMap(Properties props)
      Update the ports map.
      Parameters:
      props - the tunnel options, targetForPort.N entries define the map
    • run

      public void run()
      Runs the I2PTunnelServer to accept and handle incoming connections asynchronously.

      Accepts connections in a loop, submitting each to the thread pool via CompletableFuture. Handles expected exceptions with retries and logs errors. On shutdown, gracefully terminates the pool.

      Specified by:
      run in interface Runnable
    • sleepIgnoringInterrupt

      private static void sleepIgnoringInterrupt(long delayMs)
      Sleep for the given duration, ignoring interruption (but restoring the flag).
      Parameters:
      delayMs - the time to sleep in milliseconds
    • reconnectServerSocket

      private void reconnectServerSocket()
      Sleep for 2 minutes and recreate the server socket.
    • recoverServerSocket

      private boolean recoverServerSocket()
      Attempt to recover the server socket with a shorter delay. On failure, destroy the tunnel.
      Returns:
      true if recovered, false if gave up
    • closeSilently

      private static void closeSilently(I2PSocket s)
      Close an I2P socket silently, ignoring any exceptions.
      Parameters:
      s - the socket to close, null is ignored
    • blockingHandle

      protected void blockingHandle(I2PSocket socket)
      This is run in a thread from a limited-size thread pool via Handler.run(), except for a standard server (this class, no extension, as determined in getUsePool()), it is run directly in the acceptor thread (see run()).

      Handles an incoming I2P connection by forwarding it to the local TCP destination.

      This method is called by the server socket's acceptance thread when a new I2P connection arrives. It creates a local TCP socket connection and spawns an I2PTunnelRunner to handle bidirectional data streaming between the I2P and TCP connections.

      Implementation Notes:

      • Subclasses that override this must call super.blockingHandle() or implement full connection handling themselves
      • For protocol-specific handling (HTTP, IRC), spawn a handler thread and return
      • For simple forwarding, this base implementation handles all cases
      • Performance: local connections are fast enough to handle synchronously

      Error Handling: SocketException and IOException are caught and logged, with the socket being reset to notify the peer of the failure.

      Parameters:
      socket - the incoming I2P connection from a remote peer; never null
      See Also:
    • getSocket

      protected Socket getSocket(Hash from, int incomingPort) throws IOException
      Creates a TCP socket connection to the configured destination.

      This method resolves the target host and port for the incoming connection, supporting port-based destination mapping via the client options. If a port has a specific mapping (targetForPort.xx=host:port), that destination is used; otherwise, the default remoteHost and remotePort are used.

      Port Mapping Configuration:

      targetForPort.80=localhost:8080
      targetForPort.443=localhost:8443
      

      Special Ports: Ports 443 and 22 are automatically flagged for non-SSL handling to prevent SSL-over-SSL issues.

      Parameters:
      from - the hash of the peer's destination; used for local address binding
      incomingPort - the port on which the I2P connection was received
      Returns:
      a connected TCP Socket to the appropriate local destination
      Throws:
      IOException - if the socket cannot be created or connected
      See Also:
    • getSocketString

      protected String getSocketString(int incomingPort)
      Gets a human-readable string representation of the target socket.

      This method is used for logging and error messages when socket creation fails. It returns the configured destination address, taking into account any port-specific mappings that may have been configured.

      The returned string is formatted as "host:port" without any protocol prefix.

      Parameters:
      incomingPort - the incoming I2P connection port for lookup
      Returns:
      the target host and port as a string, or default if not configured
      See Also:
    • getSocket

      protected Socket getSocket(Hash from, InetAddress remoteHost, int remotePort) throws IOException
      Creates a TCP socket connection to the specified destination.

      This convenience method delegates to getSocket() with forceNonSSL=false, allowing SSL configuration to be controlled by client options.

      Parameters:
      from - the hash of the peer's destination
      remoteHost - the target InetAddress to connect to
      remotePort - the target port to connect to
      Returns:
      a connected TCP Socket
      Throws:
      IOException - if the socket cannot be created or connected
      See Also:
    • getOrCreateSSLFactory

      private I2PSSLSocketFactory getOrCreateSSLFactory() throws IOException
      Get or lazily create the SSL socket factory.
      Returns:
      the shared SSL socket factory, created on first use
      Throws:
      IOException - if the factory cannot be initialized, wrapping the underlying security exception
    • createUniqueLocalSocket

      private Socket createUniqueLocalSocket(Hash from, InetAddress remoteHost, int remotePort, int timeout) throws IOException
      Create a socket with a unique local address derived from the peer hash.
      Parameters:
      from - the peer's destination hash, supplying the unique local address bytes
      remoteHost - the address to connect to
      remotePort - the port to connect to
      timeout - the connect timeout in milliseconds
      Returns:
      a connected socket bound to a unique loopback address
      Throws:
      IOException - if the socket cannot be bound or connected
    • createPlainSocket

      private static Socket createPlainSocket(InetAddress host, int port, int timeout) throws IOException
      Create a plain (non-SSL) socket connection.
      Parameters:
      host - the address to connect to
      port - the port to connect to
      timeout - the connect timeout in milliseconds
      Returns:
      a connected socket
      Throws:
      IOException - if the connection fails
    • getSocket

      private Socket getSocket(Hash from, InetAddress remoteHost, int remotePort, boolean forceNonSSL) throws IOException
      Get a regular or SSL socket depending on config. The SSL config applies to all hosts/ports, unless forced off.
      Parameters:
      from - hash of the peer's destination for local address binding
      remoteHost - the target host to connect to
      remotePort - the target port to connect to
      forceNonSSL - true to skip SSL even when the SSL option is set
      Returns:
      a connected regular or SSL socket
      Throws:
      IOException - if the connection fails