All Implemented Interfaces:
Runnable, EventDispatcher

public class I2PTunnelIRCClientextends I2PTunnelClientBase
IRC client tunnel with DCC support and filtering.
  • Field Details

    • _addrs

      private final List<I2PSocketAddress> _addrs
      List of Destination objects that we point at.
    • DEFAULT_READ_TIMEOUT

      private static final long DEFAULT_READ_TIMEOUT
      How long a read may wait before the connection is dropped, 10 min; the application should time out its ping before this.
      See Also:
    • readTimeout

      protected long readTimeout
      Read timeout in milliseconds applied to each client socket, adjustable with setReadTimeout() after the tunnel is built.
    • _dccEnabled

      private final boolean _dccEnabled
      Whether DCC connections are supported.
    • _DCCServer

      private I2PTunnelDCCServer _DCCServer
      Serves inbound DCC connections, if any.
    • _DCCClientManager

      private DCCClientManager _DCCClientManager
      Opens outbound DCC connections, if any.
    • PROP_DCC

      public static final String PROP_DCC
      Client option key enabling the DCC file transfer manager.
      See Also:
    • IRC_CONNECT_MAX_ATTEMPTS

      static final int IRC_CONNECT_MAX_ATTEMPTS
      Maximum number of I2P connect attempts per client connection: the initial try plus three exponential-backoff retries. Once the budget is exhausted the tunnel gives up and sends the 499 error reply.
      See Also:
    • IRC_CONNECT_RETRY_BASE_DELAY

      static final long IRC_CONNECT_RETRY_BASE_DELAY
      Backoff floor (ms) for I2P connect retries, doubling per attempt.
      See Also:
  • Constructor Details

    • I2PTunnelIRCClient

      public I2PTunnelIRCClient(int localPort, String destinations, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel, String pkf) throws IllegalArgumentException
      Create an IRC client on the given local port.

      Since 0.9.20 this is fast, and does NOT connect the manager to the router, or open the local socket. You MUST call startRunning() for that.

      Parameters:
      localPort - if 0, use any port, get actual port selected with getLocalPort()
      destinations - peers we target, comma- or space-separated. Since 0.9.9, each dest may be appended with :port
      l - the logging instance
      ownDest - whether to use an owned destination
      notifyThis - the event dispatcher for notifications
      tunnel - the I2PTunnel instance
      pkf - path to the private key file, or null to generate a transient key
      Throws:
      IllegalArgumentException - if the I2PTunnel does not contain valid config to contact the router
  • Method Details

    • buildAddresses

      private void buildAddresses(String destinations)
      Parse the destination list from config.
      Parameters:
      destinations - comma-separated destination list, null for none
    • clientConnectionRun

      protected void clientConnectionRun(Socket s)
      Relays a new local connection to a configured IRC destination, retrying failures.
      Specified by:
      clientConnectionRun in class I2PTunnelClientBase
      Parameters:
      s - the socket to manage
    • getConnectRetryDelayMs

      static long getConnectRetryDelayMs(int attempt)
      Exponential backoff delay (ms) to sleep before the given connect retry. The first retry waits IRC_CONNECT_RETRY_BASE_DELAY (1s), doubling per attempt up to a hard cap of 8s. During a tunnel-pool stall the cap lets the pool recover instead of hammering it, and the loop still fails fast once I2PTunnelClientBase.poolState() reports a provably dead pool. Pure decision - no context access, safe for unit tests.
      Parameters:
      attempt - the 1-based connect failure count (how many failures so far)
      Returns:
      delay in ms: 0 for attempt <= 0, else 1000 << (attempt-1) bounded to 8000
    • shouldRetryConnect

      static boolean shouldRetryConnect(int failures, int maxAttempts, int poolState, Throwable last)
      Whether a connect attempt should be retried after failures failed attempts. Three independent conditions must all hold:
      • the attempt budget is not exhausted (failures < maxAttempts),
      • the client outbound pool is not provably dead (poolState != -1; a -2 "unknown" result from standalone clients does NOT fail fast, matching shouldStopEmptyReconnect()),
      • the failure is retryable per isRetryableConnectFailure(Throwable).
      Pure decision - no context access, safe for unit tests.
      Parameters:
      failures - the 1-based number of failed attempts so far
      maxAttempts - the total attempt budget, 1-based
      poolState - the I2PTunnelClientBase.poolState() value from the last failed attempt
      last - the throwable from the last failed attempt
      Returns:
      true if another attempt should be scheduled
    • isRetryableConnectFailure

      static boolean isRetryableConnectFailure(Throwable t)
      Whether a connect failure is transient enough to warrant another attempt.
      • Not retryable: ConnectException (an explicit refusal is a hard answer from the peer that a new attempt cannot change), an InterruptedIOException (local cancellation - the tunnel is closing), or null.
      • Retryable: everything else - NoRouteToHostException connect timeouts, UnknownHostException for a b32 destination whose LeaseSet may become available by the next attempt, I2PException tunnel build failures (incl. TooManyStreamsException), and generic I/O errors.
      Pure decision - no context access, safe for unit tests.
      Parameters:
      t - the throwable from the failed connect
      Returns:
      true if a retry is worthwhile
    • shouldRetry

      private boolean shouldRetry(int failures, Throwable t)
      Instance gate for the clientConnectionRun retry loop: applies the static budget, dead-pool and failure-classification rules with the current pool state (I2PTunnelClientBase.poolState()).
      Parameters:
      failures - the 1-based number of failed attempts so far
      t - the throwable from the last failed attempt
      Returns:
      true if another connect attempt should be scheduled
    • retryDelay

      private boolean retryDelay(int failures)
      Sleep through the exponential backoff preceding a retry, failing fast when the tunnel is being shut down mid-delay.
      Parameters:
      failures - the 1-based number of failed attempts so far
      Returns:
      true if the delay elapsed, false if the thread was interrupted
    • pickDestination

      private I2PSocketAddress pickDestination(int base, int attempt)
      Pick the destination to try for attempt attempt, rotating round-robin through all configured targets from a per-connection random start (base). Reverses the historical behavior of retrying the same randomly-chosen target repeatedly, which wasted the whole retry budget on one dead destination while the alternate targets went untried.
      Parameters:
      base - per-connection random start index, in [0, size)
      attempt - 0-based attempt number within this connection
      Returns:
      the address to try, or null if no targets are configured
    • destinationIndexForAttempt

      static int destinationIndexForAttempt(int attempt, int size, int base)
      Destination-list index for connect attempt attempt when rotating round-robin: base + attempt mod size. Attempt 0 uses the per-connection random start. Each later attempt advances one slot, so consecutive attempts always hit different targets (for size > 1). Pure decision - no context access, safe for unit tests.
      Parameters:
      attempt - 0-based attempt number within this connection
      size - number of configured destinations
      base - per-connection random start index, in [0, size)
      Returns:
      index into the destination list, in [0, size), or 0 for size <= 1
    • optionsUpdated

      public void optionsUpdated(I2PTunnel tunnel)
      Update the dests then call super.
      Overrides:
      optionsUpdated in class I2PTunnelClientBase
      Parameters:
      tunnel - the tunnel whose client options were updated
    • startRunning

      public void startRunning()
      Registers the IRC port with the port mapper when the tunnel is open.
      Overrides:
      startRunning in class I2PTunnelClientBase
    • close

      public boolean close(boolean forced)
      Unregisters the IRC port mapping, then closes the DCC server and client.
      Overrides:
      close in class I2PTunnelClientBase
      Parameters:
      forced - true to interrupt an in-progress build, false to close gracefully
      Returns:
      true if the tunnel is closed, or false if connections were still active and the close was refused