net.i2p.router.transport.ntcp

## Class NTCPTransport

- java.lang.Object
- - net.i2p.router.transport.TransportImpl
  - - net.i2p.router.transport.ntcp.NTCPTransport

- All Implemented Interfaces:
    Transport

      public class NTCPTransport
      extends TransportImpl

  Non-blocking TCP (NTCP) transport implementation for I2P. This class provides the primary TCP-based transport for I2P communication using Java NIO for non-blocking I/O operations. It supports both NTCP 1 and NTCP 2 protocols with advanced features like connection pooling, bandwidth management, and sophisticated peer management. Protocol Features:
  - NTCP 1: Basic encrypted TCP transport
  - NTCP 2: Enhanced protocol with improved efficiency
  - Configurable bandwidth limits and throttling
  - Connection pooling and reuse
  - IPv4 and IPv6 support
  - Automatic protocol negotiation
  Architecture:
  - Non-blocking I/O with NIO channels
  - Separate reader and writer threads
  - Event-driven message processing
  - Connection state machines for establishment
  - Peer reputation and cost-based routing
  Connection Management:
  - Multiple bid tiers (fast, slow, high-cost)
  - Connection pooling and reuse
  - Automatic failover and retry logic
  - Peer blacklisting and banlist support

- - ### Nested Class Summary

    - ### Nested classes/interfaces inherited from interface net.i2p.router.transport.Transport

      `Transport.AddressSource`

  - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `static int` | `ESTABLISH_TIMEOUT` how long from initial connection attempt (accept() or connect()) until the con must be established to avoid premature close()ing
    `static String` | `MIN_SIGTYPE_VERSION` RI sigtypes supported in 0.9.16
    `(package private) static int` | `NTCP2_INT_VERSION`
    `(package private) static String` | `NTCP2_VERSION` "2"
    `(package private) static String` | `NTCP2_VERSION_ALT` "2,"
    `static String` | `PROP_BIND_INTERFACE` this is rarely if ever used, default is to bind to wildcard address
    `static String` | `PROP_I2NP_NTCP_AUTO_IP`
    `static String` | `PROP_I2NP_NTCP_AUTO_PORT`
    `static String` | `PROP_I2NP_NTCP_HOSTNAME`
    `static String` | `PROP_I2NP_NTCP_PORT`
    `static String` | `PROP_NTCP2_IV` b64 static IV
    `static String` | `PROP_NTCP2_SP` b64 static private key
    `static String` | `STYLE`
    `static String` | `STYLE2`

    - ### Fields inherited from class net.i2p.router.transport.TransportImpl

      `_context, ADJUST_COST, CAP_IPV4, CAP_IPV4_IPV6, CAP_IPV6, CONGESTION_COST_ADJUSTMENT, PROP_BOOST_CONNECTION_LIMITS, PROP_IPV6_FIREWALLED`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `NTCPTransport(RouterContext ctx, X25519KeyFactory xdh)`

  - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `afterSend(OutNetMessage msg, boolean sendSuccessful, boolean allowRequeue, long msToSend)` The transport is done sending this message.
    `boolean` | `allowConnection()`
    `TransportBid` | `bid(RouterInfo toAddress, int dataSize)` Request to send a message to the specified router.
    `int` | `countActivePeers()` How many peers have we talked to in the last minute? As of 0.9.20, actually returns active peer count, not total.
    `int` | `countActiveSendPeers()` How many peers are we actively sending messages to (this minute)
    `int` | `countPeers()` How many peers are we connected to?
    `(package private) void` | `establishing(NTCPConnection con)` add us to the establishment timeout process
    `(package private) void` | `expireTimedOut()` called in the EventPumper no more than once a second or so, closing any unconnected/unestablished connections
    `void` | `externalAddressReceived(Transport.AddressSource source, byte[] ip, int port)` UDP changed addresses, tell NTCP and (possibly) restart
    `void` | `externalAddressRemoved(Transport.AddressSource source, boolean ipv6)` Notify a transport of an external address change.
    `void` | `forceDisconnect(Hash peer)` Tell the transport to disconnect from this peer.
    `void` | `forwardPortStatus(byte[] ip, int port, int externalPort, boolean success, String reason)` If we didn't used to be forwarded, and we have an address, and we are configured to use UPnP, update our RouterAddress Don't do anything now.
    `String` | `getAltStyle()` An alternate supported style
    `List<Long>` | `getClockSkews()` Return our peer clock skews on this transport.
    `List<Hash>` | `getEstablished()` Connected peers.
    `(package private) byte[]` | `getNTCP2StaticIV()` The static IV
    `(package private) byte[]` | `getNTCP2StaticPrivkey()` The static priv key
    `(package private) byte[]` | `getNTCP2StaticPubkey()` The static priv key
    `int[]` | `getPeerCounts()` Get detailed peer count statistics by IP version and direction.
    `Collection<NTCPConnection>` | `getPeers()` For /peers UI only.
    `(package private) EventPumper` | `getPumper()` Hook for NTCPConnection
    `CommSystemFacade.Status` | `getReachabilityStatus()` Maybe we should trust UPnP here and report OK if it opened the port, but for now we don't.
    `(package private) Reader` | `getReader()` Hook for NTCPConnection
    `int` | `getRequestedPort()` What INTERNAL port would the transport like to have forwarded by UPnP.
    `String` | `getStyle()` Get the unique style identifier for this transport.
    `(package private) Writer` | `getWriter()` Hook for NTCPConnection
    `(package private) X25519KeyFactory` | `getXDHFactory()`
    `(package private) NTCPConnection` | `inboundEstablished(NTCPConnection con)` Registers a newly established inbound connection, replacing any existing connection for the same peer.
    `boolean` | `isAlive()`
    `boolean` | `isBacklogged(Hash dest)`
    `boolean` | `isEstablished(Hash dest)`
    `(package private) boolean` | `isHXHIValid(byte[] hxhi)` Incoming connection replay detection.
    `void` | `mayDisconnect(Hash peer)` Tell the transport that we may disconnect from this peer.
    `protected void` | `outboundMessageReady()` Processes the next outbound message by retrieving or creating a connection, preparing it for sending, and handling related failures or bans.
    `(package private) NTCPConnection` | `removeCon(NTCPConnection con)`
    `(package private) void` | `sendComplete(OutNetMessage msg)` queue up afterSend call, which can take some time w/ jobs, etc
    `(package private) void` | `setLastBadSkew(long skew)` A positive number means our clock is ahead of theirs.
    `void` | `startListening()` Starts the NTCP transport listening process, ensuring only one pumper is running by checking existing state since the caller may not stop the transport correctly.
    `void` | `stopListening()` This doesn't (completely) block, caller should check isAlive() before calling startListening() or restartListening()

    - ### Methods inherited from class net.i2p.router.transport.TransportImpl

      `_t, _t, afterSend, afterSend, afterSend, allowLocal, getCurrentAddress, getCurrentAddresses, getIP, getIPv6Config, getMaxConnections, getMostRecentErrorMessages, getNextMessage, getSavedLocalAddresses, getTargetAddresses, getTransportMaxConnections, hasCurrentAddress, haveCapacity, haveCapacity, isIPv4Firewalled, isIPv6Firewalled, isPubliclyRoutable, isUnreachable, markReachable, markUnreachable, messageReceived, ngettext, removeAddress, removeAddress, renderStatusHTML, renderStatusHTML, replaceAddress, saveLocalAddress, send, setIP, setListener, updateAddress, wasUnreachable`

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Field Detail

    - #### ESTABLISH_TIMEOUT

          public static final int ESTABLISH_TIMEOUT

      how long from initial connection attempt (accept() or connect()) until the con must be established to avoid premature close()ing
      See Also:
        Constant Field Values

    - #### MIN_SIGTYPE_VERSION

          public static final String MIN_SIGTYPE_VERSION

      RI sigtypes supported in 0.9.16
      See Also:
        Constant Field Values

    - #### NTCP2_INT_VERSION

          static final int NTCP2_INT_VERSION

      See Also:
        Constant Field Values

    - #### NTCP2_VERSION

          static final String NTCP2_VERSION

      "2"

    - #### NTCP2_VERSION_ALT

          static final String NTCP2_VERSION_ALT

      "2,"

    - #### PROP_BIND_INTERFACE

          public static final String PROP_BIND_INTERFACE

      this is rarely if ever used, default is to bind to wildcard address
      See Also:
        Constant Field Values

    - #### PROP_I2NP_NTCP_AUTO_IP

          public static final String PROP_I2NP_NTCP_AUTO_IP

      See Also:
        Constant Field Values

    - #### PROP_I2NP_NTCP_AUTO_PORT

          public static final String PROP_I2NP_NTCP_AUTO_PORT

      See Also:
        Constant Field Values

    - #### PROP_I2NP_NTCP_HOSTNAME

          public static final String PROP_I2NP_NTCP_HOSTNAME

      See Also:
        Constant Field Values

    - #### PROP_I2NP_NTCP_PORT

          public static final String PROP_I2NP_NTCP_PORT

      See Also:
        Constant Field Values

    - #### PROP_NTCP2_IV

          public static final String PROP_NTCP2_IV

      b64 static IV
      See Also:
        Constant Field Values

    - #### PROP_NTCP2_SP

          public static final String PROP_NTCP2_SP

      b64 static private key
      See Also:
        Constant Field Values

    - #### STYLE

          public static final String STYLE

      See Also:
        Constant Field Values

    - #### STYLE2

          public static final String STYLE2

      See Also:
        Constant Field Values

  - ### Constructor Detail

    - #### NTCPTransport

          public NTCPTransport(RouterContext ctx,
                               X25519KeyFactory xdh)

      Parameters:
        `xdh` - null to disable NTCP2

  - ### Method Detail

    - #### afterSend

          public void afterSend(OutNetMessage msg,
                                boolean sendSuccessful,
                                boolean allowRequeue,
                                long msToSend)

      Description copied from class: `TransportImpl`
      The transport is done sending this message. This is the method that actually does all of the cleanup - firing off jobs, requeueing, updating stats, etc.
      Overrides:
        `afterSend` in class `TransportImpl`
      Parameters:
        `msg` - message in question
        `sendSuccessful` - true if the peer received it
        `allowRequeue` - true if we should try other transports if available
        `msToSend` - how long it took to transfer the data to the peer

    - #### allowConnection

          public boolean allowConnection()

    - #### bid

          public TransportBid bid(RouterInfo toAddress,
                                  int dataSize)

      Description copied from interface: `Transport`
      Request to send a message to the specified router. This method allows the transport to evaluate whether it can and wants to send a message to the target router. The transport may decline based on current load, peer reputation, or transport-specific constraints.
      Parameters:
        `toAddress` - the target router's contact information
        `dataSize` - size of message payload, assumes full 16-byte header, transports should adjust as necessary for their overhead
      Returns:
        a TransportBid containing send details, or null if unwilling to send

    - #### countActivePeers

          public int countActivePeers()

      How many peers have we talked to in the last minute? As of 0.9.20, actually returns active peer count, not total.
      Specified by:
        `countActivePeers` in interface `Transport`
      Specified by:
        `countActivePeers` in class `TransportImpl`

    - #### countActiveSendPeers

          public int countActiveSendPeers()

      How many peers are we actively sending messages to (this minute)
      Specified by:
        `countActiveSendPeers` in interface `Transport`
      Specified by:
        `countActiveSendPeers` in class `TransportImpl`

    - #### countPeers

          public int countPeers()

      Description copied from class: `TransportImpl`
      How many peers are we connected to?
      Specified by:
        `countPeers` in interface `Transport`
      Specified by:
        `countPeers` in class `TransportImpl`

    - #### establishing

          void establishing(NTCPConnection con)

      add us to the establishment timeout process

    - #### expireTimedOut

          void expireTimedOut()

      called in the EventPumper no more than once a second or so, closing any unconnected/unestablished connections

    - #### externalAddressReceived

          public void externalAddressReceived(Transport.AddressSource source,
                                              byte[] ip,
                                              int port)

      UDP changed addresses, tell NTCP and (possibly) restart
      Specified by:
        `externalAddressReceived` in interface `Transport`
      Specified by:
        `externalAddressReceived` in class `TransportImpl`
      Parameters:
        `ip` - typ. IPv4 or IPv6 non-local; may be null to indicate IPv4 failure or port info only
        `source` - defined in Transport.java
        `port` - 0 for unknown or unchanged

    - #### externalAddressRemoved

          public void externalAddressRemoved(Transport.AddressSource source,
                                             boolean ipv6)

      Notify a transport of an external address change. This may be from a local interface, UPnP, a config change, etc. This should not be called if the ip didn't change (from that source's point of view), or is a local address. May be called multiple times for IPv4 or IPv6. The transport should also do its own checking on whether to accept notifications from this source. This can be called after the transport is running. TODO externalAddressRemoved(source, ip, port)
      Specified by:
        `externalAddressRemoved` in interface `Transport`
      Overrides:
        `externalAddressRemoved` in class `TransportImpl`
      Parameters:
        `source` - defined in Transport.java
        `ipv6` - true for IPv6, false for IPv4

    - #### forceDisconnect

          public void forceDisconnect(Hash peer)

      Tell the transport to disconnect from this peer.
      Parameters:
        `peer` - hash of the peer to forcefully disconnect from

    - #### forwardPortStatus

          public void forwardPortStatus(byte[] ip,
                                        int port,
                                        int externalPort,
                                        boolean success,
                                        String reason)

      If we didn't used to be forwarded, and we have an address, and we are configured to use UPnP, update our RouterAddress Don't do anything now. If it fails, we don't know if it's because there is no firewall, or if the firewall rejected the request. So we just use the SSU reachability status to decide whether to enable inbound NTCP. SSU will have CSFI build a new NTCP address when it transitions to OK.
      Specified by:
        `forwardPortStatus` in interface `Transport`
      Overrides:
        `forwardPortStatus` in class `TransportImpl`
      Parameters:
        `ip` - may be null
        `port` - the internal port
        `externalPort` - the external port, which for now should always be the same as the internal port if the forwarding was successful.

    - #### getAltStyle

          public String getAltStyle()

      An alternate supported style
      Overrides:
        `getAltStyle` in class `TransportImpl`
      Returns:
        "NTCP2" always

    - #### getClockSkews

          public List<Long> getClockSkews()

      Return our peer clock skews on this transport. List composed of Long, each element representing a peer skew in seconds. A positive number means our clock is ahead of theirs.
      Specified by:
        `getClockSkews` in interface `Transport`
      Overrides:
        `getClockSkews` in class `TransportImpl`
      Returns:
        list of clock skew measurements in milliseconds, may be empty if no measurements available

    - #### getEstablished

          public List<Hash> getEstablished()

      Connected peers.
      Returns:
        a copy, modifiable

    - #### getNTCP2StaticIV

          byte[] getNTCP2StaticIV()

      The static IV

    - #### getNTCP2StaticPrivkey

          byte[] getNTCP2StaticPrivkey()

      The static priv key

    - #### getNTCP2StaticPubkey

          byte[] getNTCP2StaticPubkey()

      The static priv key

    - #### getPeerCounts

          public int[] getPeerCounts()

      Description copied from interface: `Transport`
      Get detailed peer count statistics by IP version and direction. This method returns an array containing peer counts broken down by IP version and connection direction. This provides detailed visibility into transport usage patterns and network composition. Array Format:
      - Version 1 (8 bytes): IPv4 inbound/outbound counts
      - Version 2 (8 bytes): IPv4 inbound/outbound, IPv6 inbound/outbound counts
      Returns:
        8 bytes: version 1 4 bytes all zeros version 2 ipv4 in/out, ipv6 in/out

    - #### getPeers

          public Collection<NTCPConnection> getPeers()

      For /peers UI only. Not a public API, not for external use.
      Returns:
        not a copy, do not modify

    - #### getPumper

          EventPumper getPumper()

      Hook for NTCPConnection

    - #### getReachabilityStatus

          public CommSystemFacade.Status getReachabilityStatus()

      Maybe we should trust UPnP here and report OK if it opened the port, but for now we don't. Just go through and if we have one inbound connection, we must be good. As we drop idle connections pretty quickly, this will be fairly accurate. We have to be careful here because much of the router console code assumes that the reachability status is really just the UDP status. This only returns OK, DISABLED, or UNKNOWN for IPv4 and IPv6. We leave the FIREWALLED status for UDP. Previously returned short, now enum as of 0.9.20
      Specified by:
        `getReachabilityStatus` in interface `Transport`
      Specified by:
        `getReachabilityStatus` in class `TransportImpl`
      Returns:
        current reachability status indicating transport's network accessibility

    - #### getReader

          Reader getReader()

      Hook for NTCPConnection

    - #### getRequestedPort

          public int getRequestedPort()

      Description copied from class: `TransportImpl`
      What INTERNAL port would the transport like to have forwarded by UPnP. This can't be passed via getCurrentAddress(), as we have to open the port before we can publish the address, and that's the external port anyway.
      Specified by:
        `getRequestedPort` in interface `Transport`
      Overrides:
        `getRequestedPort` in class `TransportImpl`
      Returns:
        current IPv4 port, else NTCP configured port, else -1 (but not UDP port if auto)

    - #### getStyle

          public String getStyle()

      Description copied from interface: `Transport`
      Get the unique style identifier for this transport. This method returns a string that uniquely identifies the transport type (e.g., "NTCP", "UDP", "SSU"). This is used for configuration, logging, and transport selection.
      Returns:
        always "NTCP"

    - #### getWriter

          Writer getWriter()

      Hook for NTCPConnection

    - #### getXDHFactory

          X25519KeyFactory getXDHFactory()

      Returns:
        null if not configured for NTCP2

    - #### inboundEstablished

          NTCPConnection inboundEstablished(NTCPConnection con)

      Registers a newly established inbound connection, replacing any existing connection for the same peer. Updates reachability status and connection statistics.
      Parameters:
        `con` - The newly established NTCPConnection.
      Returns:
        The previous NTCPConnection to the same peer if one existed, or null otherwise.

    - #### isAlive

          public boolean isAlive()

    - #### isBacklogged

          public boolean isBacklogged(Hash dest)

      Specified by:
        `isBacklogged` in interface `Transport`
      Overrides:
        `isBacklogged` in class `TransportImpl`

    - #### isEstablished

          public boolean isEstablished(Hash dest)

      Specified by:
        `isEstablished` in interface `Transport`
      Overrides:
        `isEstablished` in class `TransportImpl`

    - #### isHXHIValid

          boolean isHXHIValid(byte[] hxhi)

      Incoming connection replay detection. As there is no timestamp in the first message, we can't detect something long-delayed. To be fixed in next version of NTCP.
      Parameters:
        `hxhi` - using first 8 bytes only
      Returns:
        valid

    - #### mayDisconnect

          public void mayDisconnect(Hash peer)

      Tell the transport that we may disconnect from this peer. This is advisory only.
      Specified by:
        `mayDisconnect` in interface `Transport`
      Overrides:
        `mayDisconnect` in class `TransportImpl`
      Parameters:
        `peer` - hash of the peer that may be disconnected

    - #### outboundMessageReady

          protected void outboundMessageReady()

      Processes the next outbound message by retrieving or creating a connection, preparing it for sending, and handling related failures or bans.
      Specified by:
        `outboundMessageReady` in class `TransportImpl`

    - #### removeCon

          NTCPConnection removeCon(NTCPConnection con)

      Returns:
        usually the con passed in, but possibly a second connection with the same peer... only con or null as of 0.9.37

    - #### sendComplete

          void sendComplete(OutNetMessage msg)

      queue up afterSend call, which can take some time w/ jobs, etc

    - #### setLastBadSkew

          void setLastBadSkew(long skew)

      A positive number means our clock is ahead of theirs.
      Parameters:
        `skew` - in seconds

    - #### startListening

          public void startListening()

      Starts the NTCP transport listening process, ensuring only one pumper is running by checking existing state since the caller may not stop the transport correctly. It configures and binds local addresses, handles firewall and network interface settings, and sets fallback addresses as needed. This method is synchronized to prevent concurrent starts.

    - #### stopListening

          public void stopListening()

      This doesn't (completely) block, caller should check isAlive() before calling startListening() or restartListening()