java.lang.Object
net.i2p.router.tunnel.FragmentedMessage

class FragmentedMessageextends Object
Gather fragments of I2NPMessages at a tunnel endpoint, making them available for reading when complete.

Warning - this is all unsynchronized here - receivers must implement synchronization.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private static final ByteCache
    Cache supplying the fragment buffers.
    private boolean
    True once all fragments are in.
    private final I2PAppContext
    The app context.
    private final long
    When the reassembly started.
    Timer dropping the incomplete reassembly.
    private final ByteArray[]
    The fragments received so far.
    private int
    Highest fragment number received.
    private boolean
    True once the final fragment arrived.
    private final Log
    Logger for the fragmented message.
    private final long
    Id of the message being reassembled.
    private long
    When the reassembly is dropped if incomplete.
    private Hash
    The router the message goes to.
    private TunnelId
    The tunnel the message goes through.
    private static final int
    Largest fragment, in bytes.
    private static final int
    Most fragments in one message, even 32 is unlikely.
  • Constructor Summary

    Constructors
    Constructor
    Description
    FragmentedMessage(I2PAppContext ctx, long messageId)
    Starts an empty reassembly buffer for one message id.
  • Method Summary

    Modifier and Type
    Method
    Description
    (package private) static int
    countFragments(ByteArray[] fragments, int highFragmentNum)
    Count the non-null fragment slots from 0 through the high-water mark.
    void
    Releases the fragments, marking the message as failed.
    int
    The size of the complete message, in bytes.
    Used in the fragment handler so we can cancel the expire event on success.
    int
    The number of fragments received so far.
    long
    How long has this fragmented message been alive?
    long
    The unique ID of this fragmented message.
    boolean
    Whether this message has been released after completion.
    long
    The lifetime at which the fragments were released, or 0 if not yet released.
    The router this message is being sent to.
    The tunnel this message is being sent to.
    boolean
    Have we received all of the fragments?
    boolean
    receive(byte[] payload, int offset, int length, boolean isLast, Hash toRouter, TunnelId toTunnel)
    Receive the first fragment (#0) and related metadata.
    boolean
    receive(int fragmentNum, byte[] payload, int offset, int length, boolean isLast)
    Receive a followup fragment, though one of these may arrive at the endpoint prior to the fragment # 0.
    private void
    Called as one of the endpoints for the tunnel cache pipeline (see TunnelDataMessage).
    void
    The expire event to cancel when this message completes.
    byte[]
    The complete reassembled message data, freeing the fragments.
    Debug description of the message ID and the received fragments.
    private void
    writeComplete(byte[] target, int offset)
    Writes the reassembled message to the buffer.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
  • Field Details

    • _context

      private final I2PAppContext _context
      The app context.
    • _log

      private final Log _log
      Logger for the fragmented message.
    • _messageId

      private final long _messageId
      Id of the message being reassembled.
    • _toRouter

      private Hash _toRouter
      The router the message goes to.
    • _toTunnel

      private TunnelId _toTunnel
      The tunnel the message goes through.
    • _fragments

      private final ByteArray[] _fragments
      The fragments received so far.
    • _lastReceived

      private volatile boolean _lastReceived
      True once the final fragment arrived.
    • _highFragmentNum

      private volatile int _highFragmentNum
      Highest fragment number received.
    • _createdOn

      private final long _createdOn
      When the reassembly started.
    • _completed

      private volatile boolean _completed
      True once all fragments are in.
    • _releasedAfter

      private volatile long _releasedAfter
      When the reassembly is dropped if incomplete.
    • _expireEvent

      private SimpleTimer2.TimedEvent _expireEvent
      Timer dropping the incomplete reassembly.
    • _cache

      private static final ByteCache _cache
      Cache supplying the fragment buffers.
    • MAX_FRAGMENTS

      private static final int MAX_FRAGMENTS
      Most fragments in one message, even 32 is unlikely.
      See Also:
    • MAX_FRAGMENT_SIZE

      private static final int MAX_FRAGMENT_SIZE
      Largest fragment, in bytes.
      See Also:
  • Constructor Details

    • FragmentedMessage

      public FragmentedMessage(I2PAppContext ctx, long messageId)
      Starts an empty reassembly buffer for one message id.
      Parameters:
      ctx - the context supplying the clock and log used by this message
      messageId - the id that ties the fragments of one message together
  • Method Details

    • receive

      public boolean receive(int fragmentNum, byte[] payload, int offset, int length, boolean isLast)
      Receive a followup fragment, though one of these may arrive at the endpoint prior to the fragment # 0.
      Parameters:
      fragmentNum - sequence number within the message (1 - 63)
      payload - data for the fragment non-null
      offset - index into the payload where the fragment data starts (past headers/etc)
      length - how much past the offset should we snag?
      isLast - is this the last fragment in the message?
      Returns:
      true if the fragment was stored, false if the number, the length or the offset range was out of bounds
    • receive

      public boolean receive(byte[] payload, int offset, int length, boolean isLast, Hash toRouter, TunnelId toTunnel)
      Receive the first fragment (#0) and related metadata. This may not be the first one to arrive at the endpoint however.
      Parameters:
      payload - data for the fragment non-null
      offset - index into the payload where the fragment data starts (past headers/etc)
      length - how much past the offset should we snag?
      isLast - is this the last fragment in the message?
      toRouter - what router is this destined for (may be null)
      toTunnel - what tunnel is this destined for (may be null)
      Returns:
      true if the fragment was stored, false if the length or the offset range was out of bounds
    • getMessageId

      public long getMessageId()
      The unique ID of this fragmented message.
      Returns:
      the message id
    • getTargetRouter

      public Hash getTargetRouter()
      The router this message is being sent to.
      Returns:
      the target router
    • getTargetTunnel

      public TunnelId getTargetTunnel()
      The tunnel this message is being sent to.
      Returns:
      the target tunnel
    • getFragmentCount

      public int getFragmentCount()
      The number of fragments received so far.
      Returns:
      the fragment count
    • countFragments

      static int countFragments(ByteArray[] fragments, int highFragmentNum)
      Count the non-null fragment slots from 0 through the high-water mark.

      Slots above highFragmentNum cannot be non-null: both receive(int, byte[], int, int, boolean) overloads raise the mark to at least the index they store into, and the mark is never lowered, so scanning past it cannot add to the count. Bounding the scan therefore costs nothing in accuracy while skipping the unused tail of the array, and it makes this accessor agree with isComplete(), getCompleteSize(), writeComplete(byte[], int) and releaseFragments(), all of which already stop at the mark.

      Static and driven by its parameters so the scan can be exercised without an I2PAppContext. The high-water mark is passed in rather than read in the loop condition: it is only ever increased, and passing it as an argument reads the volatile field exactly once instead of on every iteration.

      Parameters:
      fragments - fragment slots, indexed by fragment number; not null
      highFragmentNum - highest fragment number received, or -1 if none received
      Returns:
      the number of non-null slots in 0..highFragmentNum, zero if none received
      Throws:
      NullPointerException - if fragments is null and the range to scan is non-empty
    • getExpireEvent

      public SimpleTimer2.TimedEvent getExpireEvent()
      Used in the fragment handler so we can cancel the expire event on success.
      Returns:
      the scheduled expiry event, or null if none has been set
    • setExpireEvent

      public void setExpireEvent(SimpleTimer2.TimedEvent evt)
      The expire event to cancel when this message completes.
      Parameters:
      evt - the timer event to cancel on completion
    • isComplete

      public boolean isComplete()
      Have we received all of the fragments?
      Returns:
      true if the last fragment has been seen and no slot up to the high-water mark is still empty
    • getCompleteSize

      public int getCompleteSize()
      The size of the complete message, in bytes.
      Returns:
      the complete size
    • getLifetime

      public long getLifetime()
      How long has this fragmented message been alive?
      Returns:
      the milliseconds elapsed since construction
    • getReleased

      public boolean getReleased()
      Whether this message has been released after completion.
      Returns:
      true once every fragment has been written out to the caller's buffer, after which this message must not be read again
    • writeComplete

      private void writeComplete(byte[] target, int offset)
      Writes the reassembled message to the buffer.
      Parameters:
      target - the buffer to write into
      offset - where to start writing
    • toByteArray

      public byte[] toByteArray()
      The complete reassembled message data, freeing the fragments.
      Returns:
      the concatenated fragment data, or null if the fragments have already been released
    • getReleasedAfter

      public long getReleasedAfter()
      The lifetime at which the fragments were released, or 0 if not yet released.
      Returns:
      the released after
    • failed

      public void failed()
      Releases the fragments, marking the message as failed.
    • releaseFragments

      private void releaseFragments()
      Called as one of the endpoints for the tunnel cache pipeline (see TunnelDataMessage).
    • toString

      public String toString()
      Debug description of the message ID and the received fragments.
      Overrides:
      toString in class Object