net.i2p.router.transport.ntcp
Class NTCPConnection

java.lang.Object
  extended by net.i2p.router.transport.ntcp.NTCPConnection
All Implemented Interfaces:
Closeable

 class NTCPConnection
extends Object
implements Closeable

Coordinate the connection to a single peer. The NTCP transport sends individual I2NP messages AES/256/CBC encrypted with a simple checksum. The unencrypted message is encoded as follows:

  +-------+-------+--//--+---//----+-------+-------+-------+-------+
  | sizeof(data)  | data | padding | adler checksum of sz+data+pad |
  +-------+-------+--//--+---//----+-------+-------+-------+-------+
That message is then encrypted with the DH/2048 negotiated session key (station to station authenticated per the EstablishState class) using the last 16 bytes of the previous encrypted message as the IV. One special case is a metadata message where the sizeof(data) is 0. In that case, the unencrypted message is encoded as:
  +-------+-------+-------+-------+-------+-------+-------+-------+
  |       0       |      timestamp in seconds     | uninterpreted             
  +-------+-------+-------+-------+-------+-------+-------+-------+
          uninterpreted           | adler checksum of sz+data+pad |
  +-------+-------+-------+-------+-------+-------+-------+-------+


Nested Class Summary
static class NTCPConnection.PrepBuffer
           
 
Field Summary
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.
static int MAX_MSG_SIZE
          2 bytes for length and 4 for CRC
 
