java.lang.Object
net.i2p.router.transport.ntcp.EventPumper
All Implemented Interfaces:
Runnable

class EventPumperextends Object implements Runnable
The main NTCP NIO event loop thread responsible for high-throughput, low-latency handling of inbound and outbound NTCP connections using non-blocking I/O.

This class is optimized for minimal overhead and maximum event dispatch efficiency. All hot paths (e.g., processRead(SelectionKey), processWrite(SelectionKey), runDelayedEvents()) avoid synchronization, allocations, and unnecessary syscalls.

Key performance characteristics:

  • Fixed 200ms selector timeout for consistent latency
  • Immediate wakeup() on pending I/O
  • Duplicate-free write request tracking via ConcurrentHashSet
  • Spin detection: yields briefly when select() returns repeatedly without blocking
  • Failsafe iteration every 2 seconds to clean stale connections
  • Efficient buffer pooling with bounded size
  • Field Details

    • _context

      private final RouterContext _context
      The router context.
    • _log

      private final Log _log
      Logger for the pumper thread.
    • _alive

      private volatile boolean _alive
      False once the pumper has been asked to stop.
    • _selector

      private Selector _selector
      The selector watching all NTCP channels.
    • _wantsWrite

      private final Set<NTCPConnection> _wantsWrite
      Connections waiting for the selector to watch writes.
    • _wantsRead

      private final Queue<NTCPConnection> _wantsRead
      The following 3 are unbounded and lockless for performance in runDelayedEvents().
    • _wantsRegister

      private final Queue<ServerSocketChannel> _wantsRegister
      Server channels waiting for selector registration.
    • _wantsConRegister

      private final Queue<NTCPConnection> _wantsConRegister
      Outbound connections waiting for selector registration.
    • _transport

      private final NTCPTransport _transport
      The transport this pumper serves.
    • _blockedIPs

      private final ObjectCounter<String> _blockedIPs
      Recent connection attempts from blocked IPs.
    • _failedInboundEncryption

      private final ObjectCounter<String> _failedInboundEncryption
      Recent inbound handshake decryption failures by IP.
    • _expireIdleWriteTime

      private long _expireIdleWriteTime
      When idle write interest is next expired.
    • _consecutiveFastSelects

      private int _consecutiveFastSelects
      Tracks consecutive select() calls that returned immediately (tight loop guard).
    • MAX_CONSECUTIVE_FAST_SELECTS

      private static final int MAX_CONSECUTIVE_FAST_SELECTS
      After this many consecutive immediate select returns, yield briefly.
      See Also:
    • USE_DIRECT

      private static final boolean USE_DIRECT
      Whether socket buffers use direct byte buffers.
      See Also:
    • _nodelay

      private final boolean _nodelay
      Whether TCP_NODELAY is set on connections.
    • _failedOutboundAttempts

      private final Map<Hash,Long> _failedOutboundAttempts
      When an outbound connection to a peer was last attempted.
    • _failedOutboundCount

      private final Map<Hash,Integer> _failedOutboundCount
      Failed outbound attempts per peer, for backoff.
    • MIN_RETRY_INTERVAL

      private static final long MIN_RETRY_INTERVAL
      A failed peer is retried no sooner than 500 ms.
      See Also:
    • MAX_RETRY_INTERVAL

      private static final int MAX_RETRY_INTERVAL
      Longest interval between pumper restart tries.
      See Also:
    • RETRY_BACKOFF_FACTOR

      private static final float RETRY_BACKOFF_FACTOR
      Multiplier applied to the retry wait per failure.
      See Also:
    • MAX_OUTBOUND_RETRY_COUNT

      private static final int MAX_OUTBOUND_RETRY_COUNT
      Max consecutive failures before giving up on a peer entirely (until map clearance).
      See Also:
    • _lastRetryMapClear

      private long _lastRetryMapClear
      When the retry maps were last pruned.
    • RETRY_MAP_CLEAR_INTERVAL

      private static final long RETRY_MAP_CLEAR_INTERVAL
      The retry maps are pruned every 5 minutes.
      See Also:
    • MAX_RETRY_MAP_SIZE

      private static final int MAX_RETRY_MAP_SIZE
      Max entries before clearing retry maps to prevent unbounded growth under DoS.
      See Also:
    • INBOUND_RATE_REFRESH_MS

      private static final long INBOUND_RATE_REFRESH_MS
      How often the inbound rate snapshot is refreshed, one second. The snapshot is lock-free, so the accept path does not grab the global rate monitor during a flood.
      See Also:
    • _inboundSnapshotAt

      private volatile long _inboundSnapshotAt
      When the inbound rate snapshot was taken.
    • _inboundCurrentCount

      private volatile int _inboundCurrentCount
      Inbound connections in the current rate period.
    • _inboundLastCount

      private volatile int _inboundLastCount
      Inbound connections in the previous rate period.
    • _inboundPeriodStart

      private volatile long _inboundPeriodStart
      When the current rate period began.
    • BUF_SIZE

      private static final int BUF_SIZE
      This probably doesn't need to be bigger than the largest typical message, which is a 5-slot VTBM (~2700 bytes). The occasional larger message can use multiple buffers.
      See Also:
    • IS_SLOW

      private static final boolean IS_SLOW
      Every few seconds, iterate across all ntcp connections just to make sure we have their interestOps set properly (and to expire any looong idle cons). As the number of connections grows, we should try to make this happen less frequently (or not at all), but while the connection count is small, the time to iterate across them to check a few flags shouldn't be a problem. True if the runtime is slow enough to throttle the failsafe iteration.
    • _failsafeIterationFreq

      private static volatile long _failsafeIterationFreq
      How often the failsafe pass runs, tunable.
    • MIN_FAILSAFE_FREQ

      private static final long MIN_FAILSAFE_FREQ
      Fastest allowed failsafe interval.
      See Also:
    • MAX_FAILSAFE_FREQ

      private static final long MAX_FAILSAFE_FREQ
      Slowest allowed failsafe interval.
      See Also:
    • _maxIdleLps

      private static volatile int _maxIdleLps
      Max idle loop iterations per second before the pumper sleeps to cap CPU. This is the real governor for idle busy-spin: the selector timeout alone is defeated by wakeup() storms, so we enforce a minimum idle iteration time (1e9 / this) instead of the old fixed 25ms-per-2048-loops failsafe.
    • MIN_MAX_IDLE_LPS

      private static final int MIN_MAX_IDLE_LPS
      Lowest max idle loop setting.
      See Also:
    • MAX_MAX_IDLE_LPS

      private static final int MAX_MAX_IDLE_LPS
      Highest max idle loop setting.
      See Also:
    • _selectorLoopDelay

      private static volatile long _selectorLoopDelay
      Delay between selector passes when idle.
    • SELECTOR_MAX_DELAY

      private static final long SELECTOR_MAX_DELAY
      Max delay when idle — must stay low for client responsiveness.
      See Also:
    • _currentDelay

      private static volatile long _currentDelay
      Selector delay in effect right now.
    • BLOCKED_IP_FREQ

      private static final long BLOCKED_IP_FREQ
      Blocked-IP statistics are logged every 43 minutes.
      See Also:
    • MIN_EXPIRE_IDLE_TIME

      private static final long MIN_EXPIRE_IDLE_TIME
      Tunnel test now disabled, but this should be long enough to allow an active tunnel to get started.
      See Also:
    • MAX_EXPIRE_IDLE_TIME

      private static final long MAX_EXPIRE_IDLE_TIME
      Longest a connection may stay idle before being closed.
      See Also:
    • MAY_DISCON_TIMEOUT

      private static final long MAY_DISCON_TIMEOUT
      A disconnect notice gets a 10 second grace period.
      See Also:
    • RI_STORE_INTERVAL

      private static final long RI_STORE_INTERVAL
      The router info is re-stored every 29 minutes.
      See Also:
    • PROP_NODELAY

      private static final String PROP_NODELAY
      Do we use direct buffers for reading? Default false. NOT recommended as we don't keep good track of them so they will leak.

      Unsupported, set USE_DIRECT above.

      See Also:
    • MIN_MINB

      private static final int MIN_MINB
      Lowest minimum buffer count.
    • MAX_MINB

      private static final int MAX_MINB
      Highest minimum buffer count.
    • MIN_BUFS

      private static final int MIN_BUFS
      Fewest buffers the pumper uses.
    • _bufferCache

      private static final TryCache<ByteBuffer> _bufferCache
      Pooled byte buffers for socket reads.
    • WRITE_BUFSIZE

      private static final int WRITE_BUFSIZE
      Fixed size class for NTCP2 data-phase write frames.

      Each frame carries up to NTCPConnection.BUFFER_SIZE payload bytes plus the 16-byte MAC (see OutboundNTCP2State.MAC_SIZE) and a 2-byte length header. The buffer must be a constant size for pooling: the previous per-frame new byte[2 + framelen] allocation was variable-sized, so every frame smaller than BUF_SIZE escaped the cache and was reallocated on each send.

      See Also:
    • _writeBufCache

      private static final TryCache<byte[]> _writeBufCache
      NTCP2 write-frame buffers, fixed WRITE_BUFSIZE class.
    • STATUS_OK

      private static final Set<CommSystemFacade.Status> STATUS_OK
      Reachability statuses that allow inbound connections.
    • RATES

      private static final long[] RATES
      Rate stat periods for inbound connection rates.
    • MIN_INBOUND_LAST_EVENTS

      private static final int MIN_INBOUND_LAST_EVENTS
      Minimum accepted rate in the previous period; never below this floor.
      See Also:
    • INBOUND_LAST_PERIOD_MS

      private static final long INBOUND_LAST_PERIOD_MS
      Length of the previous period used to normalize the baseline rate.
      See Also:
    • INBOUND_WARMUP_MS

      private static final long INBOUND_WARMUP_MS
      Right after a period rolls over, the accept rate is meaningless; always allow.
      See Also:
    • INBOUND_DROP_RANGE

      private static final int INBOUND_DROP_RANGE
      Random range for the probabilistic reject decision.
      See Also:
    • INBOUND_DROP_BIAS

      private static final int INBOUND_DROP_BIAS
      Ratchet constant: max accept when the current rate exceeds baseline by this bias.
      See Also:
    • INBOUND_SPARE_CAPACITY_FACTOR

      private static final float INBOUND_SPARE_CAPACITY_FACTOR
      Flood threshold is relaxed when the transport still has headroom...
      See Also:
    • INBOUND_SATURATED_FACTOR

      private static final float INBOUND_SATURATED_FACTOR
      ...and tightened when it reports saturation.
      See Also:
    • MAX_BATCH

      private static final int MAX_BATCH
      Most messages written in one pass.
    • _lastExpired

      private long _lastExpired
      When idle connections were last expired.
  • Constructor Details

    • EventPumper

      public EventPumper(RouterContext ctx, NTCPTransport transport)
      Create the pump for a transport, registering the rate stats it writes. No thread is started until startPumping().
      Parameters:
      ctx - the router context, used for configuration, logging and stats
      transport - the NTCP transport whose connections this pump drives
  • Method Details

    • acquireWriteBuf

      public static byte[] acquireWriteBuf()
      Acquire a fixed-size NTCP2 frame buffer for the next data-phase frame. High-frequency path in the writer threads.

      The caller writes the frame into the returned buffer and hands it to the connection via wantsWrite(data, 0, len). The pumper later returns it to the pool via releaseWriteBuf(byte[]) once the frame has fully drained to the socket; error paths in the producer must release it instead.

      Returns:
      a byte array of length WRITE_BUFSIZE
    • releaseWriteBuf

      public static void releaseWriteBuf(byte[] data)
      Return an NTCP2 frame buffer to the pool.

      Only buffers of the exact WRITE_BUFSIZE class are accepted, so handshake and termination buffers that happen to drain through the same write path never enter this pool. The buffer is discarded, not pooled, when the cache is full.

      Parameters:
      data - the buffer to return, or null (no-op)
    • startPumping

      public void startPumping()
      Open the selector and start the pump thread.
    • stopPumping

      public void stopPumping()
      Stop the pump thread and wake the selector.
    • isAlive

      public boolean isAlive()
      Selector can take quite a while to close after calling stopPumping().
      Returns:
      true until stopPumping() is called and the selector has closed
    • register

      public void register(ServerSocketChannel chan)
      Register the acceptor. This is only called from NTCPTransport.bindAddress(int), so it isn't clear why this needs a queue.
      Parameters:
      chan - the listening channel to add to the selector
    • registerConnect

      public void registerConnect(NTCPConnection con)
      Outbound connection registration with optional retry backoff.
      Parameters:
      con - the finished outbound connection to add to the selector
    • run

      public void run()
      Run the selector event loop.
      Specified by:
      run in interface Runnable
    • throttleIdleLoop

      private boolean throttleIdleLoop(long iterStartNanos)
      Throttle a single idle loop iteration when select() spins faster than the configured maximum (1e9 / _maxIdleLps executes per second). Selector wakeup() storms can defeat the select() timeout and busy-spin the loop. This holds each no-work iteration to a minimum duration so the real work path never sleeps.
      Parameters:
      iterStartNanos - System.nanoTime() taken at the start of the iteration
      Returns:
      true if throttling was interrupted and the pumper must exit
    • perSecond

      static int perSecond(int count, int elapsedSeconds)
      Convert a raw window counter into a per-second rate.

      Both pumper loop stats describe rates ("loops/s"), so both must be divided by the window length. Reporting the raw idle count instead made that series read about five times too large on the five-second window, which also made it uncomparable with the total-loop series it is meant to be read against.

      Parameters:
      count - events observed across the window
      elapsedSeconds - window length in seconds, coerced to at least 1
      Returns:
      the per-second rate, truncated toward zero
    • elapsedSeconds

      static int elapsedSeconds(long elapsedMs)
      Whole seconds in a window, floored at 1 so a clock that has not advanced cannot divide by zero and report an inflated rate.
      Parameters:
      elapsedMs - window length in milliseconds
      Returns:
      window length in seconds, never below 1
    • publishLoopRates

      static void publishLoopRates(java.util.function.BiConsumer<String,Long> publish, int loopCount, int idleLoopCount, int elapsedSeconds)
      Publish both pumper loop rates, normalised by the same window.

      Both stats are documented as a rate, so both are divided here rather than at the call site. Publishing them from one place is deliberate: the original defect was a raw idle count published beside a normalised total, which no test of either helper alone could catch, because the error lived in which value reached the stat manager.

      Parameters:
      publish - receives the stat name and its per-second value
      loopCount - total iterations observed across the window
      idleLoopCount - no-work iterations observed across the window
      elapsedSeconds - window length in seconds
    • updateLoopRateStats

      private void updateLoopRateStats(int loopCountSinceLastRate, int idleLoopCountSinceLastRate, long lastLoopRateUpdate, long now)
      Record pumper loop statistics for each 5-second window: total loops per second and the idle-loop count used by the Tuner to derive an idle ratio. Also scales _currentDelay to curb busy-spinning: raise it quickly when the loop rate stays far above the spin threshold, lower it slowly once the rate drops. The hard idle cap lives in throttleIdleLoop(long); this stays as a responsiveness lever.
      Parameters:
      loopCountSinceLastRate - total iterations in the window
      idleLoopCountSinceLastRate - no-work iterations in the window
      lastLoopRateUpdate - timestamp of the previous window start
      now - current time in milliseconds, the end of the window
    • cleanupShutdown

      private void cleanupShutdown()
      Close every registered channel (NTCP connections and the server socket) and the selector itself on pumper shutdown. Iterates a snapshot copy of the keys because closing a connection cancels its key and mutates the selector's live key set. Iterating the set directly would race with that mutation.
    • doFailsafeCheck

      private void doFailsafeCheck()
      Periodic failsafe scan of all connections to: - Reassert OP_WRITE interest if data is pending - Close idle/stale connections - Send periodic RouterInfo.
    • adjustExpireIdleWriteTime

      private void adjustExpireIdleWriteTime(boolean haveCap)
      Adjust the idle-expire window based on connection capacity so the router keeps fewer idle connections when resources are tight. Raising the window by 1s per check under capacity and lowering it by 3s under pressure lets the window drift toward the useful range without hunting.
      Parameters:
      haveCap - true when this router has spare connection capacity
    • getIdleExpire

      static long getIdleExpire(NTCPConnection con, boolean haveCap, long expireIdleWriteTime)
      Choose the idle timeout for a single connection. A barely-communicative connection that is disposable (may disconnect, hardly any traffic) gets the short MAY_DISCON_TIMEOUT so dead handshakes free capacity quickly; everything else falls back to the capacity-adjusted window.
      Parameters:
      con - the connection being scanned
      haveCap - true when this router has spare connection capacity
      expireIdleWriteTime - current capacity-adjusted idle window
      Returns:
      the timeout in milliseconds for this connection
    • closeIdleOrSendRouterInfo

      static boolean closeIdleOrSendRouterInfo(NTCPConnection con, long now, long expire, long failsafeIterationFreq)
      Close a connection that has exceeded its idle timeout, or send our RouterInfo when the connection has been established long enough that periodic re-announce is due (uptime in the RI_STORE_INTERVAL band).
      Parameters:
      con - the connection being scanned
      now - current time in milliseconds
      expire - idle timeout for this connection
      failsafeIterationFreq - pumper slab interval; keeps the RI re-announce roughly once per interval per connection
      Returns:
      true if the connection was idle and has been closed
    • processKeys

      private void processKeys(Set<SelectionKey> selected)
      Handles the keys the selector reported as ready.
      Parameters:
      selected - the ready keys
    • wantsWrite

      public void wantsWrite(NTCPConnection con)
      Called by the connection when it has data ready to write (after bw allocation). Only wakeup if new.
      Parameters:
      con - the connection with buffered data
    • wantsRead

      public void wantsRead(NTCPConnection con)
      This is only called from NTCPConnection.complete() if there is more data, which is rare (never?) so we don't need to check for dups or make _wantsRead a Set.
      Parameters:
      con - the connection with data to read
    • acquireBuf

      public static ByteBuffer acquireBuf()
      High-frequency path in thread.
      Returns:
      a cleared buffer of BUF_SIZE capacity, direct or heap as configured
    • releaseBuf

      public static void releaseBuf(ByteBuffer buf)
      Read buffer returned to the pool. These buffers must be from acquireBuf(), i.e. capacity() == BUF_SIZE. High-frequency path in thread.
      Parameters:
      buf - the buffer to give back, null and undersized buffers are ignored
    • processAccept

      private void processAccept(SelectionKey key)
      Accepts one inbound connection and starts a handshake.
      Parameters:
      key - the server channel's selection key
    • screenAccept

      private EventPumper.AcceptVerdict screenAccept(byte[] ip, String ba)
      Screen an inbound connection attempt and decide whether to register it. Blocklisted peers and refused attempts skip the flood/establishment decision entirely. The cheap hard rejections (bans, global limit) are done first so the per-IP count and the rate-based flood check run only for otherwise-eligible peers.
      Parameters:
      ip - raw address bytes of the peer
      ba - canonical string form of the peer address
      Returns:
      the EventPumper.AcceptVerdict for this attempt, never null
    • refuseAccepted

      private void refuseAccepted(SocketChannel chan, EventPumper.AcceptVerdict verdict, String ba, boolean shouldWarn, boolean shouldInfo)
      Log and close a refused inbound connection. The BLOCKED and FLOOD verdicts are already logged by their detectors; only BANNED and LIMIT emit a message here so repeated refusals from the same source stay informative but quiet.
      Parameters:
      chan - the rejected socket, closed by this call
      verdict - why the connection was refused (never ACCEPT)
      ba - canonical string form of the peer address
      shouldWarn - pre-fetched log level check for warn
      shouldInfo - pre-fetched log level check for info
    • shouldAllowInboundEstablishment

      private boolean shouldAllowInboundEstablishment()
      Decides whether load allows another inbound connection.
      Returns:
      true to accept the connection
    • refreshInboundRateIfStale

      private void refreshInboundRateIfStale()
      Refresh the cached snapshot of the one-minute inbound accept rate.

      The expensive part — aggregating the Rate buckets — requires the global Rate monitor and only happens once per refresh interval; every accepted connection in between reads the four volatile fields lock-free. A connection flood therefore never contends on the stat lock.

    • evaluateInboundFlood

      static EventPumper.InboundFloodDecision evaluateInboundFlood(long now, int rawCurrentCount, int rawLastCount, long periodStart, boolean hasCapacity, int maxConnections, int currentConnections, RandomSource random)
      Decide whether an inbound NTCP connection should be probabilistically rejected because the accept rate is spiking well above the recent baseline while the router is already heavily loaded with connections.

      This is the pure decision half of shouldAllowInboundEstablishment(). It performs no locking and takes raw counters instead of a Rate, so the hot accept path never blocks on the global Rate monitor. The arithmetic is pinned by InboundFloodDecisionTest in the router test tree.

      Parameters:
      now - router clock time in milliseconds
      rawCurrentCount - events so far in the current (partial) rate period
      rawLastCount - events in the most recent full rate period
      periodStart - start time of the current rate period, milliseconds
      hasCapacity - true if the transport reports spare bandwidth, which relaxes the flood threshold vs. punishing when saturated
      maxConnections - the transport connection ceiling
      currentConnections - the live peer connection count
      random - source of randomness for the probabilistic decision
      Returns:
      the decision; never null
    • processConnect

      private void processConnect(SelectionKey key)
      Completes one outbound connection's handshake.
      Parameters:
      key - the channel's selection key
    • handleConnectError

      private void handleConnectError(NTCPConnection con, IOException ioe)
      Handle an outbound connect that failed with an I/O error: log at debug (or a quiet warn) level, close the connection, record the peer for retry backoff, and mark it unreachable so the transport stops attempting it until it hears proof of life.
      Parameters:
      con - the connection whose connect failed
      ioe - the failure cause
    • connectFailReason

      private static String connectFailReason(Exception e)
      The bare failure reason from a failed connect: the exception message without the JDK 13+ " (connect failed)" operation suffix, or the exception class name when there is no message.
      Parameters:
      e - the exception from the failed connect attempt
      Returns:
      the failure reason for the close-on-timeout message, never null
    • recordFailedOutbound

      private void recordFailedOutbound(RouterIdentity remote)
      Remember a failed outbound connect attempt for retry backoff, evicting the whole history when the cap is hit so the maps never grow past MAX_RETRY_MAP_SIZE.
      Parameters:
      remote - the failed peer's identity; ignored when null
    • shouldSetKeepAlive

      private boolean shouldSetKeepAlive(SocketChannel chan)
      Decides whether to enable TCP keep-alive on a channel.
      Parameters:
      chan - the channel to check
      Returns:
      true to enable keep-alive
    • processRead

      private void processRead(SelectionKey key)
      Reads from one connection until drained.
      Parameters:
      key - the channel's selection key
    • handleReadData

      private boolean handleReadData(NTCPConnection con, SelectionKey key, ByteBuffer buf, int totalRead, boolean eof)
      Hand a filled read buffer to the connection, honoring the bandwidth limiter. When the limiter queues the read, the buffer's ownership transfers to the connection and read interest is cleared so no more data is drained while the queue is backed up.
      Parameters:
      con - the connection the data arrived on
      key - the connection's selection key (to clear OP_READ when throttled)
      buf - flipped buffer containing the received bytes
      totalRead - bytes received in this iteration
      eof - true if the socket signaled EOF after these bytes
      Returns:
      false to stop the read loop (throttled, queued, or EOF)
    • handleReadEof

      private void handleReadEof(NTCPConnection con, SocketChannel chan, ByteBuffer buf)
      Handle end-of-stream on a read. An inbound connection that received nothing before EOF is treated as a connection-flood probe (or a dead handshake); its IP is counted and escalated to the banlist unless already blocklisted.
      Parameters:
      con - the connection that hit EOF
      chan - the connection's socket channel (for the peer address)
      buf - the read buffer, released by this call
    • handleReadZero

      private void handleReadZero(NTCPConnection con, boolean shouldDebug, boolean shouldInfo)
      Handle a select() wakeup with no readable bytes. A burst of these within a one-second window is treated as a connection defect and closed. Otherwise the connection stays read-interested and the zero-read count is recorded so the Tuner can judge how much of the loop is spurious wakeups.
      Parameters:
      con - the connection that returned zero bytes
      shouldDebug - pre-fetched debug level
      shouldInfo - pre-fetched info level
    • countInboundNoMessage

      private void countInboundNoMessage(String ipStr, NTCPConnection con, String reason)
      Record an inbound connection that closed before delivering any message, feeding the per-IP attempt counter and the drop statistic. Shared by the EOF and I/O-error paths so both connection-flood sources funnel into one counter.
      Parameters:
      ipStr - the peer address string, or null when it cannot be resolved
      con - the connection that dropped
      reason - short phrase logged with the event, e.g. "EOF" or "IO Error: ..."
    • handleReadError

      private void handleReadError(NTCPConnection con, IOException ioe, boolean shouldInfo)
      Handle an I/O error on a read. An inbound connection that errored before its first message escalates its IP through countInboundNoMessage(String, NTCPConnection, String); the connection is recorded as a read error when established or as a failed connect otherwise (marking the peer unreachable if it was an outbound attempt).
      Parameters:
      con - the connection that failed
      ioe - the failure cause
      shouldInfo - pre-fetched info level
    • processWrite

      private void processWrite(SelectionKey key)
      Writes queued data to one connection.
      Parameters:
      key - the channel's selection key
    • processWrite

      private boolean processWrite(NTCPConnection con, SelectionKey key)
      Try to write the queued buffers for the connection.

      Single-writer contract: this must only be called on the pumper thread (via processWrite(SelectionKey) for OP_WRITE events). Producer threads call wantsWrite(NTCPConnection) to register interest; they never write to the socket themselves. This keeps SocketChannel.write(ByteBuffer) strictly single-threaded per connection and removes the _writeLock serialization that previously spanned the whole drain loop (which could stall frame pushes from the writer pool and other connections).

      Parameters:
      con - the connection whose outbound data is drained
      key - the selection key for the OP_WRITE event being processed
      Returns:
      true if OP_WRITE interest was cleared (drain done or connection closed), false if it was re-set to keep draining
    • writeOneBuffer

      static EventPumper.WriteState writeOneBuffer(NTCPConnection con, SocketChannel chan) throws IOException
      Write one queued buffer to the socket. Empty head buffers are discarded and the drain continues; a zero-byte write means the socket buffer is full and the caller must keep OP_WRITE interest, unless the queue is empty and fully drained, in which case interest can be dropped.

      Buffers are returned to the pool once their frame is fully flushed. Only the fixed-size NTCP2 frame class re-enters the pool; smaller handshake and termination buffers are left alone. The release happens on the pumper thread immediately after NTCPConnection.removeWriteBuf(ByteBuffer) so a frame array can never be reused while any producer still references it.

      Parameters:
      con - the connection being drained
      chan - the connection's socket channel
      Returns:
      the EventPumper.WriteState governing the next step in the drain loop
      Throws:
      IOException - if the channel write fails
    • releaseDrainedWriteBuf

      static void releaseDrainedWriteBuf(ByteBuffer buf)
      Return a fully drained NTCP2 frame buffer to the pool.

      Invoked from writeOneBuffer(NTCPConnection, SocketChannel) on the pumper thread right after the buffer leaves the connection's write queue. Only arrays of the pooled WRITE_BUFSIZE class are returned; everything else (handshake, termination, and legacy buffers) is ignored.

      Parameters:
      buf - the drained buffer, wrapped around a frame array
    • runDelayedEvents

      private void runDelayedEvents()
      Runs the periodic events queued for the pumper thread.
    • processReadRequests

      private void processReadRequests(boolean debug, boolean warn)
      Registers connections that asked to be read.
      Parameters:
      debug - true for debug logging
      warn - true to log slow passes
    • processWriteRequests

      private void processWriteRequests(boolean debug, boolean warn)
      Registers connections that asked to be written to.
      Parameters:
      debug - true for debug logging
      warn - true to log slow passes
    • processServerSocketRegistrations

      private void processServerSocketRegistrations(boolean debug, boolean warn)
      Registers new listening channels with the selector.
      Parameters:
      debug - true for debug logging
      warn - true to log slow passes
    • processOutboundConnectionRegistrations

      private void processOutboundConnectionRegistrations(boolean debug, boolean warn)
      Registers new outbound channels with the selector.
      Parameters:
      debug - true for debug logging
      warn - true to log slow passes
    • classifyConnectException

      static EventPumper.ConnectErrorKind classifyConnectException(Exception e)
      Classify an exception thrown during outbound connect setup. Genuine channel-state failures from the socket layer (already-connected, connect pending, not-yet-connected) mean the peer or the connect attempt is at fault and the peer should be marked unreachable. Anything else - local configuration misuse (blocking-mode channel), invalid arguments, or an internal defect - only tears down the local connection so an internal bug never blames (and blacks out) a healthy remote peer.

      Classified by exception type rather than class-name substrings: name matching silently misreads e.g. NotYetConnectedException as OTHER and blames a peer for a local IllegalBlockingModeException.

      Parameters:
      e - the exception to classify (never null)
      Returns:
      the EventPumper.ConnectErrorKind for this exception
    • blockIP

      public void blockIP(byte[] ip)
      Record the given IP as blocked.
      Parameters:
      ip - the 4 or 16 byte address to count as blocked, null is ignored
    • trackFailedInboundHandshake

      public void trackFailedInboundHandshake(byte[] ip, Hash hash)
      Track failed inbound handshake for diagnostic stats. Handshake timeouts on the open internet are network noise, not hostile, so we do not ban for them.
      Parameters:
      ip - source IP address (tracked for stats only)
      hash - optional router hash if available
    • trackInvalidEncryption

      public void trackInvalidEncryption(byte[] ip, Hash hash)
      Track failed inbound handshake with invalid encryption and ban if too many failures. Ban reason: "Invalid encryption".
      Parameters:
      ip - byte array IP address
      hash - optional router hash if available
    • trackFailedInboundHandshake

      public void trackFailedInboundHandshake(byte[] ip)
      Track failed inbound handshake (IP only, no hash).
      Parameters:
      ip - the 4 or 16 byte source address, null is ignored
    • expireTimedOut

      private void expireTimedOut()
      Closes connections that have been idle too long.
    • getIdleTimeout

      public long getIdleTimeout()
      The idle timeout for connections.
      Returns:
      the idle timeout
    • getSelectorLoopDelay

      public static long getSelectorLoopDelay()
      Selector loop delay in milliseconds.
      Returns:
      the base delay the pumper relaxes toward
    • getMaxIdleLps

      public static int getMaxIdleLps()
      Max idle loop rate in loops per second.
      Returns:
      the ceiling on idle selector iterations per second
    • setMaxIdleLps

      public static void setMaxIdleLps(int lps)
      Max idle loop rate in loops per second, bounded 1-5000. The pumper enforces this as a minimum idle iteration time (1e9 / rate), capping idle busy-spin even when selector wakeups defeat the timeout.
      Parameters:
      lps - the requested idle loop rate, clamped to 1-5000
    • setSelectorLoopDelay

      public static void setSelectorLoopDelay(long ms)
      Selector loop delay, bounded 1-SELECTOR_MAX_DELAY ms. Updates the base delay the pumper relaxes toward and raises the live delay immediately so Tuner-driven increases take effect without waiting for the pumper's own 60s ramp.
      Parameters:
      ms - the requested base delay, clamped to 1-SELECTOR_MAX_DELAY ms
    • getFailsafeIterationFreq

      public static long getFailsafeIterationFreq()
      Failsafe iteration frequency in milliseconds.
      Returns:
      how often the failsafe iteration runs
    • setFailsafeIterationFreq

      public static void setFailsafeIterationFreq(long ms)
      Failsafe iteration frequency, bounded by MIN-MAX.
      Parameters:
      ms - the requested interval, clamped to the supported range
    • setInterest

      public static void setInterest(SelectionKey key, int op) throws CancelledKeyException
      Interest operations on the given selection key.
      Parameters:
      key - the selector key to add the interest to, ignored if invalid
      op - the SelectionKey interest operations to add
      Throws:
      CancelledKeyException
    • clearInterest

      public static void clearInterest(SelectionKey key, int op) throws CancelledKeyException
      Clear the given interest operation on the selection key.
      Parameters:
      key - the selector key to remove the interest from, ignored if invalid
      op - the SelectionKey interest operations to remove
      Throws:
      CancelledKeyException