net.i2p.router.transport.udp

## Class UDPTransport

- java.lang.Object
- - net.i2p.router.transport.TransportImpl
  - - net.i2p.router.transport.udp.UDPTransport

- All Implemented Interfaces:
    Transport

      public class UDPTransport
      extends TransportImpl

  Secure Semi-reliable UDP (SSU) transport implementation for I2P.

  This class provides the primary UDP-based transport for I2P communication, implementing both SSU1 (legacy) and SSU2 (modern) protocols. It handles peer connections, packet processing, session management, and reachability testing.

  Protocol Features:

  - Session establishment and maintenance
  - Inbound and outbound message handling
  - Peer introduction and testing systems
  - Reachability detection and reporting
  - IPv4 and IPv6 addressing support
  - Packet fragmentation and reassembly
  - Acknowledgment and reliability mechanisms

  Internal Architecture:

  - `EstablishmentManager` for session establishment
  - `PacketHandler` for processing incoming packets
  - `IntroductionManager` for managing introductions
  - `PeerTestManager` for reachability testing
  - Various state managers for connection tracking

  SSU Protocol Support:

  - SSU1: Legacy protocol for older peers
  - SSU2: Modern protocol with improved efficiency
  - Automatic protocol negotiation and fallback
  - Backward compatibility with existing peers

