java.lang.Object
net.i2p.router.JobImpl
net.i2p.router.networkdb.kademlia.IntroducerLookupJob
All Implemented Interfaces:
Job

class IntroducerLookupJobextends JobImpl
Background maintenance job that keeps introducer RouterInfos warm in the local netDb.

Unreachable (U-cap) peers publish SSU2 introducers as router hashes (the "ih0".."ih4" options on their SSU/SSU2 addresses). When we need an inbound connection from such a peer - or need to reach one ourselves - EstablishmentManager looks up each introducer RI on demand; if the RI is not cached locally, establishment stalls while the search runs, and IntroductionManager must fall back to ad-hoc direct queries. This job reviews the introducers of known unreachable peers on a slow schedule and issues remote RouterInfo lookups for any introducer missing locally, so hole-punching has its prerequisites ready before a connection is attempted.

Pacing and politeness toward floodfills: a randomized 3-7 minute cycle whose query phase is capped at 30s wall time per cycle (no per-cycle count cap), at most MAX_CONCURRENT_LOOKUPS searches in flight, per-introducer exponential backoff after failures, and a dedup/backoff map shared across cycles (which also gates keys already covered by an overlapping search elsewhere). Each search inherits the standard adaptive RouterInfo lookup deadline used by peer lookups. Floodfill diversity is provided by the netdb selection layer itself: FloodfillPeerSelector shuffles candidates within quality tiers, skips floodfills queried in the last 60s (markQueried cooldown), and spreads same-/16 IP clusters, so repeated keys don't repeatedly land on the same floodfills and no single one sees enough volume to trigger throttling. Concurrent duplicate searches of the same key are additionally coalesced by IterativeSearchJob. SSU1 introducers carry no router hash (IP/port/intro-key only) and cannot be resolved by netDB lookup; they are skipped here and handled by the transport's existing IP-based introduction path.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private final Map<Hash,long[]>
    Introducer hash -> {last attempt time, consecutive failures}.
    The facade running the lookups.
    private final AtomicInteger
    Remote introducer searches currently in flight.
    private final Log
    Logger for this class.
    private static final int
    Prune threshold for the attempts map.
    private static final long
    Base delay between cycles, jittered ±CYCLE_JITTER before each requeue.
    private static final long
    Random spread added to or subtracted from the cycle delay, up to 2 minutes.
    private static final long
    Wall-time budget for one cycle's query phase: lookups are issued until this window closes (no per-cycle count cap), and each lookup's deadline is clamped to the budget left at issue time, so every query of a cycle completes within ~30s of cycle start.
    private static final long
    Base backoff after a failed lookup, doubling per consecutive failure.
    private static final int
    Maximum remote searches in flight during the query phase.
    private static final long
    Longest backoff after repeated failures - 6 hours.
    private static final int
    Introducer slots per address.
    private static final long
    Re-attempt gate while a lookup may still be in flight (fails == 0).
    private static final int
    Issue floor: IterativeSearchJob never lets the RouterInfo lookup maximum drop below 5s, so a search with less budget left is not worth issuing.
    private static final String
    SSU2 introducer router hash option prefix ("ih0".."ih4").
    private static final String
    Introducer relay tag option prefix ("itag0".."itag4"); required in every slot.
    private static final long
    Random spread of the first lookup after startup, up to 4 min.
    private static final long
    First run 8-12 minutes after startup: let the netdb fill from bootstrap first.

    Fields inherited from class JobImpl

    _id
    Modifier and Type
    Field
    Description
    final long
    Unique job identifier.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Constructor.
  • Method Summary

    Modifier and Type
    Method
    Description
    (package private) static long
    backoffMillis(int fails)
    Retry backoff for an introducer whose last lookup failed fails consecutive times: 0 (in flight / find pending) → MIN_RETRY_MS; 1+ → FAIL_BACKOFF_MS doubling per failure, capped at MAX_FAIL_BACKOFF_MS.
    (package private) static boolean
    canAttempt(long now, long[] state)
    Gate for issuing a lookup now: true when never attempted, or when the elapsed time since the last attempt meets the state's backoff.
    (package private) static List<Hash>
    Extract SSU2 introducer router hashes ("ih0".."ih4") from the given addresses.
    Descriptive name of the task.
    (package private) static int
    issueTimeout(long remainingBudgetMs, int adaptiveCapMs)
    Deadline for one issued lookup: the standard adaptive RouterInfo lookup cap (the same deadline peer/transit next-hop lookups get), never extended past this cycle's remaining query budget, and zero when too little budget remains to fund a useful search.
    (package private) static boolean
    Whether the peer publishes the unreachable capability ('U'), i.e.
    private long
    Next cycle delay: CYCLE_INTERVAL with uniform ±CYCLE_JITTER.
    (package private) static Hash
    Decode an "ih{i}" option value into a Hash: Base64 of exactly 32 bytes, else null.
    private void
    pruneAttempts(long now)
    Bound the attempts map: drop entries whose last attempt predates the maximum possible backoff window (they would fail canAttempt(long, long[]) as eligible anyway and would be recreated fresh).
    private void
    requestLookup(RouterContext ctx, Hash h, long now, int timeoutMs)
    Record the attempt and issue one non-blocking remote RI lookup with the given deadline (never past this cycle's query budget, never above the standard adaptive RouterInfo lookup cap).
    void
    Actually perform the task.

    Methods inherited from class JobImpl

    dropped, getContext, getJobId, getMadeReadyOn, getTiming, madeReady, requeue, toString
    Modifier and Type
    Method
    Description
    void
    Default implementation does nothing.
    The router context that this job belongs to.
    long
    The unique job ID for this job.
    long
    The timestamp when this job was last made ready for execution.
    The timing object for this job.
    void
    madeReady(long now)
    For JobQueue only, not for external use.
    protected void
    requeue(long delayMs)
    Requeue this job to run after the specified delay.
     

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
  • Field Details

    • _log

      private final Log _log
      Logger for this class.
    • _facade

      private final FloodfillNetworkDatabaseFacade _facade
      The facade running the lookups.
    • _attempts

      private final Map<Hash,long[]> _attempts
      Introducer hash -> {last attempt time, consecutive failures}. Entries are removed on lookup success and pruned when oversized.
    • _inFlight

      private final AtomicInteger _inFlight
      Remote introducer searches currently in flight.
    • CYCLE_INTERVAL

      private static final long CYCLE_INTERVAL
      Base delay between cycles, jittered ±CYCLE_JITTER before each requeue.
      See Also:
    • CYCLE_JITTER

      private static final long CYCLE_JITTER
      Random spread added to or subtracted from the cycle delay, up to 2 minutes.
      See Also:
    • STARTUP_DELAY_MIN

      private static final long STARTUP_DELAY_MIN
      First run 8-12 minutes after startup: let the netdb fill from bootstrap first.
      See Also:
    • STARTUP_DELAY_JITTER

      private static final long STARTUP_DELAY_JITTER
      Random spread of the first lookup after startup, up to 4 min.
      See Also:
    • CYCLE_QUERY_BUDGET_MS

      private static final long CYCLE_QUERY_BUDGET_MS
      Wall-time budget for one cycle's query phase: lookups are issued until this window closes (no per-cycle count cap), and each lookup's deadline is clamped to the budget left at issue time, so every query of a cycle completes within ~30s of cycle start.
      See Also:
    • MAX_CONCURRENT_LOOKUPS

      private static final int MAX_CONCURRENT_LOOKUPS
      Maximum remote searches in flight during the query phase.
      See Also:
    • MIN_USEFUL_TIMEOUT_MS

      private static final int MIN_USEFUL_TIMEOUT_MS
      Issue floor: IterativeSearchJob never lets the RouterInfo lookup maximum drop below 5s, so a search with less budget left is not worth issuing.
      See Also:
    • MIN_RETRY_MS

      private static final long MIN_RETRY_MS
      Re-attempt gate while a lookup may still be in flight (fails == 0).
      See Also:
    • FAIL_BACKOFF_MS

      private static final long FAIL_BACKOFF_MS
      Base backoff after a failed lookup, doubling per consecutive failure.
      See Also:
    • MAX_FAIL_BACKOFF_MS

      private static final long MAX_FAIL_BACKOFF_MS
      Longest backoff after repeated failures - 6 hours.
      See Also:
    • ATTEMPT_MAP_MAX

      private static final int ATTEMPT_MAP_MAX
      Prune threshold for the attempts map.
      See Also:
    • MAX_INTRO_SLOTS

      private static final int MAX_INTRO_SLOTS
      Introducer slots per address. Mirrors UDPAddress.MAX_INTRODUCERS, which is package-private in the transport package.
      See Also:
    • PROP_INTRO_TAG_PREFIX

      private static final String PROP_INTRO_TAG_PREFIX
      Introducer relay tag option prefix ("itag0".."itag4"); required in every slot.
      See Also:
    • PROP_INTRO_HASH_PREFIX

      private static final String PROP_INTRO_HASH_PREFIX
      SSU2 introducer router hash option prefix ("ih0".."ih4").
      See Also:
  • Constructor Details

    • IntroducerLookupJob

      public IntroducerLookupJob(RouterContext ctx, FloodfillNetworkDatabaseFacade facade)
      Constructor. Sets the staggered initial start time.
      Parameters:
      ctx - the router context
      facade - the floodfill network database facade
  • Method Details

    • getName

      public String getName()
      Description copied from interface: Job
      Descriptive name of the task.
      Returns:
      the descriptive name of the task
    • runJob

      public void runJob()
      Description copied from interface: Job
      Actually perform the task. This call blocks until the Job is complete.
    • requestLookup

      private void requestLookup(RouterContext ctx, Hash h, long now, int timeoutMs)
      Record the attempt and issue one non-blocking remote RI lookup with the given deadline (never past this cycle's query budget, never above the standard adaptive RouterInfo lookup cap). Success clears the tracking entry (the RI is then cached locally and expires through the normal netdb lifecycle). Failure increments the consecutive-failure count, which lengthens the retry backoff. Both outcomes release a concurrency slot.
      Parameters:
      ctx - the router context for the lookup jobs
      h - hash of the peer whose RouterInfo is to be looked up
      now - the current time in ms, recorded as the attempt timestamp
      timeoutMs - lookup deadline in ms for this attempt
    • nextInterval

      private long nextInterval(RouterContext ctx)
      Next cycle delay: CYCLE_INTERVAL with uniform ±CYCLE_JITTER.
      Parameters:
      ctx - the router context supplying the random source
      Returns:
      the delay in ms until the next lookup cycle
    • pruneAttempts

      private void pruneAttempts(long now)
      Bound the attempts map: drop entries whose last attempt predates the maximum possible backoff window (they would fail canAttempt(long, long[]) as eligible anyway and would be recreated fresh).
      Parameters:
      now - the current time in ms, used for the age cutoff
    • isUnreachablePeer

      static boolean isUnreachablePeer(RouterInfo ri)
      Whether the peer publishes the unreachable capability ('U'), i.e. it is firewalled / cannot accept unsolicited connections and therefore relies on introducers for inbound connectivity.
      Parameters:
      ri - the peer's RouterInfo (non-null)
      Returns:
      true if the capabilities string contains 'U'
    • getIntroducerHashes

      static List<Hash> getIntroducerHashes(Collection<RouterAddress> addresses)
      Extract SSU2 introducer router hashes ("ih0".."ih4") from the given addresses. An introducer slot exists only if its required relay tag option ("itag{i}") is present; SSU1-only slots (ihost/iport/ikey with no "ih") carry no hash and yield nothing. Duplicates removed. Pure decision — no context access, safe for unit tests.
      Parameters:
      addresses - the peer's transport addresses, may be null or empty
      Returns:
      the introducer hashes, never null
    • parseIntroducerHash

      static Hash parseIntroducerHash(String b64)
      Decode an "ih{i}" option value into a Hash: Base64 of exactly 32 bytes, else null. Pure decision — safe for unit tests.
      Parameters:
      b64 - the option value, may be null
      Returns:
      the hash, or null if absent/malformed
    • backoffMillis

      static long backoffMillis(int fails)
      Retry backoff for an introducer whose last lookup failed fails consecutive times: 0 (in flight / find pending) → MIN_RETRY_MS; 1+ → FAIL_BACKOFF_MS doubling per failure, capped at MAX_FAIL_BACKOFF_MS. Pure decision. Safe for unit tests.
      Parameters:
      fails - consecutive failed lookup attempts
      Returns:
      the backoff in milliseconds
    • canAttempt

      static boolean canAttempt(long now, long[] state)
      Gate for issuing a lookup now: true when never attempted, or when the elapsed time since the last attempt meets the state's backoff. Pure decision — safe for unit tests.
      Parameters:
      now - current time in milliseconds
      state - {last attempt time, consecutive failures}, or null
      Returns:
      true if a lookup may be attempted
    • issueTimeout

      static int issueTimeout(long remainingBudgetMs, int adaptiveCapMs)
      Deadline for one issued lookup: the standard adaptive RouterInfo lookup cap (the same deadline peer/transit next-hop lookups get), never extended past this cycle's remaining query budget, and zero when too little budget remains to fund a useful search. Pure decision — safe for unit tests.
      Parameters:
      remainingBudgetMs - ms left in this cycle's query phase
      adaptiveCapMs - current adaptive RouterInfo lookup deadline cap
      Returns:
      timeout in ms, or 0 when no useful lookup remains