java.lang.Object
net.i2p.router.tunnel.TunnelDispatcher
All Implemented Interfaces:
Service

public class TunnelDispatcherextends Object implements Service
Handle the actual processing and forwarding of messages through the various tunnels.
For each type of tunnel, it creates a chain of handlers, as follows:

Following tunnels are created by us:

    Outbound Gateway > 0 hops:
      PumpedTunnelGateway
        BatchedRouterPreprocessor -> OutboundSender -> OutboundReceiver -> OutNetMessagePool

    Outbound zero-hop Gateway+Endpoint:
      TunnelGatewayZeroHop
        OutboundMessageDistributor -> OutNetMessagePool

    Inbound Endpoint > 0 hops:
      TunnelParticipant
       FragmentHandler ->  InboundEndpointProcessor -> InboundMessageDistributor -> InNetMessagePool

    Inbound zero-hop Gateway+Endpoint:
      TunnelGatewayZeroHop
        InboundMessageDistributor -> InNetMessagePool


Following tunnels are NOT created by us:

    Participant (not gateway or endpoint)
      TunnelParticipant
        HopProcessor -> OutNetMessagePool

    Outbound Endpoint > 0 hops:
      OutboundTunnelEndpoint
        FragmentHandler -> HopProcessor -> OutboundMessageDistributor -> OutNetMessagePool

    Inbound Gateway > 0 hops:
      ThrottledPumpedTunnelGateway
        BatchedRouterPreprocessor -> InboundSender -> InboundGatewayReceiver -> OutNetMessagePool
  • Field Details

    • _context

      private final RouterContext _context
      The router context.
    • _log

      private final Log _log
      Logger for the tunnel dispatcher.
    • _outboundGateways

      private final ConcurrentHashMap<TunnelId, TunnelGateway> _outboundGateways
      Map of outbound gateways we created.
    • _outboundEndpoints

      private final ConcurrentHashMap<TunnelId, OutboundTunnelEndpoint> _outboundEndpoints
      Map of outbound endpoints we joined.
    • _participants

      private final ConcurrentHashMap<TunnelId, TunnelParticipant> _participants
      Map of tunnel participants (either IBEP or middle hop).
    • _inboundGateways

      private final ConcurrentHashMap<TunnelId, TunnelGateway> _inboundGateways
      Map of inbound gateways (IBGW or zero-hop tunnels).
    • _participatingConfig

      private final ConcurrentHashMap<TunnelId, HopConfig> _participatingConfig
      Configurations for tunnels we are participating in but not creating.
    • _lastParticipatingExpiration

      private volatile long _lastParticipatingExpiration
      Timestamp of the last expiration of a participating tunnel.
    • _transitThrottleFactor

      private volatile float _transitThrottleFactor
      Cached transit throttle factors, refreshed by updateThrottleFactors() on the cleanup timer.
    • _inboundTransitThrottleFactor

      private volatile float _inboundTransitThrottleFactor
      Throttle applied to inbound transit bandwidth.
    • _tunedTransitThrottleFactor

      private static volatile float _tunedTransitThrottleFactor
      Tuned transit throttle factor, -1.0 = use router config. Set by the Tuner when autotuning router.transitThrottleFactor.
    • _tunedPerTunnelBweDivisor

      private static volatile int _tunedPerTunnelBweDivisor
      Tuner override for the per tunnel bandwidth divisor.
    • _validator

      private BloomFilterIVValidator _validator
      Validator used for tunnel IVs.
    • _dispatchParticipantStat

      private final RateStat _dispatchParticipantStat
      Cached handles for the three per-transit-message counters reported by dispatch(TunnelDataMessage, Hash) and dispatch(TunnelGatewayMessage).

      These cannot be batched: N calls of addRateData(name, 1) give a period total of N and an event count of N, and both are read — GraphListener stores the count when total equals count, and the Tuner reads Rate.getLastEventCount() directly. Batching would keep the plotted value right and drop the count to one per flush.

      What they do not need is the string-keyed map lookup and log-level check on every call. Resolved after initializeStats() so the handles can only ever alias an already-registered stat.

    • _dispatchEndpointStat

      private final RateStat _dispatchEndpointStat
      Stat for messages we process as a tunnel participant.
      See Also:
    • _dispatchInboundStat

      private final RateStat _dispatchInboundStat
      Stat for messages we process as a tunnel endpoint.
      See Also:
    • _leaveJob

      private final TunnelDispatcher.LeaveTunnel _leaveJob
      Job to expire tunnels we are participating in.
    • _pumper

      private final TunnelGatewayPumper _pumper
      Pumper used to drive tunnel message processing.
    • _recentlyExpired

      private final ConcurrentHashMap<TunnelId,Long> _recentlyExpired
      Recently expired tunnel IDs to suppress warnings.
    • RECENT_EXPIRY_WINDOW_MS

      private static final long RECENT_EXPIRY_WINDOW_MS
      Time window (in ms) for suppressing warnings on recently expired tunnels.
      See Also:
    • CLEANUP_INTERVAL_MIN

      private static final long CLEANUP_INTERVAL_MIN
      Base interval for periodic cleanup of expired tunnels.
      See Also:
    • CLEANUP_INTERVAL_MAX

      private static final long CLEANUP_INTERVAL_MAX
      Max interval for cleanup when few tunnels.
      See Also:
    • CLEANUP_THRESHOLD_HIGH

      private static final int CLEANUP_THRESHOLD_HIGH
      Tunnel count thresholds for scaling cleanup interval.
      See Also:
    • CLEANUP_THRESHOLD_MED

      private static final int CLEANUP_THRESHOLD_MED
      Job queue depth treated as medium stress.
      See Also:
    • TUNNEL_EXPIRY_FUDGE

      private static final long TUNNEL_EXPIRY_FUDGE
      Fudge factor for tunnel expiration check - simplifies complex calculation.
      See Also:
    • _configsBeingRemoved

      private final Set<HopConfig> _configsBeingRemoved
      Configs currently being removed - prevents duplicate removal calls.
    • RATES

      private static final long[] RATES
      Rate stat periods for the tunnel statistics.
    • _joinParticipantLock

      private final Object _joinParticipantLock
      Lock used when joining tunnels as participant, endpoint, or gateway.
    • _allocatedBW

      private final AtomicInteger _allocatedBW
      Total bandwidth allocated for participating tunnels.
    • MAX_FUTURE_EXPIRATION

      private static final long MAX_FUTURE_EXPIRATION
      High for now, just to prevent long-lived-message attacks.
      See Also:
    • _joinsSinceLast

      private final AtomicLong _joinsSinceLast
      Tunnel joins since the last stats log, a transit pool trend counter.
    • _expiresSinceLast

      private final AtomicLong _expiresSinceLast
      Tunnel expirations since the last stats log.
  • Constructor Details

    • TunnelDispatcher

      public TunnelDispatcher(RouterContext ctx)
      Creates a new instance of TunnelDispatcher.
      Parameters:
      ctx - the router context
  • Method Details

    • hasOutboundGateway

      public boolean hasOutboundGateway(TunnelId tid)
      Whether an outbound gateway exists for the given TunnelId. Lets callers avoid dispatching to a tunnel that is not ready yet.
      Parameters:
      tid - the tunnel ID
      Returns:
      true if we currently have an outbound gateway for the given TunnelId.
    • setTransitThrottleFactor

      public static void setTransitThrottleFactor(float f)
      Set the transit throttle factor (called by Tuner).
      Parameters:
      f - the transit throttle factor
    • getTransitThrottleFactor

      public static float getTransitThrottleFactor(RouterContext ctx, float def)
      The transit throttle factor in effect, tuned value if set else config.
      Parameters:
      ctx - the router context
      def - fallback when neither tuned nor configured (0.95f outbound, 0.0f inbound)
      Returns:
      the transit throttle factor
    • setPerTunnelBweDivisor

      public static void setPerTunnelBweDivisor(int div)
      Set the per-tunnel bandwidth divisor (called by Tuner).
      Parameters:
      div - the per-tunnel bandwidth divisor
    • getPerTunnelBweDivisor

      public static int getPerTunnelBweDivisor(RouterContext ctx)
      The per-tunnel bandwidth divisor in effect, tuned value if set else router.tunnel.perTunnelBweDivisor config, else the derived default of min(max tunnels, 100).
      Parameters:
      ctx - the router context
      Returns:
      the per-tunnel bandwidth divisor
    • getIVValidator

      public BloomFilterIVValidator getIVValidator()
      The tunnel IV validator, so the Tuner can retune its size. Null before setup and after shutdown.
      Returns:
      the validator, or null
    • getCleanupInterval

      private long getCleanupInterval()
      The cleanup interval scaled to the tunnel count. More tunnels = more frequent cleanup.
      Returns:
      cleanup interval in milliseconds
    • logTransitSummary

      private void logTransitSummary()
      Per-minute transit pool summary, so a transition from growth to decline is visible in the log trace without the stats graphing framework.
    • cleanupExpiredTunnels

      int cleanupExpiredTunnels()
      Clean up expired tunnels from all dispatcher maps. This is a defensive measure to remove tunnels that may have been orphaned due to race conditions or missed expirations.

      Package-visible for tests, so the sweep can be driven without waiting on the periodic timer.

      Returns:
      number of tunnels cleaned up
    • pruneExpirationQueue

      private int pruneExpirationQueue()
      Single pass over the expiration queue that both recomputes _lastParticipatingExpiration and drops entries the maps no longer hold.

      Ordering is deliberate: the running maximum is folded in before the orphan test, so a pruned entry still contributes to the maximum and remove(HopConfig) still compares against the same value it always did.

      Returns:
      number of orphaned entries pruned
    • initializeStats

      private void initializeStats()
      Initializes all stats tracked by this class.
    • registerFragmentStats

      static void registerFragmentStats(StatManager sm)
      Declare the rate stats emitted by FragmentHandler on the endpoint side. They must be declared as required: createRateStat is a no-op unless stat.full is set, and StatManager discards addRateData for an unregistered stat, so these failure and abuse signals would silently never appear in the default configuration.

      Package-visible and static so a unit test can assert the registration without standing up a whole router.

      Parameters:
      sm - the stat manager to declare into
    • createPreprocessor

      private TunnelGateway.QueuePreprocessor createPreprocessor(HopConfig cfg)
      Create a preprocessor for an inbound tunnel gateway.
      Parameters:
      cfg - the hop configuration for the inbound gateway
      Returns:
      a preprocessor batching the gateway's outbound sends
    • createPreprocessor

      private TunnelGateway.QueuePreprocessor createPreprocessor(TunnelCreatorConfig cfg)
      Create a preprocessor for an outbound tunnel gateway.
      Parameters:
      cfg - the tunnel creator configuration for the outbound gateway
      Returns:
      a preprocessor batching the gateway's outbound sends
    • getLastParticipatingExpiration

      public long getLastParticipatingExpiration()
      Returns the timestamp of the last participating tunnel expiration.
      Returns:
      last expiration in milliseconds since epoch, or -1 if none
    • updateLastParticipatingExpiration

      private void updateLastParticipatingExpiration()
      Update the last participating expiration to reflect the maximum expiration of all tunnels in the queue.
    • joinOutbound

      public boolean joinOutbound(TunnelCreatorConfig cfg)
      We are the outbound gateway - we created this tunnel.
      Parameters:
      cfg - config for the outbound tunnel we created
      Returns:
      true if successful, false if tunnel ID is a duplicate
    • joinInbound

      public boolean joinInbound(TunnelCreatorConfig cfg)
      We are the inbound endpoint - we created this tunnel.
      Parameters:
      cfg - config for the inbound tunnel we created
      Returns:
      true if successful, false if tunnel ID is a duplicate
    • joinParticipant

      public boolean joinParticipant(HopConfig cfg)
      We are a participant in this tunnel, but not as the endpoint or gateway.
      Parameters:
      cfg - config for the tunnel we're joining as participant
      Returns:
      true if successful, false if tunnel ID is a duplicate
    • joinOutboundEndpoint

      public boolean joinOutboundEndpoint(HopConfig cfg)
      We are the outbound endpoint in this tunnel, and did not create it.
      Parameters:
      cfg - config for the tunnel we're joining as outbound endpoint
      Returns:
      true if successful, false if tunnel ID is a duplicate
    • joinInboundGateway

      public boolean joinInboundGateway(HopConfig cfg)
      We are the inbound gateway in this tunnel, and did not create it.
      Parameters:
      cfg - config for the tunnel we're joining as inbound gateway
      Returns:
      true if successful, false if tunnel ID is a duplicate
    • getAllocatedBW

      public int getAllocatedBW()
      The total bandwidth allocated for participating tunnels.
      Returns:
      the allocated b w
    • getParticipatingCount

      public int getParticipatingCount()
      The number of participating tunnels.
      Returns:
      the participating count
    • getNewOBGWID

      public TunnelId getNewOBGWID()
      A random send tunnel ID that isn't a duplicate.
      Returns:
      the new o b g w i d
    • getNewIBEPID

      public TunnelId getNewIBEPID()
      A random receive tunnel ID that isn't a duplicate.
      Returns:
      the new i b e p i d
    • getNewIBZeroHopID

      public TunnelId getNewIBZeroHopID()
      A random receive tunnel ID that isn't a duplicate (zero hop).
      Returns:
      the new i b zero hop i d
    • remove

      public void remove(TunnelCreatorConfig cfg)
      Remove a tunnel we created.
      Parameters:
      cfg - the tunnel being dropped, whose direction picks the outbound gateway or inbound participant map it is removed from, and whose message and failure counts are recorded in the stats
    • remove

      public void remove(HopConfig cfg)
      Remove a tunnel we're participating in.
      Parameters:
      cfg - the tunnel being dropped, identified by its receive tunnel; releases its allocated bandwidth, null is ignored, and a second removal of the same config is a no-op
    • addRecentlyExpired

      private void addRecentlyExpired(TunnelId id)
      Records a tunnel id as recently expired.
      Parameters:
      id - the tunnel that expired
    • freeBandwidth

      private void freeBandwidth(int bw)
      Free allocated bandwidth for a tunnel.

      Only remove() may decrement this counter. A second decrement path let IdleTunnelMonitor double-free and drift the transit total negative.

      Parameters:
      bw - the bandwidth in bytes to release; zero or negative is ignored
    • dispatch

      public void dispatch(TunnelDataMessage msg, Hash recvFrom)
      Dispatch a TunnelDataMessage to the appropriate participant or endpoint.
      Parameters:
      msg - transit message to deliver, routed by its tunnel ID
      recvFrom - hash of the peer that sent it, recorded in the dispatch log and passed on for profile accounting
    • dispatch

      public void dispatch(TunnelGatewayMessage msg)
      Dispatch a TunnelGatewayMessage to the appropriate gateway.
      Parameters:
      msg - gateway message wrapping the I2NP message to forward; both its own and the wrapped expiration must fall within -CLOCK_FUDGE_FACTOR and +MAX_FUTURE_EXPIRATION of now
    • dispatchOutbound

      public boolean dispatchOutbound(I2NPMessage msg, TunnelId outboundTunnel, Hash targetPeer)
      Dispatch an outbound message through a tunnel.
      Parameters:
      msg - message to send; an already expired one is dropped, and a short expiration is extended to at least 20s for transit
      outboundTunnel - send tunnel to hand the message to, which must exist or the message is dropped
      targetPeer - hash of the eventual destination, passed to the gateway for per-peer limits and message history
      Returns:
      true if the message was accepted by the tunnel gateway, false if dropped
    • dispatchOutbound

      public boolean dispatchOutbound(I2NPMessage msg, TunnelId outboundTunnel, TunnelId targetTunnel, Hash targetPeer)
      Dispatch an outbound message through a tunnel.
      Parameters:
      msg - message to send; an already expired one is dropped, and a short expiration is extended to at least 20s for transit
      outboundTunnel - send tunnel to hand the message to, which must exist or the message is dropped
      targetTunnel - tunnel of a target that is itself reachable, or null for an ordinary peer destination; a non-null value also marks the dispatch as tunnel-targeted in the stats
      targetPeer - hash of the eventual destination, passed to the gateway for per-peer limits and message history
      Returns:
      true if the message was accepted by the tunnel gateway, false if dropped
    • listParticipatingTunnels

      public List<HopConfig> listParticipatingTunnels()
      The participating tunnels for console display. Filters out tunnels that are > 30 seconds past expiration.
      Returns:
      snapshot list of the participating tunnel configs still within 30s of their expiration
    • updateParticipatingStats

      public void updateParticipatingStats(int ms)
      Update stats for participating tunnels.
      Parameters:
      ms - length in ms of the coalescing interval the counters cover; also the averaging period applied to the message rates, so the per-tunnel average is scaled to a 10 minute figure
    • updateThrottleFactors

      void updateThrottleFactors()
      Update cached transit throttle factors from router properties.
    • shouldDropParticipatingMessage

      boolean shouldDropParticipatingMessage(TunnelDispatcher.Location loc, int type, int length, SyntheticREDQueue bwe)
      Implement RED (Random Early Discard) to enforce bandwidth limits. Only active when queue size > minThreshold (congestion). When queue > maxThreshold, ALL messages are dropped (regardless of factor).
      Parameters:
      loc - role of the sender in the tunnel, used for logging only
      type - message type, used for logging only
      length - message size in bytes; 0 or less is never dropped
      bwe - per-tunnel estimator consulted before the global limit, may be null to skip the per-tunnel check
      Returns:
      true to drop, false to accept
    • shouldDropParticipatingInboundMessage

      boolean shouldDropParticipatingInboundMessage(TunnelDispatcher.Location loc, int type, int length, SyntheticREDQueue bwe)
      Check if we should drop an inbound participating tunnel message. Implements symmetric throttling: both inbound and outbound transit traffic should be throttled equally to prevent inbound traffic from overwhelming outbound capacity.
      Parameters:
      loc - location in tunnel (IBGP, PARTICIPANT, OBEP)
      type - I2NP message type, reported in the drop log only
      length - message size in bytes
      bwe - per-tunnel bandwidth estimator (may be null)
      Returns:
      true to drop, false to accept
    • getMaxPerTunnelBandwidth

      int getMaxPerTunnelBandwidth(TunnelDispatcher.Location loc)
      The max bandwidth per transit tunnel. Scales with allocation: higher share = higher per-tunnel cap. Uses outbound bandwidth only. On floodfill routers inbound is far smaller than outbound and would create an artificial bottleneck.
      Parameters:
      loc - role in the tunnel, currently unused; the cap depends only on the outbound rate and our share percentage
      Returns:
      cap in bytes per second, floored at 10KB (30KB or 50KB for the larger allocation tiers) once the computed value exceeds 256KB
    • startup

      public void startup()
      Start up the TunnelDispatcher.
      Specified by:
      startup in interface Service
    • shutdown

      public void shutdown()
      Shut down TunnelDispatcher.
      Specified by:
      shutdown in interface Service
    • restart

      public void restart()
      Restart the TunnelDispatcher.
      Specified by:
      restart in interface Service
    • renderStatusHTML

      public void renderStatusHTML(Writer out) throws IOException
      Required by Service; status rendering moved to routerconsole.
      Specified by:
      renderStatusHTML in interface Service
      Parameters:
      out - the writer to write to
      Throws:
      IOException - if an error occurs writing
    • getShareBandwidth

      public static int getShareBandwidth(RouterContext ctx)
      The current bandwidth share in KBps.
      Parameters:
      ctx - router context whose bandwidth limiter and share percentage are read
      Returns:
      the share bandwidth
    • expiredConfigs

      static List<HopConfig> expiredConfigs(Collection<HopConfig> configs, long now)
      The queued configs whose expiration, plus the expiry fudge, has already passed.

      The whole queue is scanned. It is filled in join order, so an entry that is still live can sit in front of entries that expired long ago; stopping at the first live entry left those behind, holding a tunnel ID and transit bandwidth until the head itself expired.

      Parameters:
      configs - the queued participating tunnels
      now - current time, already allowing for the clock fudge
      Returns:
      the expired configs, in queue order; an empty list if none
    • getRequeueTime

      public static long getRequeueTime()
      The delay before an idle gateway pumper is requeued.
      Returns:
      the requeue delay in ms
    • setRequeueTime

      public static void setRequeueTime(long ms)
      The delay before an idle gateway pumper is requeued.
      Parameters:
      ms - delay in ms, clamped to [10, 200]
    • getMaxObMsgsPerPump

      public static int getMaxObMsgsPerPump()
      The cap on messages a single outbound pump pass may handle.
      Returns:
      the max outbound messages per pump
    • getPumperQueueCapacity

      public static int getPumperQueueCapacity()
      The capacity given to each gateway pumper's queue.
      Returns:
      the per-pumper queue capacity
    • setPumperQueueCapacity

      public static void setPumperQueueCapacity(int value)
      The capacity given to each gateway pumper's queue.
      Parameters:
      value - capacity, clamped to [64, 4096]; takes effect on the next pumper, existing queues are untouched
    • resizePumperQueue

      public static void resizePumperQueue(int value)
      Apply a new capacity to the running pumper instance's queue.
      Parameters:
      value - capacity to resize to
    • getPumperMaxThreads

      public static int getPumperMaxThreads()
      The cap on how many gateway pumper threads may run.
      Returns:
      the max pumper threads
    • getPumperUtilization

      public static double getPumperUtilization()
      The pumper pool utilization as a ratio (0.0-1.0). Returns NaN if not started.
      Returns:
      the pumper utilization
    • setPumperMaxThreads

      public static void setPumperMaxThreads(int value)
      The cap on how many gateway pumper threads may run.
      Parameters:
      value - thread count, clamped to [2, 16]
    • adjustPumperThreads

      public static void adjustPumperThreads(int value)
      Change the thread count of the running pumper instance.
      Parameters:
      value - desired thread count, applied to the live instance
    • setMaxObMsgsPerPump

      public static void setMaxObMsgsPerPump(int val)
      The cap on messages a single outbound pump pass may handle.
      Parameters:
      val - messages per pump, clamped to [8, 1024]
    • getMaxIbMsgsPerPump

      public static int getMaxIbMsgsPerPump()
      The cap on messages a single inbound pump pass may handle.
      Returns:
      the max inbound messages per pump
    • setMaxIbMsgsPerPump

      public static void setMaxIbMsgsPerPump(int val)
      The cap on messages a single inbound pump pass may handle.
      Parameters:
      val - messages per pump, clamped to [8, 1024]