Commit 4adb6beb authored by jan.koester's avatar jan.koester
Browse files

test

parent 163b8983
Loading
Loading
Loading
Loading
+16 −4
Original line number Diff line number Diff line
@@ -7046,10 +7046,12 @@ void quic::closeStream(uint64_t stream_id) {
    // such no-op stream is needless wire traffic (observed to visibly
    // degrade unrelated traffic on the same connection when done in bulk).
    if (!stream.recv_fin && stream.send_offset > 0) {
        stopSending(stream_id);
        // Already confirmed to exist (it, above) — skip stopSending()'s own
        // existence check and go straight to the wire-building helper.
        sendStopSendingFrame(stream_id, 0x0102);
    }

    retireStreamIfDone(stream_id);
    retireStreamIfDone(stream_id, it);
}

// If a stream has terminated in both directions, erase it and — for a
@@ -7059,6 +7061,10 @@ void quic::closeStream(uint64_t stream_id) {
void quic::retireStreamIfDone(uint64_t stream_id) {
    auto it = _streams.find(stream_id);
    if (it == _streams.end()) return;
    retireStreamIfDone(stream_id, it);
}

void quic::retireStreamIfDone(uint64_t stream_id, std::unordered_map<uint64_t, Stream>::iterator it) {
    Stream& stream = it->second;

    // If both sides have sent FIN, remove stream and replenish peer's budget
@@ -7123,10 +7129,13 @@ void quic::resetStream(uint64_t stream_id, uint64_t error_code) {
    // No further STREAM frames should follow an abort.
    if (it != _streams.end()) {
        it->second.send_fin = true;
    }

        // Already have a valid iterator from the lookup above — pass it
        // directly instead of making retireStreamIfDone() re-find stream_id.
        retireStreamIfDone(stream_id, it);
    } else {
        retireStreamIfDone(stream_id);
    }
}

// ============================================================================
// STOP_SENDING: ask the peer to abort its send side (RFC 9000 §19.5)
@@ -7136,7 +7145,10 @@ void quic::stopSending(uint64_t stream_id, uint64_t error_code) {
    std::lock_guard<std::recursive_mutex> lock(quic_mtx());

    if (_streams.find(stream_id) == _streams.end()) return;
    sendStopSendingFrame(stream_id, error_code);
}

void quic::sendStopSendingFrame(uint64_t stream_id, uint64_t error_code) {
    std::vector<uint8_t> frame;
    frame.push_back(0x05); // STOP_SENDING frame type
    uint8_t buf[8];
+21 −2
Original line number Diff line number Diff line
@@ -888,6 +888,18 @@ namespace netplus {
		// to read buffered data or check isStreamReset()/hasStreamData()
		// after a STREAM/RESET_STREAM frame updates send_fin/recv_fin.
		void retireStreamIfDone(uint64_t stream_id);
		// Iterator-based variant: used by closeStream()/resetStream(), which
		// already hold a valid iterator from their own _streams lookup, so
		// one logical "close a stream" call doesn't re-find the same
		// stream_id 2-3 times over (F48). `it` must be a valid, dereferenceable
		// iterator (checked by the caller) — this overload skips the
		// existence check the stream_id-only version does.
		void retireStreamIfDone(uint64_t stream_id, std::unordered_map<uint64_t, Stream>::iterator it);

		// Wire-only STOP_SENDING send, no existence check — shared by the
		// public stopSending() (which checks first) and closeStream() (which
		// already knows the stream exists from its own lookup).
		void sendStopSendingFrame(uint64_t stream_id, uint64_t error_code);

		// Loss detection and retransmission
		void checkLossAndRetransmit();
@@ -1210,8 +1222,15 @@ namespace netplus {
		// itself is declared near the top of the private section, above).
		EncryptionLevel _current_enc_level = EncryptionLevel::Initial;

		// Streams
		std::map<uint64_t, Stream> _streams;
		// Streams. unordered_map, not map: stream_id has no ordering
		// requirement anywhere this is used (both iteration sites in
		// quic.cpp visit "every stream"/"any stream with data" without
		// relying on sort order — grep confirms it), so there is no reason
		// to pay std::map's O(log n) tree lookups on the hot per-STREAM-
		// frame lookup path when std::hash<uint64_t> gives O(1) average
		// lookup for free — mirrors the same std::map -> unordered_map
		// reasoning already applied to _child_connections.
		std::unordered_map<uint64_t, Stream> _streams;

		// Bounded tracking for "has this stream_id been fully closed"
		// (prevents resurrection via a stale/retransmitted frame after