net.i2p.router.transport.ntcp

## Class NTCPConnection

- java.lang.Object
- - net.i2p.router.transport.ntcp.NTCPConnection

- All Implemented Interfaces:
    Closeable, AutoCloseable

      public class NTCPConnection
      extends Object
      implements Closeable

  Coordinates a connection to a single peer using NTCP 1 or NTCP 2 protocols. Manages the complete connection lifecycle including establishment, message encryption/decryption, bandwidth management, and graceful shutdown. Public only for UI peers page. Not a public API, not for external use.

- - ### Nested Class Summary

    Nested Classes
    Modifier and Type | Class and Description
    --- | ---
    `(package private) static class` | `NTCPConnection.PrepBuffer` Buffer for preparing data to be written to the connection.

  - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `(package private) static int` | `BUFFER_SIZE` Why this is 16K, and where it is documented, good question? We claim we can do 32K datagrams so this is a problem.
    `(package private) static int` | `DELAY_DEFAULT`
    `(package private) static int` | `DUMMY_DEFAULT`
    `(package private) static int` | `NTCP2_MAX_MSG_SIZE` See spec.
    `(package private) static int` | `PADDING_MAX_DEFAULT_INT`
    `(package private) static int` | `PADDING_MIN_DEFAULT_INT`
    `(package private) static int` | `REASON_AEAD`
    `(package private) static int` | `REASON_BANNED`
    `(package private) static int` | `REASON_FRAME_TIMEOUT`
    `(package private) static int` | `REASON_FRAMING`
    `(package private) static int` | `REASON_MSG1`
    `(package private) static int` | `REASON_MSG2`
    `(package private) static int` | `REASON_MSG3`
    `(package private) static int` | `REASON_OPTIONS`
    `(package private) static int` | `REASON_PADDING`
    `(package private) static int` | `REASON_PAYLOAD`
    `(package private) static int` | `REASON_S_MISMATCH`
    `(package private) static int` | `REASON_SIGFAIL`
    `(package private) static int` | `REASON_SIGTYPE`
    `(package private) static int` | `REASON_SKEW`
    `(package private) static int` | `REASON_TERMINATION`
    `(package private) static int` | `REASON_TIMEOUT`
    `(package private) static int` | `REASON_UNSPEC`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `NTCPConnection(RouterContext ctx, NTCPTransport transport, RouterIdentity remotePeer, RouterAddress remAddr, int version)` Create an outbound unconnected NTCP connection.
    `NTCPConnection(RouterContext ctx, NTCPTransport transport, SocketChannel chan, SelectionKey key)` Create an inbound connected (though not established) NTCP connection.

  - ### Method Summary

    All Methods Static Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `clearZeroRead()` workaround for EventPumper
    `void` | `close()`
    `void` | `close(boolean allowRequeue)`
    `(package private) void` | `closeOnTimeout(String cause, Exception e)` Close and release EstablishState resources.
    `boolean` | `compareAndSetWriteInterestPending(boolean expected, boolean update)`
    `(package private) void` | `enqueueInfoMessage()` Inject a DatabaseStoreMessage with our RouterInfo.
    `(package private) void` | `failInboundEstablishment(CipherState sender, byte[] sip_ba, int reason)` We are Bob.
    `(package private) void` | `finishInboundEstablishment(CipherState sender, CipherState receiver, byte[] sip_ba, byte[] sip_ab, long clockSkew, NTCP2Options hisPadding)` We are Bob.
    `(package private) void` | `finishOutboundEstablishment(CipherState sender, CipherState receiver, byte[] sip_ab, byte[] sip_ba, long clockSkew)` We are Alice.
    `SocketChannel` | `getChannel()` Valid for inbound; valid for outbound shortly after creation
    `long` | `getClockSkew()` A positive number means our clock is ahead of theirs.
    `long` | `getCreated()`
    `long` | `getEstablishedOn()`
    `(package private) EstablishState` | `getEstablishState()` Only valid during establishment; replaced with EstablishState.VERIFIED or FAILED afterwards
    `SelectionKey` | `getKey()` Valid for inbound; valid for outbound shortly after creation
    `long` | `getLastActiveTime()`
    `long` | `getLastZeroReadTime()`
    `boolean` | `getMayDisconnect()`
    `int` | `getMessagesReceived()`
    `int` | `getMessagesSent()`
    `(package private) ByteBuffer` | `getNextReadBuf()`
    `(package private) ByteBuffer` | `getNextWriteBuf()` Returns but does not remove the buffer.
    `int` | `getOutboundQueueSize()`
    `float` | `getRecvRate()`
    `RouterAddress` | `getRemoteAddress()` Only valid for outbound; null for inbound
    `byte[]` | `getRemoteIP()`
    `RouterIdentity` | `getRemotePeer()` Valid for outbound; valid for inbound after handshake
    `float` | `getSendRate()`
    `long` | `getTimeSinceCreated()`
    `long` | `getTimeSinceCreated(long now)`
    `long` | `getTimeSinceReceive()`
    `long` | `getTimeSinceReceive(long now)`
    `long` | `getTimeSinceSend()`
    `long` | `getTimeSinceSend(long now)`
    `long` | `getUptime()`
    `int` | `getVersion()` The NTCP2 version, for the console.
    `(package private) Object` | `getWriteLock()` Write lock for pumper delayed writes
    `int` | `gotZeroRead()` Track time of zero-reads to avoid closing healthy connections
    `boolean` | `hasWriteInterestPending()`
    `boolean` | `isBacklogged()`
    `boolean` | `isBanned()` Check if the peer is blocklisted or banned.
    `boolean` | `isClosed()`
    `boolean` | `isEstablished()`
    `boolean` | `isInbound()`
    `boolean` | `isIPv6()`
    `(package private) boolean` | `isWriteBufEmpty()` Replaces getWriteBufCount().
    `(package private) void` | `outboundConnected()` async callback after the outbound connection was completed (this should NOT block, as it occurs in the selector thread)
    `(package private) void` | `prepareNextWrite(NTCPConnection.PrepBuffer prep)` Prepare the next I2NP message for transmission.
    `(package private) void` | `queuedRecv(ByteBuffer buf, FIFOBandwidthLimiter.Request req)` We have read the data in the buffer, but we can't process it locally yet, because we're choked by the bandwidth limiter.
    `(package private) void` | `recv(ByteBuffer buf)` The contents of the buffer have been read and can be processed asap.
    `(package private) void` | `recvEncryptedI2NP(ByteBuffer buf)` Connection must be established! The contents of the buffer include some fraction of one or more encrypted and encoded I2NP messages.
    `(package private) static void` | `releaseResources()` Call at transport shutdown
    `(package private) void` | `removeWriteBuf(ByteBuffer buf)` Remove the buffer, which _should_ be the one at the head of _writeBufs.
    `void` | `send(OutNetMessage msg)` toss the message onto the connection's send queue
    `(package private) void` | `sendOurRouterInfo(boolean shouldFlood)` NTCP2 only
    `(package private) void` | `sendTerminationAndClose()` NTCP 1 or 2.
    `void` | `setChannel(SocketChannel chan)`
    `void` | `setKey(SelectionKey key)`
    `void` | `setMayDisconnect()` Sets to true.
    `void` | `setRemotePeer(RouterIdentity ident)` Valid for outbound; valid for inbound after handshake
    `void` | `setVersion(int ver)` Set version 2 from InboundEstablishState.
    `boolean` | `shouldSetInterest(int ops)` Check if the given interest op is not already set
    `boolean` | `tooBacklogged()` Returns true if the outbound connection is currently too backlogged to accept new messages, allowing a short grace period after connection establishment and optionally logging details.
    `String` | `toString()`
    `void` | `updateInterestOps(int ops)` Update the cached interest ops
    `void` | `updateLastActiveTime()`
    `(package private) void` | `wantsWrite(byte[] data)` Call when there is data ready to write.
    `(package private) void` | `wantsWrite(byte[] data, int off, int len)` Call when there is data ready to write.

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

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

