Commit 19221fe8 authored by jan.koester's avatar jan.koester
Browse files

quic reset

parent 078b9a08
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -2880,6 +2880,16 @@ bool quic::isStreamComplete(uint64_t stream_id) const {
    return it->second.recv_complete;
}

bool quic::isStreamReset(uint64_t stream_id) const {
    std::lock_guard<std::recursive_mutex> lock(quic_mtx());

    auto it = _streams.find(stream_id);
    if (it == _streams.end()) {
        return false;
    }
    return it->second.reset;
}

// ============================================================================
// Frame Processing: Process individual frames
// ============================================================================
@@ -5435,6 +5445,42 @@ void quic::closeStream(uint64_t stream_id) {
    }
}

// ============================================================================
// RESET_STREAM: Abort a stream abnormally (RFC 9000 §19.4)
// ============================================================================

void quic::resetStream(uint64_t stream_id, uint64_t error_code) {
    std::lock_guard<std::recursive_mutex> lock(quic_mtx());

    auto it = _streams.find(stream_id);
    uint64_t final_size = (it != _streams.end()) ? it->second.send_offset : 0;

    std::vector<uint8_t> frame;
    frame.push_back(0x04); // RESET_STREAM frame type
    uint8_t buf[8];
    size_t bytes = encodeVarInt(stream_id, buf);
    frame.insert(frame.end(), buf, buf + bytes);
    bytes = encodeVarInt(error_code, buf);
    frame.insert(frame.end(), buf, buf + bytes);
    bytes = encodeVarInt(final_size, buf);
    frame.insert(frame.end(), buf, buf + bytes);

    std::vector<uint8_t> packet = buildShortHeaderPacket(frame);
    const uint8_t* hp_key = _is_server ? _app_hp_server : _app_hp_client;
    applyHeaderProtection(packet, hp_key);
    ssize_t sent = sendPacket(packet.data(), packet.size());
    if (sent < 0) {
        // Best-effort immediate retry — do not sleep here since the
        // caller typically holds quic_mtx().
        sendPacket(packet.data(), packet.size());
    }

    // No further STREAM frames should follow an abort.
    if (it != _streams.end()) {
        it->second.send_fin = true;
    }
}

// ============================================================================
// TLS 1.3 Handshake: sendClientHello (wrapper for connect flow)
// ============================================================================
+7 −0
Original line number Diff line number Diff line
@@ -642,6 +642,13 @@ namespace netplus {
		size_t recvStreamData(uint64_t stream_id, uint8_t* data, size_t max_len);
		bool hasStreamData(uint64_t stream_id) const;
		bool isStreamComplete(uint64_t stream_id) const;
		bool isStreamReset(uint64_t stream_id) const;

		// Abort a stream abnormally (RFC 9000 §19.4 RESET_STREAM). Use this
		// instead of sendStreamData(..., fin=true) when the body falls short
		// of the advertised Content-Length, so the peer sees a failed
		// transfer instead of silently accepting a truncated body as complete.
		void resetStream(uint64_t stream_id, uint64_t error_code = 0x0102);

		// Read raw UDP datagrams and process QUIC packets without consuming
		// stream data.  Use this in HTTP/3 client loops to pump the network