Commit d305257f authored by jan.koester's avatar jan.koester
Browse files

deb



Co-authored-by: default avatarCopilot <copilot@github.com>
parent 1c7379fa
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
libnetplus (20260503+4) unstable; urgency=high

  * QUIC: CRITICAL FIX — flushBatch() was unconditionally clearing all queued
    packets even when sendmmsg() returned a partial batch count, causing
    silent packet loss (dropped STORE_BLOCK responses, timeouts on write-heavy
    traffic). Now only successfully sent packets are removed; unsent packets
    remain queued for retry.

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 03 May 2026 18:30:00 +0200

libnetplus (20260502+1) unstable; urgency=medium

  * QUIC: add udp::recvBatchAddr() — batch receive with peer addresses
+25 −4
Original line number Diff line number Diff line
@@ -3701,9 +3701,28 @@ void quic::checkLossAndRetransmit() {
// ============================================================================

void quic::sendStreamData(uint64_t stream_id, const std::vector<uint8_t>& data, bool fin) {
    // Delegate to the fast-path variant which uses batching, CC gating,
    // and ACK piggybacking for much better throughput.
    sendStreamData(stream_id, data.data(), data.size(), fin);
    // Retry until all data is sent or connection is lost.
    // The size_t variant may return early when congestion control blocks;
    // we must loop to ensure the full message (including FIN) reaches the peer.
    size_t offset = 0;
    size_t remaining = data.size();
    int stall_count = 0;
    while (remaining > 0) {
        size_t sent = sendStreamData(stream_id, data.data() + offset, remaining, fin);
        if (sent == 0) {
            if (++stall_count > 50) break; // give up after ~5s of total CC stall
            // Pump incoming to process ACKs and open congestion window
            pumpIncoming();
            continue;
        }
        stall_count = 0;
        offset += sent;
        remaining -= sent;
    }
    // Handle FIN-only (empty data with fin flag)
    if (data.empty() && fin) {
        sendStreamData(stream_id, data.data(), 0, true);
    }
}

// ============================================================================
@@ -4808,7 +4827,9 @@ size_t quic::sendStreamData(uint64_t stream_id, const uint8_t* data, size_t len,
        flushBatch();
    }

    if (fin) {
    // Only mark FIN if we actually sent all requested data (FIN is on the last chunk).
    // If CC broke the loop early, the FIN was never put on the wire.
    if (fin && sent_total >= send_len) {
        stream.send_fin = true;
        // Auto-cleanup: both sides FIN'd → erase stream & replenish peer's stream budget
        if (stream.recv_fin) {