- - ### 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` | `DEFAULT_COST`
    `static String` | `DEFAULT_SOURCES`
    `static int` | `EXPIRE_TIMEOUT` We used to have MAX_IDLE_TIME = 5m, but this causes us to drop peers and lose the old introducer tags, causing introduction fails, so we keep the max time long to give the introducer keepalive code in the IntroductionManager a chance to work.
    `(package private) static long` | `INTRODUCER_EXPIRATION_MARGIN`
    `static int` | `MIN_EXPIRE_TIMEOUT`
    `static String` | `PROP_ALLOW_DIRECT` Do we allow direct SSU connections, sans introducers?
    `static String` | `PROP_BIND_INTERFACE` This is rarely if ever used, default is to bind to wildcard address
    `static String` | `PROP_EXTERNAL_HOST` define this to explicitly set an external IP address
    `static String` | `PROP_EXTERNAL_PORT` define this to explicitly set an external port
    `static String` | `PROP_FORCE_INTRODUCERS` Do we require introducers, regardless of our status?
    `static String` | `PROP_INTERNAL_PORT`
    `static String` | `PROP_INTRO_KEY`
    `static String` | `PROP_IP` remember IP changes
    `static String` | `PROP_IP_CHANGE`
    `static String` | `PROP_IPV6`
    `static String` | `PROP_LAPTOP_MODE`
    `static String` | `PROP_PREFER_UDP` If i2np.udp.preferred is set to "always", UDP bids will always be under the bid from the TCP transport - even if a TCP connection already exists.
    `static String` | `PROP_SOURCES` allowed sources of address updates
    `static String` | `PROP_SSU2_IKEY` b64 static IV
    `static String` | `PROP_SSU2_SP` b64 static private key
    `static int` | `PUBLIC_RELAY_COUNT` How many relays offered to us will we use at a time?
    `(package private) static long[]` | `RATES`
    `(package private) static int` | `SSU2_INT_VERSION`
    `(package private) static String` | `SSU2_VERSION` "2"
    `(package private) static String` | `SSU2_VERSION_ALT` "2,"
    `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
    `UDPTransport(RouterContext ctx, X25519KeyFactory xdh)`

  - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `(package private) void` | `addRecentlyClosed(PeerStateDestroyed peer)` Start listening for packets on a destroyed connection
    `(package private) boolean` | `addRemotePeerState(PeerState peer)` Adds a new peer state or replaces an existing one if the peer identity or address changes.
    `boolean` | `allowConnection()`
    `TransportBid` | `bid(RouterInfo toAddress, int dataSize)` Request to send a message to the specified router.
    `(package private) boolean` | `canIntroduce(boolean ipv6)` For EstablishmentManager.
    `(package private) boolean` | `canTestAsCharlie(boolean ipv6)` Can we be a Charlie right now?
    `(package private) void` | `changePeerAddress(PeerState2 peer, RemoteHostId newAddress)` Remove and add to peersByRemoteHost map
    `(package private) void` | `changePeerPort(PeerState peer, int newPort)` Remove and add to peersByRemoteHost map
    `int` | `countActivePeers()` How many peers are we currently connected to, that we have sent a message to or received a message from in the last five minutes.
    `int` | `countActiveSendPeers()` How many peers are we currently connected to, that we have sent a message to in the last minute.
    `int` | `countPeers()` How many peers are we connected to?
    `(package private) void` | `dropPeer(Hash peer, boolean shouldBanlist, String why)` This does not send a session destroy, caller must do that if desired.
    `(package private) void` | `dropPeer(PeerState peer, boolean shouldBanlist, String why)` This does not send a session destroy, caller must do that if desired.
    `(package private) void` | `externalAddressReceived(Hash from, byte[] ourIP, int ourPort)` Someone we tried to contact gave us what they think our IP address is.
    `void` | `externalAddressReceived(Transport.AddressSource source, byte[] ip, int port)` From config, UPnP, local i/f, ...
    `void` | `fail(UDPEndpoint endpoint)` The endpoint has failed.
    `void` | `failed(OutboundMessageState msg)`
    `(package private) void` | `failed(OutboundMessageState msg, boolean allowPeerFailure)`
    `void` | `failed(OutNetMessage msg, String reason)`
    `void` | `forceDisconnect(Hash peer)` Tell the transport to disconnect from this peer.
    `void` | `forwardPortStatus(byte[] ip, int port, int externalPort, boolean success, String reason)` Callback from UPnP.
    `String` | `getAltStyle()` An alternate supported style, or null.
    `(package private) PacketBuilder2` | `getBuilder2()`
    `List<Long>` | `getClockSkews()` Return our peer clock skews on this transport.
    `RouterAddress` | `getCurrentExternalAddress(boolean isIPv6)` Simple fetch of stored IP and port, since we don't put them in the real, published RouterAddress anymore if we are firewalled.
    `List<Hash>` | `getEstablished()` Connected peers.
    `(package private) EstablishmentManager` | `getEstablisher()` For IntroductionManager
    `(package private) byte[]` | `getExternalIP()` Published IP, IPv4 only
    `(package private) int` | `getExternalPort(boolean ipv6)` Published or requested port
    `(package private) InboundMessageFragments` | `getInboundFragments()`
    `(package private) SessionKey` | `getIntroKey()` Introduction key that people should use to contact us, or null if SSU1 disabled.
    `(package private) IntroductionManager` | `getIntroManager()`
    `int` | `getMTU(boolean ipv6)` The MTU for the socket interface.
    `(package private) OutboundMessageFragments` | `getOMF()`
    `(package private) PacketHandler` | `getPacketHandler()`
    `(package private) String` | `getPacketHandlerStatus()`
    `int[]` | `getPeerCounts()` Returns statistics on the number of connected peers, broken down by: <ul> <li>Protocol version (SSU1 or SSU2)</li> <li>Address family (IPv4 or IPv6)</li> <li>Connection direction (inbound or outbound)</li> </ul>
    `Collection<PeerState>` | `getPeers()` For /peers UI only.
    `(package private) PeerState` | `getPeerState(Hash remotePeer)` get the state for the peer with the given ident, or null if no state exists
    `(package private) PeerState2` | `getPeerState(long rcvConnID)` Get the state by SSU2 connection ID
    `(package private) PeerState` | `getPeerState(RemoteHostId hostInfo)` Retrieves the current connection state for a peer identified by their remote host and port.
    `(package private) List<PeerState>` | `getPeerStatesByIP(RemoteHostId hostInfo)` Get the states for all peers at the given remote host, ignoring port.
    `(package private) PeerTestManager` | `getPeerTestManager()`
    `CommSystemFacade.Status` | `getReachabilityStatus()` Returns the current reachability status of the transport.
    `(package private) PeerStateDestroyed` | `getRecentlyClosed(long rcvConnID)` Was the state for this SSU2 receive connection ID recently closed?
    `int` | `getRequestedPort()` The current or configured internal IPv4 port.
    `int` | `getSSU2MTU(boolean ipv6)` The SSU2 MTU for the socket interface.
    `(package private) byte[]` | `getSSU2StaticIntroKey()` The static Intro key
    `(package private) byte[]` | `getSSU2StaticPrivKey()` The static priv key
    `(package private) byte[]` | `getSSU2StaticPubKey()` The static pub key
    `(package private) int` | `getSSUVersion(RouterAddress addr)` Get the valid SSU version of Bob's SSU address for our outbound connections as Alice.
    `String` | `getStyle()` Get the unique style identifier for this transport.
    `(package private) RouterAddress` | `getTargetAddress(RouterInfo target)` Get first available address we can use.
    `(package private) X25519KeyFactory` | `getXDHFactory()`
    `(package private) boolean` | `hasIPv6Address()` For PeerTestManager
    `(package private) void` | `inboundConnectionReceived(boolean isIPv6)`
    `(package private) boolean` | `introducersMaybeRequired(boolean ipv6)` MIGHT we require introducers? This is like introducersRequired, but if we aren't sure, this returns true.
    `boolean` | `isBacklogged(Hash dest)`
    `boolean` | `isEstablished(Hash dest)`
    `(package private) boolean` | `isInDropList(RemoteHostId peer)`
    `(package private) boolean` | `isSymNatted()` Is IPv4 Symmetric NATted?
    `(package private) boolean` | `isTooClose(byte[] ip)` Is this IP too close to ours to trust it for things like relaying?
    `boolean` | `isValid(byte[] addr)` An IPv6 address is only valid if we are configured to support IPv6 AND we have a public IPv6 address.
    `void` | `mayDisconnect(Hash peer)` Tell the transport that we may disconnect from this peer.
    `void` | `messageReceived(I2NPMessage inMsg, RouterIdentity remoteIdent, Hash remoteIdentHash, long msToReceive, int bytesReceived)` Message received from the I2NPMessageReader - send it to the listener
    `protected void` | `outboundMessageReady()` This message is called whenever a new message is added to the send pool, and it should not block Only used by NTCP.
    `(package private) PeerState` | `pickTestPeer(PeerTestState.Role peerRole, int version, boolean isIPv6, RemoteHostId dontInclude)` Pick a Bob (if we are Alice) or a Charlie (if we are Bob).
    `protected void` | `removeAddress(boolean ipv6)` Remove then tell NTCP that we changed.
    `protected void` | `removeAddress(RouterAddress address)` Remove then tell NTCP that we changed.
    `(package private) void` | `removeRecentlyClosed(PeerStateDestroyed peer)` Stop listening for packets on a destroyed connection
    `protected void` | `replaceAddress(RouterAddress address)` Replace then tell NTCP that we changed.
    `(package private) void` | `send(I2NPMessage msg, List<OutNetMessage> msgs, PeerState peer)` "injected" message from the EstablishmentManager, plus pending messages to send, so the messages may be bundled efficiently.
    `(package private) void` | `send(I2NPMessage msg, PeerState peer)` "injected" message from the EstablishmentManager.
    `(package private) void` | `send(List<I2NPMessage> msgs, PeerState peer)` "injected" messages from the EstablishmentManager.
    `void` | `send(OutNetMessage msg)` Asynchronously send the message as requested in the message and, if the send is successful, queue up any msg.getOnSendJob job, and register it with the OutboundMessageRegistry (if it has a reply selector).
    `(package private) void` | `send(UDPPacket packet)` This sends it directly out, bypassing OutboundMessageFragments.
    `(package private) void` | `sendDestroy(PeerState peer, int reasonCode)` Send a session destroy message, bypassing OMF and PacketPusher.
    `(package private) void` | `sendIfEstablished(OutNetMessage msg)` Send only if established, otherwise fail immediately.
    `(package private) void` | `setReachabilityStatus(CommSystemFacade.Status status, boolean isIPv6)`
    `void` | `shutdown()`
    `void` | `startListening()`
    `void` | `stopListening()`
    `void` | `succeeded(OutboundMessageState msg)`
    `List<RouterAddress>` | `updateAddress()` Rebuild to get updated cost and introducers.

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

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

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

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

- - ### Field Detail

    - #### DEFAULT_COST

          public static final int DEFAULT_COST

      See Also:
        Constant Field Values

    - #### DEFAULT_SOURCES

          public static final String DEFAULT_SOURCES

    - #### EXPIRE_TIMEOUT

          public static final int EXPIRE_TIMEOUT

      We used to have MAX_IDLE_TIME = 5m, but this causes us to drop peers and lose the old introducer tags, causing introduction fails, so we keep the max time long to give the introducer keepalive code in the IntroductionManager a chance to work.
      See Also:
        Constant Field Values

    - #### INTRODUCER_EXPIRATION_MARGIN

          static final long INTRODUCER_EXPIRATION_MARGIN

      See Also:
        Constant Field Values

    - #### MIN_EXPIRE_TIMEOUT

          public static final int MIN_EXPIRE_TIMEOUT

      See Also:
        Constant Field Values

    - #### PROP_ALLOW_DIRECT

          public static final String PROP_ALLOW_DIRECT

      Do we allow direct SSU connections, sans introducers?
      See Also:
        Constant Field Values

    - #### 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_EXTERNAL_HOST

          public static final String PROP_EXTERNAL_HOST

      define this to explicitly set an external IP address
      See Also:
        Constant Field Values

    - #### PROP_EXTERNAL_PORT

          public static final String PROP_EXTERNAL_PORT

      define this to explicitly set an external port
      See Also:
        Constant Field Values

    - #### PROP_FORCE_INTRODUCERS

          public static final String PROP_FORCE_INTRODUCERS

      Do we require introducers, regardless of our status?
      See Also:
        Constant Field Values

    - #### PROP_INTERNAL_PORT

          public static final String PROP_INTERNAL_PORT

      See Also:
        Constant Field Values

    - #### PROP_INTRO_KEY

          public static final String PROP_INTRO_KEY

      See Also:
        Constant Field Values

    - #### PROP_IP

          public static final String PROP_IP

      remember IP changes
      See Also:
        Constant Field Values

    - #### PROP_IP_CHANGE

          public static final String PROP_IP_CHANGE

      See Also:
        Constant Field Values

    - #### PROP_IPV6

          public static final String PROP_IPV6

      See Also:
        Constant Field Values

    - #### PROP_LAPTOP_MODE

          public static final String PROP_LAPTOP_MODE

      See Also:
        Constant Field Values

    - #### PROP_PREFER_UDP

          public static final String PROP_PREFER_UDP

      If i2np.udp.preferred is set to "always", UDP bids will always be under the bid from the TCP transport - even if a TCP connection already exists. If set to "true", UDP is preferred unless no UDP session exists and a TCP connection already exists. If it is set to "false" (the default), it will prefer TCP unless no TCP session exists and a UDP connection already exists.
      See Also:
        Constant Field Values

    - #### PROP_SOURCES

          public static final String PROP_SOURCES

      allowed sources of address updates
      See Also:
        Constant Field Values

    - #### PROP_SSU2_IKEY

          public static final String PROP_SSU2_IKEY

      b64 static IV
      See Also:
        Constant Field Values

    - #### PROP_SSU2_SP

          public static final String PROP_SSU2_SP

      b64 static private key
      See Also:
        Constant Field Values

    - #### PUBLIC_RELAY_COUNT

          public static final int PUBLIC_RELAY_COUNT

      How many relays offered to us will we use at a time?
      See Also:
        Constant Field Values

    - #### RATES

          static final long[] RATES

    - #### SSU2_INT_VERSION

          static final int SSU2_INT_VERSION

      See Also:
        Constant Field Values

    - #### SSU2_VERSION

          static final String SSU2_VERSION

      "2"

    - #### SSU2_VERSION_ALT

          static final String SSU2_VERSION_ALT

      "2,"

    - #### STYLE

          public static final String STYLE

      See Also:
        Constant Field Values

    - #### STYLE2

          public static final String STYLE2

      See Also:
        Constant Field Values

  - ### Constructor Detail

    - #### UDPTransport

          public UDPTransport(RouterContext ctx,
                              X25519KeyFactory xdh)

      Parameters:
        `xdh` - non-null

  - ### Method Detail

    - #### addRecentlyClosed

          void addRecentlyClosed(PeerStateDestroyed peer)

      Start listening for packets on a destroyed connection

    - #### addRemotePeerState

          boolean addRemotePeerState(PeerState peer)

      Adds a new peer state or replaces an existing one if the peer identity or address changes. This method ensures thread-safe updates to internal peer tracking maps.
      Parameters:
        `peer` - the peer state to add or update
      Returns:
        true if the peer was successfully added or updated

    - #### 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

    - #### canIntroduce

          boolean canIntroduce(boolean ipv6)

      For EstablishmentManager.

    - #### canTestAsCharlie

          boolean canTestAsCharlie(boolean ipv6)

      Can we be a Charlie right now?
      Returns:
        true if we can participate

    - #### changePeerAddress

          void changePeerAddress(PeerState2 peer,
                                 RemoteHostId newAddress)

      Remove and add to peersByRemoteHost map

    - #### changePeerPort

          void changePeerPort(PeerState peer,
                              int newPort)

      Remove and add to peersByRemoteHost map

    - #### countActivePeers

          public int countActivePeers()

      Description copied from class: `TransportImpl`
      How many peers are we currently connected to, that we have sent a message to or received a message from in the last five minutes.
      Specified by:
        `countActivePeers` in interface `Transport`
      Specified by:
        `countActivePeers` in class `TransportImpl`

    - #### countActiveSendPeers

          public int countActiveSendPeers()

      Description copied from class: `TransportImpl`
      How many peers are we currently connected to, that we have sent a message to in the last minute. Unused for anything, to be removed.
      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`

    - #### dropPeer

          void dropPeer(Hash peer,
                        boolean shouldBanlist,
                        String why)

      This does not send a session destroy, caller must do that if desired.
      Parameters:
        `shouldBanlist` - doesn't really, only sets unreachable

    - #### dropPeer

          void dropPeer(PeerState peer,
                        boolean shouldBanlist,
                        String why)

      This does not send a session destroy, caller must do that if desired.
      Parameters:
        `shouldBanlist` - doesn't really, only sets unreachable

    - #### externalAddressReceived

          void externalAddressReceived(Hash from,
                                       byte[] ourIP,
                                       int ourPort)

      Someone we tried to contact gave us what they think our IP address is. Right now, we just blindly trust them, changing our IP and port on a whim. this is not good ;) Slight enhancement - require two different peers in a row to agree Todo: - Much better tracking of troublemakers - Disable if we have good local address or UPnP - This gets harder if and when we publish multiple addresses, or IPv6
      Parameters:
        `from` - Hash of inbound destination
        `ourIP` - publicly routable IPv4 or IPv6 only, non-null
        `ourPort` - >= 1024

    - #### externalAddressReceived

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

      From config, UPnP, local i/f, ... Not for info received from peers - see externalAddressReceived(Hash, ip, port)
      Specified by:
        `externalAddressReceived` in interface `Transport`
      Specified by:
        `externalAddressReceived` in class `TransportImpl`
      Parameters:
        `source` - as defined in Transport.SOURCE_xxx
        `ip` - publicly routable IPv4 or IPv6, null ok
        `port` - 0 if unknown

    - #### fail

          public void fail(UDPEndpoint endpoint)

      The endpoint has failed. Remove it.

    - #### failed

          public void failed(OutboundMessageState msg)

    - #### failed

          void failed(OutboundMessageState msg,
                      boolean allowPeerFailure)

    - #### failed

          public void failed(OutNetMessage msg,
                             String reason)

    - #### 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)

      Callback from UPnP. If we we have an IP address and UPnP claims success, believe it. If this is wrong, the peer test will figure it out and change the status. Don't do anything if UPnP claims failure.
      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, or null.
      Overrides:
        `getAltStyle` in class `TransportImpl`
      Returns:
        null, override to add support

    - #### getBuilder2

          PacketBuilder2 getBuilder2()

      Returns:
        null if not configured for SSU2

    - #### 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

    - #### getCurrentExternalAddress

          public RouterAddress getCurrentExternalAddress(boolean isIPv6)

      Simple fetch of stored IP and port, since we don't put them in the real, published RouterAddress anymore if we are firewalled.

    - #### getEstablished

          public List<Hash> getEstablished()

      Connected peers.
      Returns:
        a copy, modifiable

    - #### getEstablisher

          EstablishmentManager getEstablisher()

      For IntroductionManager
      Returns:
        may be null if not started

    - #### getExternalIP

          byte[] getExternalIP()

      Published IP, IPv4 only
      Returns:
        IP or null

    - #### getExternalPort

          int getExternalPort(boolean ipv6)

      Published or requested port

    - #### getInboundFragments

          InboundMessageFragments getInboundFragments()

    - #### getIntroKey

          SessionKey getIntroKey()

      Introduction key that people should use to contact us, or null if SSU1 disabled.

    - #### getIntroManager

          IntroductionManager getIntroManager()

    - #### getMTU

          public int getMTU(boolean ipv6)

      The MTU for the socket interface. To be used as the "large" MTU.
      Returns:
        limited to range PeerState.MIN_MTU to PeerState.LARGE_MTU.

    - #### getOMF

          OutboundMessageFragments getOMF()

      Returns:
        the instance of OutboundMessageFragments

    - #### getPacketHandler

          PacketHandler getPacketHandler()

    - #### getPacketHandlerStatus

          String getPacketHandlerStatus()

    - #### getPeerCounts

          public int[] getPeerCounts()

      Returns statistics on the number of connected peers, broken down by: <ul> <li>Protocol version (SSU1 or SSU2)</li> <li>Address family (IPv4 or IPv6)</li> <li>Connection direction (inbound or outbound)</li> </ul>
      Returns:
        an array of 8 integers representing peer counts for each category

    - #### getPeers

          public Collection<PeerState> getPeers()

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

    - #### getPeerState

          PeerState getPeerState(Hash remotePeer)

      get the state for the peer with the given ident, or null if no state exists

    - #### getPeerState

          PeerState2 getPeerState(long rcvConnID)

      Get the state by SSU2 connection ID

    - #### getPeerState

          PeerState getPeerState(RemoteHostId hostInfo)

      Retrieves the current connection state for a peer identified by their remote host and port.
      Parameters:
        `hostInfo` - the remote host and port of the peer
      Returns:
        the peer state, or null if not found

    - #### getPeerStatesByIP

          List<PeerState> getPeerStatesByIP(RemoteHostId hostInfo)

      Get the states for all peers at the given remote host, ignoring port. Used for a last-chance search for a peer that changed port, by PacketHandler. Always returns empty list for IPv6 hostInfo.

    - #### getPeerTestManager

          PeerTestManager getPeerTestManager()

    - #### getReachabilityStatus

          public CommSystemFacade.Status getReachabilityStatus()

      Returns the current reachability status of the transport. This includes both IPv4 and IPv6 reachability states.
      Specified by:
        `getReachabilityStatus` in interface `Transport`
      Specified by:
        `getReachabilityStatus` in class `TransportImpl`
      Returns:
        the current status, never null

    - #### getRecentlyClosed

          PeerStateDestroyed getRecentlyClosed(long rcvConnID)

      Was the state for this SSU2 receive connection ID recently closed?

    - #### getRequestedPort

          public int getRequestedPort()

      The current or configured internal IPv4 port. UDPEndpoint should always be instantiated (and a random port picked if not configured) before this is called, so the returned value should be > 0 unless the endpoint failed to bind.
      Specified by:
        `getRequestedPort` in interface `Transport`
      Overrides:
        `getRequestedPort` in class `TransportImpl`
      Returns:
        port or -1 for none or 0 for any

    - #### getSSU2MTU

          public int getSSU2MTU(boolean ipv6)

      The SSU2 MTU for the socket interface. To be used as the "large" MTU.
      Returns:
        limited to range PeerState2.MIN_MTU to PeerState2.LARGE_MTU, or 0 if unavailable

    - #### getSSU2StaticIntroKey

          byte[] getSSU2StaticIntroKey()

      The static Intro key
      Returns:
        null if not configured for SSU2

    - #### getSSU2StaticPrivKey

          byte[] getSSU2StaticPrivKey()

      The static priv key
      Returns:
        null if not configured for SSU2

    - #### getSSU2StaticPubKey

          byte[] getSSU2StaticPubKey()

      The static pub key
      Returns:
        null if not configured for SSU2

    - #### getSSUVersion

          int getSSUVersion(RouterAddress addr)

      Get the valid SSU version of Bob's SSU address for our outbound connections as Alice.
      Returns:
        the valid version 1 or 2, or 0 if unusable

    - #### 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:
        unique transport style identifier

    - #### getTargetAddress

          RouterAddress getTargetAddress(RouterInfo target)

      Get first available address we can use.
      Returns:
        address or null

    - #### getXDHFactory

          X25519KeyFactory getXDHFactory()

      Returns:
        null if not configured for SSU2

    - #### hasIPv6Address

          boolean hasIPv6Address()

      For PeerTestManager

    - #### inboundConnectionReceived

          void inboundConnectionReceived(boolean isIPv6)

    - #### introducersMaybeRequired

          boolean introducersMaybeRequired(boolean ipv6)

      MIGHT we require introducers? This is like introducersRequired, but if we aren't sure, this returns true. Used only by EstablishmentManager.

    - #### 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`

    - #### isInDropList

          boolean isInDropList(RemoteHostId peer)

    - #### isSymNatted

          boolean isSymNatted()

      Is IPv4 Symmetric NATted?

    - #### isTooClose

          boolean isTooClose(byte[] ip)

      Is this IP too close to ours to trust it for things like relaying?
      Parameters:
        `ip` - IPv4 or IPv6

    - #### isValid

          public final boolean isValid(byte[] addr)

      An IPv6 address is only valid if we are configured to support IPv6 AND we have a public IPv6 address.
      Parameters:
        `addr` - may be null, returns false

    - #### 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

    - #### messageReceived

          public void messageReceived(I2NPMessage inMsg,
                                      RouterIdentity remoteIdent,
                                      Hash remoteIdentHash,
                                      long msToReceive,
                                      int bytesReceived)

      Description copied from class: `TransportImpl`
      Message received from the I2NPMessageReader - send it to the listener
      Overrides:
        `messageReceived` in class `TransportImpl`
      Parameters:
        `inMsg` - non-null
        `remoteIdent` - may be null
        `remoteIdentHash` - may be null, calculated from remoteIdent if null

    - #### outboundMessageReady

          protected void outboundMessageReady()

      Description copied from class: `TransportImpl`
      This message is called whenever a new message is added to the send pool, and it should not block Only used by NTCP. SSU throws UOE.
      Specified by:
        `outboundMessageReady` in class `TransportImpl`

    - #### pickTestPeer

          PeerState pickTestPeer(PeerTestState.Role peerRole,
                                 int version,
                                 boolean isIPv6,
                                 RemoteHostId dontInclude)

      Pick a Bob (if we are Alice) or a Charlie (if we are Bob). For Bob (as called from PeerTestEvent below), returns an established IPv4/v6 peer. While the protocol allows Alice to select an unestablished Bob, we don't support that. For Charlie (as called from PeerTestManager), returns an established IPv4 or IPv6 peer. (doesn't matter how Bob and Charlie communicate) Any returned peer must advertise an IPv4 address to prove it is IPv4-capable. Ditto for v6.
      Parameters:
        `peerRole` - The role of the peer we are looking for, BOB or CHARLIE only (NOT our role)
        `version` - 1 or 2 for role CHARLIE; ignored for role BOB
        `isIPv6` - true to get a v6-capable peer back
        `dontInclude` - may be null
      Returns:
        peer or null

    - #### removeAddress

          protected void removeAddress(boolean ipv6)

      Remove then tell NTCP that we changed.
      Overrides:
        `removeAddress` in class `TransportImpl`
      Parameters:
        `ipv6` - true to remove all IPv6 addresses, false to remove all IPv4 addresses

    - #### removeAddress

          protected void removeAddress(RouterAddress address)

      Remove then tell NTCP that we changed.
      Overrides:
        `removeAddress` in class `TransportImpl`

    - #### removeRecentlyClosed

          void removeRecentlyClosed(PeerStateDestroyed peer)

      Stop listening for packets on a destroyed connection

    - #### replaceAddress

          protected void replaceAddress(RouterAddress address)

      Replace then tell NTCP that we changed.
      Overrides:
        `replaceAddress` in class `TransportImpl`
      Parameters:
        `address` - the new address or null to remove all

    - #### send

          void send(I2NPMessage msg,
                    List<OutNetMessage> msgs,
                    PeerState peer)

      "injected" message from the EstablishmentManager, plus pending messages to send, so the messages may be bundled efficiently. Called at end of outbound establishment.
      Parameters:
        `msg` - may be null if nothing to inject
        `msgs` - non-null, may be empty
        `peer` - all messages MUST be going to this peer

    - #### send

          void send(I2NPMessage msg,
                    PeerState peer)

      "injected" message from the EstablishmentManager. If you have multiple messages, use the list variant, so the messages may be bundled efficiently.
      Parameters:
        `peer` - the message MUST be going to this peer

    - #### send

          void send(List<I2NPMessage> msgs,
                    PeerState peer)

      "injected" messages from the EstablishmentManager. Called at end of inbound establishment.
      Parameters:
        `peer` - all messages MUST be going to this peer

    - #### send

          public void send(OutNetMessage msg)

      Description copied from class: `TransportImpl`
      Asynchronously send the message as requested in the message and, if the send is successful, queue up any msg.getOnSendJob job, and register it with the OutboundMessageRegistry (if it has a reply selector). If the send fails, queue up any msg.getOnFailedSendJob Only used by NTCP. SSU overrides. Note that this adds to the queue and then takes it back off in the same thread, so it actually blocks, and we don't need a big queue. TODO: Override in NTCP also and get rid of queue?
      Specified by:
        `send` in interface `Transport`
      Overrides:
        `send` in class `TransportImpl`
      Parameters:
        `msg` - the message to send, containing destination, payload, and callbacks

    - #### send

          void send(UDPPacket packet)

      This sends it directly out, bypassing OutboundMessageFragments. The only queueing is for the bandwidth limiter. BLOCKING if OB queue is full.

    - #### sendDestroy

          void sendDestroy(PeerState peer,
                           int reasonCode)

      Send a session destroy message, bypassing OMF and PacketPusher. BLOCKING if OB queue is full.
      Parameters:
        `reasonCode` - SSU2 only, ignored for SSU1

    - #### sendIfEstablished

          void sendIfEstablished(OutNetMessage msg)

      Send only if established, otherwise fail immediately. Never queue with the establisher.

    - #### setReachabilityStatus

          void setReachabilityStatus(CommSystemFacade.Status status,
                                     boolean isIPv6)

      Parameters:
        `isIPv6` - Is the change an IPv6 change?

    - #### shutdown

          public void shutdown()

    - #### startListening

          public void startListening()

    - #### stopListening

          public void stopListening()

    - #### succeeded

          public void succeeded(OutboundMessageState msg)

    - #### updateAddress

          public List<RouterAddress> updateAddress()

      Rebuild to get updated cost and introducers. IPv4 only, unless configured as IPv6 only. Do not tell the router (he is the one calling this)
      Specified by:
        `updateAddress` in interface `Transport`
      Overrides:
        `updateAddress` in class `TransportImpl`
      Returns:
        a copy of all addresses, non-null