- All Implemented Interfaces:
Closeable, AutoCloseable
This class buffers incoming data blocks and reorders them transparently, ensuring a continuous byte stream to the caller. It supports:
- Out-of-order message handling
- Flow control via blocking reads
- Optional read timeouts
- EOF signaling via closeReceived()
- Error propagation via streamErrorOccurred()
Thread Safety: This class is synchronized internally and safe for use by one reader thread and potentially multiple message-receiving threads.
Performance: Designed for high-throughput scenarios such as large file downloads. Avoids unnecessary copying by using ByteArray references.
Lifecycle: The stream can be closed locally or receive an EOF signal remotely. Once closed, no further reads or message receptions are allowed.
Usage:
I2PSession -> MessageHandler -> PacketHandler -> ConnectionPacketHandler -> MessageInputStream
Constructor Summary
ConstructorsConstructorDescriptionMessageInputStream(I2PAppContext ctx, int maxMessageSize, int maxWindowSize, int maxBufferSize) New stream with the specified buffer limits.MessageInputStream(I2PAppContext ctx, int maxMessageSize, int maxWindowSize, int maxBufferSize, int maxPacketCount) New stream with the specified buffer limits.Method Summary
All MethodsModifier and TypeMethodDescriptionintReturns an estimate of bytes readily available to read without blocking.booleancanAccept(long messageId, int payloadSize) Determines whether the stream can accept a new message.voidclose()Closes the stream, clears all buffered data, and marks the stream as locally closed.voidNotifies the stream that no more messages will be received after the current highest.booleanensureCanAccept(long messageId, int payloadSize) Combined canAccept with automatic buffer growth.longReturns the highest block ID received so far, regardless of order.longReturns the highest consecutive block ID that has been fully received and marked ready.long[]getNacks()Missing block IDs between the highest ready block and highest received block.(package private) long[]Returns missing block IDs.intReturns the current read timeout in milliseconds.intTotal number of bytes queued up in ready buffers.booleanTry to grow the receive buffer when canAccept() returns false.booleanChecks if this stream has been closed locally.booleanmessageReceived(long messageId, ByteArray payload) Accepts a newly received message block.intread()Reads a single byte from the stream.intread(byte[] target) Reads bytes into the given array.intread(byte[] target, int offset, int length) Reads up tolengthbytes into thetargetarray atoffset.voidsetReadTimeout(int timeout) Read timeout in milliseconds.(package private) voidRecords a stream error and marks the stream as locally closed.voidupdateAcks(PacketLocal packet) Updates the ACK and NACK fields of a packet based on current stream state.Methods inherited from class InputStream
mark, markSupported, nullInputStream, readAllBytes, readNBytes, readNBytes, reset, skip, skipNBytes, transferTo
Constructor Details
MessageInputStream
public MessageInputStream(I2PAppContext ctx, int maxMessageSize, int maxWindowSize, int maxBufferSize) New stream with the specified buffer limits.- Parameters:
ctx- Application context for logging and utilitiesmaxMessageSize- Max size of a single message blockmaxWindowSize- Max number of messages in the windowmaxBufferSize- Max total size of all buffered data
MessageInputStream
public MessageInputStream(I2PAppContext ctx, int maxMessageSize, int maxWindowSize, int maxBufferSize, int maxPacketCount) New stream with the specified buffer limits.- Parameters:
ctx- Application context for logging and utilitiesmaxMessageSize- Max size of a single message blockmaxWindowSize- Max number of messages in the windowmaxBufferSize- Max total size of all buffered datamaxPacketCount- Max number of packets regardless of byte size
Method Details
getHighestReadyBlockId
public long getHighestReadyBlockId()Returns the highest consecutive block ID that has been fully received and marked ready.- Returns:
- highest ready block ID, or -1 if none
getHighestBlockId
public long getHighestBlockId()Returns the highest block ID received so far, regardless of order.- Returns:
- highest block ID received, or -1 if none
getTotalReadySize
public int getTotalReadySize()Total number of bytes queued up in ready buffers. Does not throw IOException on closed stream.- Returns:
- number of bytes waiting to be read
isLocallyClosed
public boolean isLocallyClosed()Checks if this stream has been closed locally.- Returns:
- true if closed, false otherwise
canAccept
public boolean canAccept(long messageId, int payloadSize) Determines whether the stream can accept a new message.Accepts zero-length or duplicate packets always.
- Parameters:
messageId- The sequence ID of the messagepayloadSize- Size of the message payload- Returns:
- true if the message can be accepted, false otherwise
growBuffer
public boolean growBuffer()Try to grow the receive buffer when canAccept() returns false. Doubles the buffer size up to a reasonable cap (8MB) to reduce choke frequency for high-throughput connections.- Returns:
- true if the buffer was grown, false if already at cap
ensureCanAccept
public boolean ensureCanAccept(long messageId, int payloadSize) Combined canAccept with automatic buffer growth. If the buffer is full, tries to grow it before rejecting.- Parameters:
messageId- the inbound message being offeredpayloadSize- the size in bytes the message needs- Returns:
- true if the message can be accepted (possibly after buffer growth)
getNacks
public long[] getNacks()Missing block IDs between the highest ready block and highest received block. Two-pass to avoid ArrayList allocation inside the lock.- Returns:
- array of missing block IDs, empty if none
getNacksLocked
long[] getNacksLocked()Returns missing block IDs. Must be called while holding_dataLock.- Returns:
- array of missing block IDs, empty if none
updateAcks
Updates the ACK and NACK fields of a packet based on current stream state.- Parameters:
packet- Packet to update
closeReceived
public void closeReceived()Notifies the stream that no more messages will be received after the current highest. Buffered data remains accessible until read.messageReceived
Accepts a newly received message block.If the message is next in sequence, it's added to the ready list and contiguous out-of-order messages are promoted.
- Parameters:
messageId- The message sequence IDpayload- The message payload- Returns:
- true if the message was new, false if a duplicate
read
Reads a single byte from the stream.- Specified by:
readin classInputStream- Returns:
- the next byte (0-255), or -1 on EOF
- Throws:
IOException- if stream is closed or read fails
read
Reads bytes into the given array. Throws SocketTimeoutException on timeout.- Overrides:
readin classInputStream- Parameters:
target- byte array to read into- Returns:
- number of bytes read, or -1 on EOF
- Throws:
IOException- if stream is closed or read fails
read
Reads up tolengthbytes into thetargetarray atoffset. Blocks until data is available or timeout occurs.The lock is held only during state checks, waits, and index updates. The actual
System.arraycopy(Object, int, Object, int, int)is performed outside the synchronized block to reduce contention with the receive thread (messageReceived(long, ByteArray)). This is safe becauseByteArraypayloads are immutable once stored.- Overrides:
readin classInputStream- Parameters:
target- byte array to read intooffset- offset in array to start writinglength- number of bytes to read- Returns:
- number of bytes read, or -1 on EOF
- Throws:
IOException- if stream is closed or read fails
available
Returns an estimate of bytes readily available to read without blocking.- Overrides:
availablein classInputStream- Returns:
- number of bytes available for reading
- Throws:
IOException- if stream is closed or error occurred
getReadTimeout
public int getReadTimeout()Returns the current read timeout in milliseconds. -1 means block indefinitely, 0 means non-blocking.- Returns:
- read timeout in ms
setReadTimeout
public void setReadTimeout(int timeout) Read timeout in milliseconds. -1 means block indefinitely, 0 means non-blocking.- Parameters:
timeout- new read timeout
close
public void close()Closes the stream, clears all buffered data, and marks the stream as locally closed. Subsequent reads will throw IOException.- Specified by:
closein interfaceAutoCloseable- Specified by:
closein interfaceCloseable- Overrides:
closein classInputStream
streamErrorOccurred
Records a stream error and marks the stream as locally closed. Wakes up any waiting threads.- Parameters:
ioe- The IOException that occurred