java.lang.Object
net.i2p.router.client.ClientConnectionRunner
Direct Known Subclasses:
QueuedClientConnectionRunner

class ClientConnectionRunnerextends Object
Bridge the router and the client - managing state for a client.

As of release 0.9.21, multiple sessions are supported on a single I2CP connection. These sessions share tunnels and some configuration.

  • Field Details

    • _log

      protected final Log _log
      Logger for the runner.
    • _context

      protected final RouterContext _context
      Router context.
    • _manager

      protected final ClientManager _manager
      Client manager managing this runner.
    • _reader

      protected I2CPMessageReader _reader
      Reads and processes incoming I2CP messages from the client.
  • Constructor Details

    • ClientConnectionRunner

      public ClientConnectionRunner(RouterContext context, ClientManager manager, Socket socket)
      Create a new runner against the given socket.
      Parameters:
      context - the router context
      manager - the client manager
      socket - the I2CP socket
  • Method Details

    • startRunning

      public void startRunning() throws IOException
      Actually run the connection - listen for I2CP messages and respond. This is the main driver for this class, though it gets all its meat from the I2CPMessageReader.
      Throws:
      IOException - if the socket I/O fails
    • createListener

      protected I2CPMessageReader.I2CPMessageEventListener createListener()
      Allow override for testing.
      Returns:
      the message event listener
    • stopRunning

      public void stopRunning()
      Die a horrible death. Cannot be restarted.
    • getAddress

      public InetAddress getAddress()
      The address of the client socket.
      Returns:
      the client's InetAddress
    • getConfig

      public SessionConfig getConfig(Hash h)
      Current client's config, will be null if session not found IS subsession aware.
      Parameters:
      h - the session hash
      Returns:
      the config, or null if session not found
    • getConfig

      public SessionConfig getConfig(SessionId id)
      Current client's config, will be null if session not found IS subsession aware. Returns null if id is null.
      Parameters:
      id - the session id
      Returns:
      the config, or null if not found or id is null
    • getPrimaryConfig

      public SessionConfig getPrimaryConfig()
      Primary client's config, will be null if session not set up.
      Returns:
      the primary config, or null if not set up
    • setClientVersion

      public void setClientVersion(String version)
      The client version.
      Parameters:
      version - the client version string
    • getClientVersion

      public String getClientVersion()
      The client version.
      Returns:
      null if unknown or less than 0.8.7
    • getSessionKeyManager

      public SessionKeyManager getSessionKeyManager()
      The current client's SessionKeyManager. As of 0.9.44, returned implementation varies based on supported encryption types.
      Returns:
      the session key manager
    • getLeaseSet

      public LeaseSet getLeaseSet(Hash h)
      Currently allocated leaseSet. IS subsession aware. Returns primary leaseset only.
      Parameters:
      h - the session hash
      Returns:
      leaseSet or null if not yet set or unknown hash
    • getDestHash

      public Hash getDestHash()
      Equivalent to getConfig().getDestination().calculateHash(); will be null before session is established Not subsession aware. Returns primary session hash. Don't use if you can help it.
      Returns:
      primary hash or null if not yet set
    • getDestHash

      public Hash getDestHash(SessionId id)
      Return the hash for the given ID.
      Parameters:
      id - the session id
      Returns:
      hash or null if unknown
    • getDestination

      public Destination getDestination(SessionId id)
      Return the dest for the given ID.
      Parameters:
      id - the session id
      Returns:
      dest or null if unknown
    • getSessionId

      SessionId getSessionId(Hash h)
      Subsession aware.
      Parameters:
      h - the local target
      Returns:
      current client's sessionId or null if not yet set or not a valid hash
    • getSessionIds

      List<SessionId> getSessionIds()
      Subsession aware.
      Returns:
      all current client's sessionIds, non-null
    • getDestinations

      List<Destination> getDestinations()
      Subsession aware.
      Returns:
      all current client's destinations, non-null
    • setSessionId

      void setSessionId(Hash hash, SessionId id)
      To be called only by ClientManager.
      Parameters:
      hash - for the session
      id - the session id to set
      Throws:
      IllegalStateException - if already set
    • removeSession

      void removeSession(SessionId id)
      Kill the session. Caller must kill runner if none left. If the session is primary and there are subsessions, this removes all subsessions also.
      Parameters:
      id - the session id to remove
    • getLeaseRequest

      LeaseRequestState getLeaseRequest(Hash h)
      Data for the current leaseRequest, or null if there is no active leaseSet request. Not subsession aware. Returns primary ID only.
      Parameters:
      h - the session hash
      Returns:
      the lease request state, or null if none
    • failLeaseRequest

      public void failLeaseRequest(LeaseRequestState req)
      Fail the given lease request and track consecutive failures. The counter decays after LEASE_FAIL_DECAY_MS of no failures, so a brief I2CP stall does not permanently prime a disconnect. Counter resets to zero on successful LeaseSet receipt. All null states (request, requested LeaseSet, or its destination) are guarded before any dereference; RequestLeaseSetJob calls this with a null LeaseSet or null destination on its early-failure paths.
      Parameters:
      req - the failed request, or null to ignore
    • isDead

      boolean isDead()
      Already closed?
      Returns:
      true if the runner is dead
    • getPayload

      Payload getPayload(MessageId id)
      Only call if _dontSendMSMOnReceive is false, otherwise will always be null.
      Parameters:
      id - the message id
      Returns:
      the payload, or null
    • setPayload

      void setPayload(MessageId id, Payload payload)
      Only call if _dontSendMSMOnReceive is false.
      Parameters:
      id - the message id
      payload - the payload to store
    • removePayload

      void removePayload(MessageId id)
      Only call if _dontSendMSMOnReceive is false.
      Parameters:
      id - the message id to remove
    • sessionEstablished

      public int sessionEstablished(SessionConfig config)
      Caller must send a SessionStatusMessage to the client with the returned code. Caller must call disconnectClient() on failure. Side effect: Sets the session ID.
      Parameters:
      config - the session config
      Returns:
      SessionStatusMessage return code, 1 for success, != 1 for failure
    • updateMessageDeliveryStatus

      void updateMessageDeliveryStatus(Destination dest, MessageId id, long messageNonce, int status)
      Send a notification to the client that their message (id specified) was delivered (or failed delivery) Note that this sends the Guaranteed status codes, even though we only support best effort. Doesn't do anything if i2cp.messageReliability = "none"

      Do not use for status = STATUS_SEND_ACCEPTED; use ackSendMessage() for that.

      Parameters:
      dest - the client whose session is notified; no notification if it has none
      id - the router's ID for this message
      messageNonce - the client's ID for this message, greater than zero
      status - see I2CP MessageStatusMessage for success/failure codes
    • leaseSetCreated

      void leaseSetCreated(LeaseSet ls)
      Called after a new leaseSet is granted by the client and the NetworkDb has been updated. This takes care of all the LeaseRequestState stuff (including firing any jobs).
      Parameters:
      ls - if encrypted, the encrypted LS, not the decrypted one
    • registerEncryptedLS

      public boolean registerEncryptedLS(Hash hash)
      Call after destinationEstablished(), when an encrypted leaseset is created, so we know it's local. Add to the clients list. Check for a dup hash. Caller must call runner.disconnectClient() on failure.
      Parameters:
      hash - the location of the encrypted LS, will change every day
      Returns:
      success, false on dup
    • disconnectClient

      void disconnectClient(String reason)
      Send a DisconnectMessage and log with level Log.ERROR. This is always bad. See ClientMessageEventListener.handleCreateSession(CreateSessionMessage) for why we don't send a SessionStatusMessage when we do this.
      Parameters:
      reason - will be truncated to 255 bytes
    • disconnectClient

      void disconnectClient(String reason, int logLevel)
      Disconnect the client with the given reason and log level.
      Parameters:
      reason - will be truncated to 255 bytes
      logLevel - accepted but never read; the disconnect is logged at WARN
    • distributeMessage

      MessageId distributeMessage(SendMessageMessage message)
      Distribute the message. If the dest is local, it blocks until its passed to the target ClientConnectionRunner (which then fires it into a MessageReceivedJob). If the dest is remote, it blocks until it is added into the ClientMessagePool.
      Parameters:
      message - the message to distribute
      Returns:
      the message id assigned
    • ackSendMessage

      void ackSendMessage(SessionId sid, MessageId id, long nonce)
      Send a notification to the client that their message (id specified) was accepted for delivery (but not necessarily delivered) Doesn't do anything if i2cp.messageReliability = "none" or if the nonce is 0.
      Parameters:
      sid - the session id
      id - OUR id for the message
      nonce - HIS id for the message
    • receiveMessage

      boolean receiveMessage(Destination toDest, Destination fromDest, Payload payload)
      Synchronously deliver the message to the current runner

      Failure indication is available as of 0.9.29. Fails on e.g. queue overflow to client, client dead, etc.

      Parameters:
      toDest - non-null
      fromDest - generally null when from remote, non-null if from local
      payload - the payload to deliver
      Returns:
      true if the client was told about the message
    • receiveMessage

      boolean receiveMessage(Hash toHash, Destination fromDest, Payload payload)
      Synchronously deliver the message to the current runner

      Failure indication is available as of 0.9.29. Fails on e.g. queue overflow to client, client dead, etc.

      Parameters:
      toHash - non-null
      fromDest - generally null when from remote, non-null if from local
      payload - the payload to deliver
      Returns:
      true if a session existed for toHash and the client was told
    • reportAbuse

      public void reportAbuse(Destination dest, String reason, int severity)
      Send async abuse message to the client.
      Parameters:
      dest - the offending destination
      reason - the human-readable description of the abuse
      severity - the severity level
    • rerequestAfterTransientPublishFailure

      boolean rerequestAfterTransientPublishFailure(Destination dest)
      Re-queue the pending lease request after netdb publish() rejected the client's LeaseSet as expired (client clock skew or slow signing). The same LeaseRequestState is re-run so the session slot, callbacks, and deadline stay intact while the job recomputes lease end times against the current clock, instead of leaving the request to wait out the full timeout check. Bounded by LeaseRequestState.MAX_TRANSIENT_PUBLISH_RETRIES so a persistently skewed client cannot re-request forever.
      Parameters:
      dest - the session destination, null for no session
      Returns:
      true if a retry was queued
    • requestLeaseSet

      void requestLeaseSet(Hash h, LeaseSet set, long expirationTime, Job onCreateJob, Job onFailedJob)
      Request that a particular client authorize the Leases contained in the LeaseSet, after which the onCreateJob is queued up. If that doesn't occur within the timeout specified, queue up the onFailedJob. This call does not block.

      Job args are always null, may need some fixups if we start using them.

      Parameters:
      h - the Destination's hash
      set - LeaseSet with requested leases - this object must be updated to contain the signed version (as well as any changed/added/removed Leases) The LeaseSet contains Leases only, it is unsigned. Must be unique for this hash, do not reuse for subsessions.
      expirationTime - ms to wait before failing
      onCreateJob - Job to run after the LeaseSet is authorized, null OK
      onFailedJob - Job to run after the timeout passes without receiving authorization, null OK
    • disconnected

      void disconnected()
      The client was disconnected.
    • getIsDead

      boolean getIsDead()
      Check if the runner is dead.
      Returns:
      true if the runner is dead
    • writeMessage

      void writeMessage(I2CPMessage msg)
      Not thread-safe. Blocking. Only used for external sockets. ClientWriterRunner thread is the only caller. Others must use doSend().
      Parameters:
      msg - the message to write
    • doSend

      void doSend(I2CPMessage msg) throws I2CPMessageException
      Actually send the I2CPMessage to the peer through the socket.
      Parameters:
      msg - the message to send
      Throws:
      I2CPMessageException - if the message could not be sent
    • doSendWait

      void doSendWait(I2CPMessage msg, long timeoutMs) throws I2CPMessageException
      Send a message, allowing the transport up to timeoutMs to accept it.

      For messages whose loss costs more than a short wait. The default is doSend(I2CPMessage): a socket-backed runner hands the message to a writer thread that buffers it regardless, so there is nothing to wait for here. Subclasses that write straight into a bounded queue override this.

      Parameters:
      msg - the message to send
      timeoutMs - how long to wait for the transport to accept the message
      Throws:
      I2CPMessageException - if the message could not be sent
    • getNextMessageId

      public int getNextMessageId()
      Get the next message id.
      Returns:
      the next id
    • getFloodfillNetworkDatabaseFacade

      public FloodfillNetworkDatabaseFacade getFloodfillNetworkDatabaseFacade()
      The FloodfillNetworkDatabaseFacade for this runner, the client netDb.

      If a session has not been created yet, it will return null.

      Returns:
      the client netdb or null if no session was created yet