sendStreamPacket method

void sendStreamPacket(
  1. int dstStreamId,
  2. int srcStreamId,
  3. List<Frame> frames, {
  4. bool trackForRetransmit = true,
})

Sends a packet with the given frames on behalf of a stream. Uses connection-level sequence numbers (per QUIC RFC 9000). If trackForRetransmit is true, the packet is registered with the PacketManager for retransmission and congestion control.

Implementation

void sendStreamPacket(int dstStreamId, int srcStreamId, List<Frame> frames, {bool trackForRetransmit = true}) {
  if (_closing) return;

  // Determine if this packet carries stream data (data, SYN, or FIN).
  // Control-only packets (WindowUpdate, ACK, etc.) use seq=0 to avoid
  // consuming sequence numbers that create gaps in the receiver's ordered
  // delivery. This matches the Go UDX sendPacket() logic.
  bool hasData = false;
  int dataSize = 0;
  for (final frame in frames) {
    if (frame is StreamFrame) {
      dataSize += frame.data.length;
      if (frame.data.isNotEmpty || frame.isSyn || frame.isFin) {
        hasData = true;
      }
    }
  }

  final seq = hasData ? _packetManager.nextSequence : 0;
  final packet = UDXPacket(
    destinationCid: cids.remoteCid,
    sourceCid: cids.localCid,
    destinationStreamId: dstStreamId,
    sourceStreamId: srcStreamId,
    sequence: seq,
    frames: frames,
  );

  if (hasData && trackForRetransmit) {
    _packetManager.sendPacket(packet);
    _congestionController.onPacketSent(dataSize);
    _sentPacketsForRtt[seq] = (DateTime.now(), dataSize);
  }

  send(packet.toBytes());

  if (dataSize > 0) {
    incrementConnectionBytesSent(dataSize);
    _congestionController.pacingController.onPacketSent(packet.toBytes().length);
  }
}