java.lang.Object
net.i2p.client.streaming.impl.Packet
net.i2p.client.streaming.impl.PacketLocal
All Implemented Interfaces:
MessageOutputStream.WriteStatus

class PacketLocalextends Packet implements MessageOutputStream.WriteStatus
This is the class used for outbound packets.

coordinate local attributes about a packet - send time, ack time, number of retries, etc.

  • Field Details

    • _context

      private final I2PAppContext _context
      The app context.
    • _log

      private final Log _log
      Logger for the local packet record.
    • _connection

      private final Connection _connection
      The connection the packet was sent on.
    • _to

      private final Destination _to
      The peer the packet was sent to.
    • _createdOn

      private final long _createdOn
      When the packet was created.
    • _numSends

      private final AtomicInteger _numSends
      Times the packet has been sent.
    • _numSoftResends

      private final AtomicInteger _numSoftResends
      Resend attempts triggered by a router soft failure (NO_TUNNELS / EXPIRED / LOCAL).
    • _lastSend

      private volatile long _lastSend
      When the packet was last sent.
    • _acceptedOn

      private long _acceptedOn
      When the packet was acked, 0 while unacked.
    • _ackOn

      private long _ackOn
      LOCKING: this.
    • _cancelledOn

      private long _cancelledOn
      When the packet was cancelled, 0 while active.
    • _nackCount

      private final AtomicInteger _nackCount
      Nacks received for the packet.
    • _retransmitted

      private volatile boolean _retransmitted
      True once the packet was retransmitted.
    • _timeout

      private volatile int _timeout
      Timeout used waiting for the packet's ack.
    • _enqueued

      private volatile boolean _enqueued
      Whether this packet has been enqueued for I2CP send.
    • _payloadCache

      private static final ByteCache _payloadCache
      Cache supplying the payload buffers.
  • Constructor Details

    • PacketLocal

      public PacketLocal(I2PAppContext ctx, Destination to, I2PSession session)
      Constructor for a packet not bound to a connection.
      Parameters:
      ctx - the router context
      to - the remote destination the packet is addressed to
      session - the session used to send the packet
    • PacketLocal

      public PacketLocal(I2PAppContext ctx, Destination to, Connection con)
      Constructor for a packet bound to a connection.
      Parameters:
      ctx - the router context
      to - the remote destination the packet is addressed to
      con - the connection the packet is sent over
  • Method Details

    • setOptionalFrom

      public void setOptionalFrom()
      This sets the from field in the packet to the Destination for the session provided in the constructor. This also sets flag FLAG_FROM_INCLUDED. Also, as of 0.9.39, sets the offline signing data if supported by the session.
    • getTo

      public Destination getTo()
      The peer this packet was sent to.
      Returns:
      the peer's destination
    • shouldSign

      public boolean shouldSign()
      Whether this packet should be signed.
      Returns:
      true if this packet should be signed
    • getCreatedOn

      public long getCreatedOn()
      Read the router clock time at which this packet was created.
      Returns:
      the time this packet was created
    • getLifetime

      public long getLifetime()
      Lifetime of this packet.
      Returns:
      the lifetime of this packet in ms
    • incrementSends

      public void incrementSends()
      Increment the number of times this packet has been sent.
    • ackReceived

      public void ackReceived()
      Record that this packet was ACKed.
    • releasePayload

      public void releasePayload()
      Return the payload to the shared pool instead of letting it GC. Only returns buffers that came from the MAX_PAYLOAD_SIZE pool; zero-length or other-size payloads fall through to default no-op.

      Synchronized on this packet, the same monitor writeReleased() and the send path's serialize take, so the buffer cannot go back to the pool while a copy of it is in flight.

      Overrides:
      releasePayload in class Packet
    • getPayloadCache

      static ByteCache getPayloadCache()
      Shared outbound payload cache (MAX_PAYLOAD_SIZE buffers). Must match the cache in ConnectionDataReceiver._payloadCache.
      Returns:
      the static cache of outbound payload buffers
    • cancelled

      public void cancelled()
      Record that this packet was cancelled.
    • getAckTime

      public int getAckTime()
      How long after packet creation was it acked?
      Returns:
      how long after packet creation the packet was ACKed in ms
    • getRttTime

      public int getRttTime()
      RTT sample for an ACKed packet: time between its last transmission and its ACK.

      Unlike getAckTime() (which measures lifetime since creation and is used for the stream.sendsBeforeAck stat), this excludes queueing delay: a packet may sit in the outbound queue (pacing, choke, slow tunnel) long after creation, and folding that delay into the RTT sample inflates SRTT and pins RTO at its ceiling exactly when recovery is needed. Per RFC 6298 section 3, only packets sent once are valid RTT samples; callers gate on getNumSends() <= 1 before trusting the value.

      Returns:
      the RTT sample in ms, or -1 if the packet was never sent or never ACKed
    • rttSample

      static long rttSample(long ackOn, long lastSend)
      Pure RTT sample computation: ACK time minus last transmission time.

      The sample is only meaningful when the packet was transmitted exactly once (RFC 6298 section 3); resend bookkeeping is left to the caller so this helper stays testable without router context.

      Parameters:
      ackOn - time the packet was ACKed in ms since epoch
      lastSend - time of the last transmission in ms since epoch
      Returns:
      the RTT sample in ms, or -1 if either time is unknown (<= 0)
    • getNumSends

      public int getNumSends()
      Number of times sent.
      Returns:
      the number of times this packet has been sent
    • incrementSoftResends

      public void incrementSoftResends()
      Record a resend that was triggered by a router soft failure. Soft failures (NO_TUNNELS / EXPIRED / LOCAL) mean the packet was never put on the tunnel fabric, so the attempt should not consume the hard retransmit budget (see Connection.hardResendBudgetExceeded(int, int, int)).
    • getNumSoftResends

      public int getNumSoftResends()
      Number of send attempts that were router soft failures.
      Returns:
      the number of soft-failure-triggered resends
    • getLastSend

      public long getLastSend()
      Time of the last send.
      Returns:
      the time of the last send, or -1 if never sent
    • getConnection

      public Connection getConnection()
      Read the connection this packet is bound to.
      Returns:
      the bound connection, or null if not bound
    • incrementNACKs

      public void incrementNACKs()
      Count a NACK for this packet, and on the Connection.FAST_RETRANSMIT_THRESHOLDth one ask for a fast retransmit, provided the retransmit timer has demonstrably not already fired: the packet must have been sent at least max(4s, RTT) ago, and only the first such NACK storm triggers it. The retransmit is a no-op unless this is the lowest unacked packet (see Connection.ResendPacketEvent).
    • getNACKs

      public int getNACKs()
      Warning: This is different than getNacks() in super.
      Returns:
      Number of times this packet has been nacked
    • getTimeout

      public int getTimeout()
      Used by PacketQueue to feed an expiration to the router.
      Returns:
      time from now, not absolute time. May be zero if unset.
    • setTimeout

      public void setTimeout(int timeout)
      Timeout for this packet.
      Parameters:
      timeout - time from now, not absolute time
    • writeSignedPacket

      public int writeSignedPacket(byte[] buffer, int offset) throws IllegalStateException
      Sign and write the packet to the buffer (starting at the offset) and return the number of bytes written.
      Parameters:
      buffer - data to be written
      offset - starting point in the buffer
      Returns:
      Count of bytes written
      Throws:
      IllegalStateException - if the offline signature has expired, or if signing the packet failed
    • formatAsString

      public StringBuilder formatAsString()
      Format as a string builder for logging, full form.

      Not gated on the log level: every caller builds this from inside a log message that has already passed its own shouldXxx() test, so gating the description on INFO meant a WARN or ERROR about a packet logged an empty string - the one thing that makes such a message useless. The bulky parts (the NACK list, offline key material) stay behind shouldDebug(). The description is two lines: the header (stream IDs and sequence number), then one " * " continuation line carrying the flags, options and payload size together.

      Overrides:
      formatAsString in class Packet
      Returns:
      a buffer holding the human readable form of this packet, ready to be appended to a log message
    • formatAsString

      public StringBuilder formatAsString(boolean withContext)
      Format as a string builder for logging.

      With withContext false this drops the send count and the connection pair - the caller's connection prefix already names both endpoints, and the count rides in its message.

      Overrides:
      formatAsString in class Packet
      Parameters:
      withContext - when false, omit the facts the caller's own message already carries - the stream-ID header and the sequence number here, the send count and the connection pair in PacketLocal: a caller that leads with the connection prefix must not print them a second time
      Returns:
      a buffer holding the human readable form of this packet, ready to be appended to a log message
    • waitForAccept

      public void waitForAccept(int maxWaitMs) throws IOException, InterruptedException
      Blocks until outbound window is not full. See Connection.packetSendChoke(long).
      Specified by:
      waitForAccept in interface MessageOutputStream.WriteStatus
      Parameters:
      maxWaitMs - MessageOutputStream is the only caller, generally with -1
      Throws:
      IOException - if the connection is closed
      InterruptedException - if the thread is interrupted
    • waitForCompletion

      public void waitForCompletion(int maxWaitMs) throws IOException, InterruptedException
      Block until the packet is acked from the far end.
      Specified by:
      waitForCompletion in interface MessageOutputStream.WriteStatus
      Parameters:
      maxWaitMs - maximum time to wait in ms
      Throws:
      IOException - if the connection is reset or cancelled
      InterruptedException - if the thread is interrupted
    • isAckStarvation

      static boolean isAckStarvation(boolean packetAcked, long highestAckedThrough, long ackProgressAtStart)
      Pure decision rule for the write-timeout ACK-starvation fail-fast.

      When a waitForCompletion reaches its write timeout with this packet still unacknowledged, the send should be treated as failed (rather than silently timing out and dropping the payload) only when the connection made no forward ACK progress at all while we waited. If any other packet was acknowledged during the window, the connection is slow but alive, and this packet's ACK is likely merely coalesced or lost — we must NOT fail it (avoid a false positive that would truncate a legitimate slow-but-progressing transfer).

      This was extracted as a pure static method so the fail-fast rule is unit-testable without a live Connection (mirrors the getAdaptiveSynTimeout evidence-gated pattern).

      Parameters:
      packetAcked - whether the specific packet was acknowledged (WriteStatus.writeSuccessful())
      highestAckedThrough - current connection-wide forward-ACK progress (Connection.getHighestAckedThrough())
      ackProgressAtStart - forward-ACK progress captured at wait start
      Returns:
      true if this is unambiguously ACK starvation and the send should fail fast; false if the connection made progress (or the packet was acked) and the send should be left to the normal timeout path
    • isCancelled

      private boolean isCancelled()
      Whether this packet was cancelled.
      Returns:
      true if this packet was cancelled
    • writeAccepted

      public boolean writeAccepted()
      Whether the send was accepted.
      Specified by:
      writeAccepted in interface MessageOutputStream.WriteStatus
      Returns:
      true if this packet was accepted for sending
    • writeFailed

      public boolean writeFailed()
      Whether the send failed.
      Specified by:
      writeFailed in interface MessageOutputStream.WriteStatus
      Returns:
      true if this packet's send failed
    • writeSuccessful

      public boolean writeSuccessful()
      Whether the send succeeded and was ACKed.
      Returns:
      true if this packet was successfully sent and ACKed
    • writeReleased

      public boolean writeReleased()
      Whether this packet's payload has been released and it can no longer be (re)transmitted.

      Both ackReceived() and cancelled() call releasePayload(), which returns this packet's buffer to the shared outbound payload cache and clears _payload. Once either has run the packet must never be enqueued again — a (re)send would read a null payload and crash the I2CP write. isCancelled() alone is insufficient: an ACKed-but-not-cancelled packet also has a released payload.

      This is the discriminator the retransmit timer uses to skip packets that were acknowledged or cancelled after it snapshotted the outbound set (a use-after-release TOCTOU between Connection.ackPackets and Connection.RetransmitEvent.timeReached), mirroring the paced-path guard on getAckTime().

      Returns:
      true if the packet was ACKed or cancelled, so its payload was released; false if it may still be transmitted
    • logTCPDump

      public void logTCPDump()
      Generate a pcap/tcpdump-compatible format, so we can use standard debugging tools.
    • markEnqueued

      public void markEnqueued()
      Flag this packet as handed to I2CP for sending.
    • isEnqueued

      public boolean isEnqueued()
      Report whether this packet has been queued for I2CP send.
      Returns:
      true if this packet has been queued for I2CP send