Constructor Summary
NTCPConnection(RouterContext ctx, NTCPTransport transport, RouterIdentity remotePeer, RouterAddress remAddr)
          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
 void clearZeroRead()
          workaround for EventPumper
 void close()
           
 void close(boolean allowRequeue)
           
 void closeOnTimeout(String cause, Exception e)
          Close and release EstablishState resources.
 void enqueueInfoMessage()
          Inject a DatabaseStoreMessage with our RouterInfo
 void finishInboundEstablishment(SessionKey key, long clockSkew, byte[] prevWriteEnd, byte[] prevReadEnd)
          We are Bob.
 void finishOutboundEstablishment(SessionKey key, long clockSkew, byte[] prevWriteEnd, byte[] prevReadEnd)
          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()
           
 EstablishState getEstablishState()
          Only valid during establishment; null later
 SelectionKey getKey()
          Valid for inbound; valid for outbound shortly after creation
 long getMessagesReceived()
           
 long getMessagesSent()
           
 ByteBuffer getNextReadBuf()
           
 ByteBuffer getNextWriteBuf()
           
 long getOutboundQueueSize()
           
 float getRecvRate()
           
 RouterAddress getRemoteAddress()
          Only valid for outbound; null for inbound
 RouterIdentity getRemotePeer()
          Valid for outbound; valid for inbound after handshake
 float getSendRate()
           
 long getTimeSinceCreated()
           
 long getTimeSinceReceive()
           
 long getTimeSinceSend()
           
 long getUptime()
           
 int gotZeroRead()
          workaround for EventPumper
 boolean isBacklogged()
          private long queueTime() { OutNetMessage msg = _currentOutbound; if (msg == null) { msg = _outbound.peek(); if (msg == null) return 0; } return msg.getSendTime(); // does not include any of the pre-send(...) preparation }
 boolean isClosed()
           
 boolean isEstablished()
           
 boolean isInbound()
           
 boolean isIPv6()
           
 boolean isWriteBufEmpty()
          Replaces getWriteBufCount()
 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.
 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.
 void queuedWrite(ByteBuffer buf, FIFOBandwidthLimiter.Request req)
          ditto for writes
 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
 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
 void setChannel(SocketChannel chan)
           
 void setKey(SelectionKey key)
           
 void setRemotePeer(RouterIdentity ident)
           
 boolean tooBacklogged()
           
 String toString()
           
 void write(ByteBuffer buf)
          The contents of the buffer have been encrypted / padded / etc and have been fully allocated for the bandwidth limiter.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

BUFFER_SIZE

public 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

MAX_MSG_SIZE

public static final int MAX_MSG_SIZE
2 bytes for length and 4 for CRC

See Also:
Constant Field Values
Constructor Detail

NTCPConnection

public NTCPConnection(RouterContext ctx,
                      NTCPTransport transport,
                      SocketChannel chan,
                      SelectionKey key)
Create an inbound connected (though not established) NTCP connection


NTCPConnection

public NTCPConnection(RouterContext ctx,
                      NTCPTransport transport,
                      RouterIdentity remotePeer,
                      RouterAddress remAddr)
Create an outbound unconnected NTCP connection

Method Detail

getChannel

public SocketChannel getChannel()
Valid for inbound; valid for outbound shortly after creation


getKey

public SelectionKey getKey()
Valid for inbound; valid for outbound shortly after creation


setChannel

public void setChannel(SocketChannel chan)

setKey

public void setKey(SelectionKey key)

isInbound

public boolean isInbound()

isEstablished

public boolean isEstablished()

isIPv6

public boolean isIPv6()
Since:
IPv6

getEstablishState

public EstablishState getEstablishState()
Only valid during establishment; null later


getRemoteAddress

public RouterAddress getRemoteAddress()
Only valid for outbound; null for inbound


getRemotePeer

public RouterIdentity getRemotePeer()
Valid for outbound; valid for inbound after handshake


setRemotePeer

public void setRemotePeer(RouterIdentity ident)

finishInboundEstablishment

public void finishInboundEstablishment(SessionKey key,
                                       long clockSkew,
                                       byte[] prevWriteEnd,
                                       byte[] prevReadEnd)
We are Bob.

Parameters:
clockSkew - OUR clock minus ALICE's clock in seconds (may be negative, obviously, but |val| should be under 1 minute)
prevWriteEnd - exactly 16 bytes, not copied, do not corrupt
prevReadEnd - 16 or more bytes, last 16 bytes copied

getClockSkew

public long getClockSkew()
A positive number means our clock is ahead of theirs.

Returns:
seconds

getUptime

public long getUptime()
Returns:
milliseconds

getMessagesSent

public long getMessagesSent()

getMessagesReceived

public long getMessagesReceived()

getOutboundQueueSize

public long getOutboundQueueSize()

getTimeSinceSend

public long getTimeSinceSend()
Returns:
milliseconds

getTimeSinceReceive

public long getTimeSinceReceive()
Returns:
milliseconds

getTimeSinceCreated

public long getTimeSinceCreated()
Returns:
milliseconds

getCreated

public long getCreated()
Returns:
when this connection was created (not established)
Since:
0.9.20

clearZeroRead

public void clearZeroRead()
workaround for EventPumper

Since:
0.8.12

gotZeroRead

public int gotZeroRead()
workaround for EventPumper

Returns:
value after incrementing
Since:
0.8.12

isClosed

public boolean isClosed()

close

public void close()
Specified by:
close in interface Closeable

close

public void close(boolean allowRequeue)

closeOnTimeout

public void closeOnTimeout(String cause,
                           Exception e)
Close and release EstablishState resources.

Parameters:
e - may be null
Since:
0.9.16

send

public void send(OutNetMessage msg)
toss the message onto the connection's send queue


isBacklogged

public boolean isBacklogged()
private long queueTime() { OutNetMessage msg = _currentOutbound; if (msg == null) { msg = _outbound.peek(); if (msg == null) return 0; } return msg.getSendTime(); // does not include any of the pre-send(...) preparation }


tooBacklogged

public boolean tooBacklogged()

enqueueInfoMessage

public void enqueueInfoMessage()
Inject a DatabaseStoreMessage with our RouterInfo


finishOutboundEstablishment

public void finishOutboundEstablishment(SessionKey key,
                                        long clockSkew,
                                        byte[] prevWriteEnd,
                                        byte[] prevReadEnd)
We are Alice.

Parameters:
clockSkew - OUR clock minus BOB's clock in seconds (may be negative, obviously, but |val| should be under 1 minute)
prevWriteEnd - exactly 16 bytes, not copied, do not corrupt
prevReadEnd - 16 or more bytes, last 16 bytes copied

prepareNextWrite

void prepareNextWrite(NTCPConnection.PrepBuffer prep)
prepare the next i2np message for transmission. this should be run from the Writer thread pool.

Parameters:
prep - an instance of PrepBuffer to use as scratch space

outboundConnected

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


queuedRecv

public 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


queuedWrite

public void queuedWrite(ByteBuffer buf,
                        FIFOBandwidthLimiter.Request req)
ditto for writes


recv

public 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().


write

public void write(ByteBuffer buf)
The contents of the buffer have been encrypted / padded / etc and have been fully allocated for the bandwidth limiter.


getNextReadBuf

public ByteBuffer getNextReadBuf()
Returns:
null if none available

isWriteBufEmpty

public boolean isWriteBufEmpty()
Replaces getWriteBufCount()

Since:
0.8.12

getNextWriteBuf

public ByteBuffer getNextWriteBuf()
Returns:
null if none available

removeWriteBuf

public void removeWriteBuf(ByteBuffer buf)
Remove the buffer, which _should_ be the one at the head of _writeBufs


getSendRate

public float getSendRate()

getRecvRate

public float getRecvRate()

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().


releaseResources

static void releaseResources()
Call at transport shutdown

Since:
0.8.8

toString

public String toString()
Overrides:
toString in class Object