- - ### Field Detail

    - #### BUFFER_SIZE

          static final int BUFFER_SIZE

      Why this is 16K, and where it is documented, good question? We claim we can do 32K datagrams so this is a problem. Needs to be fixed. But SSU can handle it? In the meantime, don't let the transport bid on big messages.
      See Also:
        Constant Field Values

    - #### DELAY_DEFAULT

          static final int DELAY_DEFAULT

      See Also:
        Constant Field Values

    - #### DUMMY_DEFAULT

          static final int DUMMY_DEFAULT

      See Also:
        Constant Field Values

    - #### NTCP2_MAX_MSG_SIZE

          static final int NTCP2_MAX_MSG_SIZE

      See spec. Max Noise payload 65535, minus 16 byte MAC and 3 byte block header. Includes 9-byte I2NP header.
      See Also:
        Constant Field Values

    - #### PADDING_MAX_DEFAULT_INT

          static final int PADDING_MAX_DEFAULT_INT

      See Also:
        Constant Field Values

    - #### PADDING_MIN_DEFAULT_INT

          static final int PADDING_MIN_DEFAULT_INT

      See Also:
        Constant Field Values

    - #### REASON_AEAD

          static final int REASON_AEAD

      See Also:
        Constant Field Values

    - #### REASON_BANNED

          static final int REASON_BANNED

      See Also:
        Constant Field Values

    - #### REASON_FRAME_TIMEOUT

          static final int REASON_FRAME_TIMEOUT

      See Also:
        Constant Field Values

    - #### REASON_FRAMING

          static final int REASON_FRAMING

      See Also:
        Constant Field Values

    - #### REASON_MSG1

          static final int REASON_MSG1

      See Also:
        Constant Field Values

    - #### REASON_MSG2

          static final int REASON_MSG2

      See Also:
        Constant Field Values

    - #### REASON_MSG3

          static final int REASON_MSG3

      See Also:
        Constant Field Values

    - #### REASON_OPTIONS

          static final int REASON_OPTIONS

      See Also:
        Constant Field Values

    - #### REASON_PADDING

          static final int REASON_PADDING

      See Also:
        Constant Field Values

    - #### REASON_PAYLOAD

          static final int REASON_PAYLOAD

      See Also:
        Constant Field Values

    - #### REASON_S_MISMATCH

          static final int REASON_S_MISMATCH

      See Also:
        Constant Field Values

    - #### REASON_SIGFAIL

          static final int REASON_SIGFAIL

      See Also:
        Constant Field Values

    - #### REASON_SIGTYPE

          static final int REASON_SIGTYPE

      See Also:
        Constant Field Values

    - #### REASON_SKEW

          static final int REASON_SKEW

      See Also:
        Constant Field Values

    - #### REASON_TERMINATION

          static final int REASON_TERMINATION

      See Also:
        Constant Field Values

    - #### REASON_TIMEOUT

          static final int REASON_TIMEOUT

      See Also:
        Constant Field Values

    - #### REASON_UNSPEC

          static final int REASON_UNSPEC

      See Also:
        Constant Field Values

  - ### Constructor Detail

    - #### NTCPConnection

          public NTCPConnection(RouterContext ctx,
                                NTCPTransport transport,
                                RouterIdentity remotePeer,
                                RouterAddress remAddr,
                                int version)
                         throws DataFormatException

      Create an outbound unconnected NTCP connection. Caller MUST call transport.establishing(this) after construction.
      Parameters:
        `version` - must be 1 or 2
      Throws:
        `DataFormatException` - if there's a problem with the address

    - #### NTCPConnection

          public NTCPConnection(RouterContext ctx,
                                NTCPTransport transport,
                                SocketChannel chan,
                                SelectionKey key)

      Create an inbound connected (though not established) NTCP connection. Caller MUST call transport.establishing(this) after construction. Caller MUST key.attach(this) after construction.

  - ### Method Detail

    - #### clearZeroRead

          public void clearZeroRead()

      workaround for EventPumper

    - #### close

          public void close()

      Specified by:
        `close` in interface `Closeable`
      Specified by:
        `close` in interface `AutoCloseable`

    - #### close

          public void close(boolean allowRequeue)

    - #### closeOnTimeout

          void closeOnTimeout(String cause,
                              Exception e)

      Close and release EstablishState resources.
      Parameters:
        `e` - may be null

    - #### compareAndSetWriteInterestPending

          public boolean compareAndSetWriteInterestPending(boolean expected,
                                                           boolean update)

    - #### enqueueInfoMessage

          void enqueueInfoMessage()

      Inject a DatabaseStoreMessage with our RouterInfo. NTCP 1 or 2. Externally, this is only called by NTCPTransport for outbound cons, before the con is established, but we know what version it is. Internally, may be called for outbound or inbound, but only after the con is established, so we know what the version is.

    - #### failInboundEstablishment

          void failInboundEstablishment(CipherState sender,
                                        byte[] sip_ba,
                                        int reason)

      We are Bob. NTCP2 only. This is only for invalid payload received in message 3. We send a termination and close. There will be no receiving.
      Parameters:
        `sender` - use to send to Alice
        `sip_ba` - 24 bytes to init SipHash to Alice

    - #### finishInboundEstablishment

          void finishInboundEstablishment(CipherState sender,
                                          CipherState receiver,
                                          byte[] sip_ba,
                                          byte[] sip_ab,
                                          long clockSkew,
                                          NTCP2Options hisPadding)

      We are Bob. NTCP2 only. Caller MUST call recvEncryptedI2NP() after, for any remaining bytes in receive buffer
      Parameters:
        `clockSkew` - OUR clock minus ALICE's clock in seconds (may be negative, obviously, but |val| should be under 1 minute)
        `sender` - use to send to Alice
        `receiver` - use to receive from Alice
        `sip_ba` - 24 bytes to init SipHash to Alice
        `sip_ab` - 24 bytes to init SipHash from Alice
        `hisPadding` - may be null

    - #### finishOutboundEstablishment

          void finishOutboundEstablishment(CipherState sender,
                                           CipherState receiver,
                                           byte[] sip_ab,
                                           byte[] sip_ba,
                                           long clockSkew)

      We are Alice. NTCP2 only. Caller MUST call recvEncryptedI2NP() after, for any remaining bytes in receive buffer
      Parameters:
        `clockSkew` - OUR clock minus BOB's clock in seconds (may be negative, obviously, but |val| should be under 1 minute)
        `sender` - use to send to Bob
        `receiver` - use to receive from Bob
        `sip_ab` - 24 bytes to init SipHash to Bob
        `sip_ba` - 24 bytes to init SipHash from Bob

    - #### getChannel

          public SocketChannel getChannel()

      Valid for inbound; valid for outbound shortly after creation

    - #### getClockSkew

          public long getClockSkew()

      A positive number means our clock is ahead of theirs.
      Returns:
        seconds

    - #### getCreated

          public long getCreated()

      Returns:
        when this connection was created (not established)

    - #### getEstablishedOn

          public long getEstablishedOn()

    - #### getEstablishState

          EstablishState getEstablishState()

      Only valid during establishment; replaced with EstablishState.VERIFIED or FAILED afterwards

    - #### getKey

          public SelectionKey getKey()

      Valid for inbound; valid for outbound shortly after creation

    - #### getLastActiveTime

          public long getLastActiveTime()

    - #### getLastZeroReadTime

          public long getLastZeroReadTime()

    - #### getMayDisconnect

          public boolean getMayDisconnect()

    - #### getMessagesReceived

          public int getMessagesReceived()

    - #### getMessagesSent

          public int getMessagesSent()

    - #### getNextReadBuf

          ByteBuffer getNextReadBuf()

      Returns:
        null if none available

    - #### getNextWriteBuf

          ByteBuffer getNextWriteBuf()

      Returns but does not remove the buffer. Call removeWriteBuf() after write complete. Caller should sync on getWriteLock()
      Returns:
        null if none available

    - #### getOutboundQueueSize

          public int getOutboundQueueSize()

    - #### getRecvRate

          public float getRecvRate()

    - #### getRemoteAddress

          public RouterAddress getRemoteAddress()

      Only valid for outbound; null for inbound

    - #### getRemoteIP

          public byte[] getRemoteIP()

      Returns:
        null if unknown

    - #### getRemotePeer

          public RouterIdentity getRemotePeer()

      Valid for outbound; valid for inbound after handshake

    - #### getSendRate

          public float getSendRate()

    - #### getTimeSinceCreated

          public long getTimeSinceCreated()

      Returns:
        milliseconds

    - #### getTimeSinceCreated

          public long getTimeSinceCreated(long now)

      Returns:
        milliseconds

    - #### getTimeSinceReceive

          public long getTimeSinceReceive()

      Returns:
        milliseconds

    - #### getTimeSinceReceive

          public long getTimeSinceReceive(long now)

      Returns:
        milliseconds

    - #### getTimeSinceSend

          public long getTimeSinceSend()

      Returns:
        milliseconds

    - #### getTimeSinceSend

          public long getTimeSinceSend(long now)

      Returns:
        milliseconds

    - #### getUptime

          public long getUptime()

      Returns:
        milliseconds

    - #### getVersion

          public int getVersion()

      The NTCP2 version, for the console. For outbound, will not change. For inbound, defaults to 1, may change to 2 after establishment.
      Returns:
        the version, 1 or 2

    - #### getWriteLock

          Object getWriteLock()

      Write lock for pumper delayed writes

    - #### gotZeroRead

          public int gotZeroRead()

      Track time of zero-reads to avoid closing healthy connections
      Returns:
        current count after incrementing

    - #### hasWriteInterestPending

          public boolean hasWriteInterestPending()

    - #### isBacklogged

          public boolean isBacklogged()

    - #### isBanned

          public boolean isBanned()

      Check if the peer is blocklisted or banned. If so, log and close the connection.
      Returns:
        true if banned or blocklisted, false otherwise

    - #### isClosed

          public boolean isClosed()

    - #### isEstablished

          public boolean isEstablished()

    - #### isInbound

          public boolean isInbound()

    - #### isIPv6

          public boolean isIPv6()

    - #### isWriteBufEmpty

          boolean isWriteBufEmpty()

      Replaces getWriteBufCount(). Caller should sync on getWriteLock()

    - #### outboundConnected

          void outboundConnected()

      async callback after the outbound connection was completed (this should NOT block, as it occurs in the selector thread)

    - #### prepareNextWrite

          void prepareNextWrite(NTCPConnection.PrepBuffer prep)

      Prepare the next I2NP message for transmission. This should be run from the Writer thread pool. NTCP 1 or 2. This is the entry point as called from Writer.Runner.run()
      Parameters:
        `prep` - an instance of PrepBuffer to use as scratch space

    - #### queuedRecv

          void queuedRecv(ByteBuffer buf,
                          FIFOBandwidthLimiter.Request req)

      We have read the data in the buffer, but we can't process it locally yet, because we're choked by the bandwidth limiter. Cache the contents of the buffer (not copy) and register ourselves to be notified when the contents have been fully allocated

    - #### recv

          void recv(ByteBuffer buf)

      The contents of the buffer have been read and can be processed asap. This should not block, and the NTCP connection now owns the buffer to do with as it pleases BUT it should eventually copy out the data and call EventPumper.releaseBuf().

    - #### recvEncryptedI2NP

          void recvEncryptedI2NP(ByteBuffer buf)

      Connection must be established! The contents of the buffer include some fraction of one or more encrypted and encoded I2NP messages. individual i2np messages are encoded as "sizeof(data)+data+pad+crc", and those are encrypted with the session key and the last 16 bytes of the previous encrypted i2np message. The NTCP connection now owns the buffer BUT it must copy out the data as reader will call EventPumper.releaseBuf(). This is the entry point as called from Reader.processRead()

    - #### releaseResources

          static void releaseResources()

      Call at transport shutdown

    - #### removeWriteBuf

          void removeWriteBuf(ByteBuffer buf)

      Remove the buffer, which _should_ be the one at the head of _writeBufs. Caller must sync on _writeLock

    - #### send

          public void send(OutNetMessage msg)

      toss the message onto the connection's send queue

    - #### sendOurRouterInfo

          void sendOurRouterInfo(boolean shouldFlood)

      NTCP2 only

    - #### sendTerminationAndClose

          void sendTerminationAndClose()

      NTCP 1 or 2. For NTCP1, simply closes the connection immediately. For NTCP2, sends termination and then closes the connection after a brief delay.

    - #### setChannel

          public void setChannel(SocketChannel chan)

    - #### setKey

          public void setKey(SelectionKey key)

    - #### setMayDisconnect

          public void setMayDisconnect()

      Sets to true.

    - #### setRemotePeer

          public void setRemotePeer(RouterIdentity ident)

      Valid for outbound; valid for inbound after handshake

    - #### setVersion

          public void setVersion(int ver)

      Set version 2 from InboundEstablishState. Just for logging, so we know before finishInboundEstablish() is called.

    - #### shouldSetInterest

          public boolean shouldSetInterest(int ops)

      Check if the given interest op is not already set

    - #### tooBacklogged

          public boolean tooBacklogged()

      Returns true if the outbound connection is currently too backlogged to accept new messages, allowing a short grace period after connection establishment and optionally logging details.

    - #### toString

          public String toString()

      Overrides:
        `toString` in class `Object`

    - #### updateInterestOps

          public void updateInterestOps(int ops)

      Update the cached interest ops

    - #### updateLastActiveTime

          public void updateLastActiveTime()

    - #### wantsWrite

          void wantsWrite(byte[] data)

      Call when there is data ready to write. If we have bandwidth, calls write() which calls EventPumnper.wantsWrite(con). If no bandwidth, calls queuedWrite().

    - #### wantsWrite

          void wantsWrite(byte[] data,
                          int off,
                          int len)

      Call when there is data ready to write. If we have bandwidth, calls write() which calls EventPumnper.wantsWrite(con). If no bandwidth, calls queuedWrite().