diff --git a/quic/CMakeLists.txt b/quic/CMakeLists.txt index dffa87870..04951ca58 100644 --- a/quic/CMakeLists.txt +++ b/quic/CMakeLists.txt @@ -80,7 +80,6 @@ add_subdirectory(client) add_subdirectory(codec) add_subdirectory(common) add_subdirectory(congestion_control) -add_subdirectory(dsr) add_subdirectory(fizz) add_subdirectory(flowcontrol) add_subdirectory(folly_utils) diff --git a/quic/api/QuicPacketScheduler.cpp b/quic/api/QuicPacketScheduler.cpp index 7eeba0221..06f2b113f 100644 --- a/quic/api/QuicPacketScheduler.cpp +++ b/quic/api/QuicPacketScheduler.cpp @@ -532,10 +532,6 @@ quic::Expected StreamFrameScheduler::writeStreamsHelper( do { auto streamId = level.iterator->current(); auto stream = CHECK_NOTNULL(conn_.streamManager->findStream(streamId)); - if (!stream->hasSchedulableData() && stream->hasSchedulableDsr()) { - // We hit a DSR stream - return {}; - } CHECK(stream) << "streamId=" << streamId << "inc=" << uint64_t(level.incremental); auto writeResult = writeSingleStream(builder, *stream, connWritableBytes); @@ -576,10 +572,6 @@ quic::Expected StreamFrameScheduler::writeStreamsHelper( CHECK(id.isStreamID()); auto streamId = id.asStreamID(); auto stream = CHECK_NOTNULL(conn_.streamManager->findStream(streamId)); - if (!stream->hasSchedulableData() && stream->hasSchedulableDsr()) { - // We hit a DSR stream - return {}; - } CHECK(stream) << "streamId=" << streamId; // TODO: this is counting STREAM frame overhead against the stream itself auto lastWriteBytes = builder.remainingSpaceInPkt(); @@ -630,7 +622,6 @@ quic::Expected StreamFrameScheduler::writeStreams( conn_.schedulingState.nextScheduledControlStream = result.value(); } auto* oldWriteQueue = conn_.streamManager->oldWriteQueue(); - QuicStreamState* nextStream{nullptr}; if (oldWriteQueue) { if (!oldWriteQueue->empty()) { auto result = writeStreamsHelper( @@ -641,8 +632,6 @@ quic::Expected StreamFrameScheduler::writeStreams( if (!result.has_value()) { return quic::make_unexpected(result.error()); } - auto streamId = oldWriteQueue->getNextScheduledStream(); - nextStream = conn_.streamManager->findStream(streamId); } } else { auto& writeQueue = conn_.streamManager->writeQueue(); @@ -655,29 +644,15 @@ quic::Expected StreamFrameScheduler::writeStreams( if (!result.has_value()) { return quic::make_unexpected(result.error()); } - if (!writeQueue.empty()) { - auto id = writeQueue.peekNextScheduledID(); - CHECK(id.isStreamID()); - nextStream = conn_.streamManager->findStream(id.asStreamID()); - } } } - // If the next non-control stream is DSR, record that fact in the - // scheduler so that we don't try to write a non DSR stream again. - // Note that this means that in the presence of many large control - // streams and DSR streams, we won't completely prioritize control - // streams but they will not be starved. - if (nextStream && !nextStream->hasSchedulableData()) { - nextStreamDsr_ = true; - } return {}; } bool StreamFrameScheduler::hasPendingData() const { - return !nextStreamDsr_ && - (conn_.streamManager->hasNonDSRLoss() || - (conn_.streamManager->hasNonDSRWritable() && - getSendConnFlowControlBytesWire(conn_) > 0)); + return conn_.streamManager->hasLoss() || + (conn_.streamManager->hasWritable() && + getSendConnFlowControlBytesWire(conn_) > 0); } quic::Expected StreamFrameScheduler::writeStreamFrame( @@ -695,9 +670,8 @@ quic::Expected StreamFrameScheduler::writeStreamFrame( uint64_t flowControlLen = std::min(getSendStreamFlowControlBytesWire(stream), connWritableBytes); uint64_t bufferLen = stream.pendingWrites.chainLength(); - // We should never write a FIN from the non-DSR scheduler for a DSR stream. - bool canWriteFin = stream.finalWriteOffset.has_value() && - bufferLen <= flowControlLen && stream.writeBufMeta.offset == 0; + bool canWriteFin = + stream.finalWriteOffset.has_value() && bufferLen <= flowControlLen; auto writeOffset = stream.currentWriteOffset; auto res = writeStreamFrameHeader( builder, @@ -741,8 +715,7 @@ quic::Expected RstStreamScheduler::writeRsts( conn_.streamManager->getStream(streamId).value_or(nullptr); CHECK(streamState) << "Stream " << streamId << " not found when going through resets"; - if (streamState->pendingWrites.empty() && - streamState->writeBufMeta.length == 0) { + if (streamState->pendingWrites.empty()) { // We only write a RESET_STREAM or RESET_STREAM_AT frame for a stream // once we've written out all data that needs to be delivered reliably. // While this is not something that's mandated by the spec, we're doing @@ -1029,8 +1002,7 @@ CloningScheduler::CloningScheduler( cipherOverhead_(cipherOverhead) {} bool CloningScheduler::hasData() const { - return frameScheduler_.hasData() || - conn_.outstandings.numOutstanding() > conn_.outstandings.dsrCount; + return frameScheduler_.hasData() || conn_.outstandings.numOutstanding() > 0; } quic::Expected @@ -1053,7 +1025,7 @@ CloningScheduler::scheduleFramesForPacket( std::move(builder).releaseOutputBuffer(); // Look for an outstanding packet that's no larger than the writableBytes for (auto& outstandingPacket : conn_.outstandings.packets) { - if (outstandingPacket.declaredLost || outstandingPacket.isDSRPacket) { + if (outstandingPacket.declaredLost) { continue; } auto opPnSpace = outstandingPacket.packet.header.getPacketNumberSpace(); diff --git a/quic/api/QuicPacketScheduler.h b/quic/api/QuicPacketScheduler.h index d1b160f9f..d268e1a46 100644 --- a/quic/api/QuicPacketScheduler.h +++ b/quic/api/QuicPacketScheduler.h @@ -137,7 +137,6 @@ class StreamFrameScheduler { uint64_t& connWritableBytes); QuicConnectionStateBase& conn_; - bool nextStreamDsr_{false}; }; class RstStreamScheduler { diff --git a/quic/api/QuicSocket.h b/quic/api/QuicSocket.h index 5d79a1d01..ffc13ffa5 100644 --- a/quic/api/QuicSocket.h +++ b/quic/api/QuicSocket.h @@ -22,8 +22,6 @@ namespace quic { -class DSRPacketizationRequestSender; - class QuicSocket : virtual public QuicSocketLite { public: /** diff --git a/quic/api/QuicSocketLite.h b/quic/api/QuicSocketLite.h index 0464ce04c..349a2e0d6 100644 --- a/quic/api/QuicSocketLite.h +++ b/quic/api/QuicSocketLite.h @@ -515,22 +515,6 @@ class QuicSocketLite { bool eof, ByteEventCallback* cb = nullptr) = 0; - /** - * Write a data representation in the form of BufferMeta to the given stream. - */ - virtual WriteResult writeBufMeta( - StreamId id, - const BufferMeta& data, - bool eof, - ByteEventCallback* cb = nullptr) = 0; - - /** - * Set the DSRPacketizationRequestSender for a stream. - */ - virtual WriteResult setDSRPacketizationRequestSender( - StreamId id, - std::unique_ptr sender) = 0; - /** * Close the stream for writing. Equivalent to writeChain(id, nullptr, true). */ diff --git a/quic/api/QuicTransportBaseLite.cpp b/quic/api/QuicTransportBaseLite.cpp index 3676ba2d7..3de3b1aac 100644 --- a/quic/api/QuicTransportBaseLite.cpp +++ b/quic/api/QuicTransportBaseLite.cpp @@ -1519,7 +1519,6 @@ void QuicTransportBaseLite::closeImpl( uint64_t(conn_->transportSettings.timeReorderingThreshDividend), conn_->usedZeroRtt, conn_->version.value_or(QuicVersion::MVFST_INVALID), - conn_->dsrPacketCount, conn_->initialPacketsReceived, conn_->uniqueInitialCryptoFramesReceived, timeUntilLastInitialCryptoFrameReceived, diff --git a/quic/api/QuicTransportFunctions.cpp b/quic/api/QuicTransportFunctions.cpp index aa3dd4dae..341dddc34 100644 --- a/quic/api/QuicTransportFunctions.cpp +++ b/quic/api/QuicTransportFunctions.cpp @@ -472,18 +472,6 @@ iobufChainBasedBuildScheduleEncrypt( namespace quic { -void handleNewStreamBufMetaWritten( - QuicStreamState& stream, - uint64_t frameLen, - bool frameFin); - -void handleRetransmissionBufMetaWritten( - QuicStreamState& stream, - uint64_t frameOffset, - uint64_t frameLen, - bool frameFin, - const decltype(stream.lossBufMetas)::iterator lossBufMetaIter); - bool writeLoopTimeLimit( TimePoint loopBeginTime, const QuicConnectionStateBase& connection) { @@ -517,28 +505,6 @@ void handleNewStreamDataWritten( .second); } -void handleNewStreamBufMetaWritten( - QuicStreamState& stream, - uint64_t frameLen, - bool frameFin) { - CHECK_GT(stream.writeBufMeta.offset, 0); - auto originalOffset = stream.writeBufMeta.offset; - auto bufMetaSplit = stream.writeBufMeta.split(frameLen); - CHECK_EQ(bufMetaSplit.offset, originalOffset); - if (frameFin) { - // If FIN is written, nothing should be left in the writeBufMeta. - CHECK_EQ(0, stream.writeBufMeta.length); - ++stream.writeBufMeta.offset; - CHECK_GT(stream.writeBufMeta.offset, *stream.finalWriteOffset); - } - CHECK(stream.retransmissionBufMetas - .emplace( - std::piecewise_construct, - std::forward_as_tuple(originalOffset), - std::forward_as_tuple(bufMetaSplit)) - .second); -} - void handleRetransmissionWritten( QuicStreamLike& stream, uint64_t frameOffset, @@ -572,32 +538,6 @@ void handleRetransmissionWritten( } } -void handleRetransmissionBufMetaWritten( - QuicStreamState& stream, - uint64_t frameOffset, - uint64_t frameLen, - bool frameFin, - const decltype(stream.lossBufMetas)::iterator lossBufMetaIter) { - if (frameLen == lossBufMetaIter->length && frameFin == lossBufMetaIter->eof) { - stream.lossBufMetas.erase(lossBufMetaIter); - } else { - CHECK_GT(lossBufMetaIter->length, frameLen); - lossBufMetaIter->length -= frameLen; - lossBufMetaIter->offset += frameLen; - } - CHECK(stream.retransmissionBufMetas - .emplace( - std::piecewise_construct, - std::forward_as_tuple(frameOffset), - std::forward_as_tuple( - WriteBufferMeta::Builder() - .setOffset(frameOffset) - .setLength(frameLen) - .setEOF(frameFin) - .build())) - .second); -} - /** * Update the connection and stream state after stream data is written and deal * with new data, as well as retranmissions. Returns true if the data sent is @@ -664,50 +604,6 @@ quic::Expected handleStreamWritten( return false; } -bool handleStreamBufMetaWritten( - QuicConnectionStateBase& conn, - QuicStreamState& stream, - uint64_t frameOffset, - uint64_t frameLen, - bool frameFin, - PacketNum packetNum, - PacketNumberSpace packetNumberSpace) { - auto writtenNewData = false; - // Handle new data first - if (stream.writeBufMeta.offset > 0 && - frameOffset == stream.writeBufMeta.offset) { - handleNewStreamBufMetaWritten(stream, frameLen, frameFin); - writtenNewData = true; - } - - if (writtenNewData) { - // Count packet. It's based on the assumption that schedluing scheme will - // only writes one STREAM frame for a stream in a packet. If that doesn't - // hold, we need to avoid double-counting. - ++stream.numPacketsTxWithNewData; - VLOG(10) << nodeToString(conn.nodeType) << " sent" - << " packetNum=" << packetNum << " space=" << packetNumberSpace - << " " << conn; - return true; - } - - auto lossBufMetaIter = std::lower_bound( - stream.lossBufMetas.begin(), - stream.lossBufMetas.end(), - frameOffset, - [](const auto& bufMeta, auto offset) { return bufMeta.offset < offset; }); - // We do not clone BufMeta right now. So the data has to be in lossBufMetas. - CHECK(lossBufMetaIter != stream.lossBufMetas.end()); - CHECK_EQ(lossBufMetaIter->offset, frameOffset); - handleRetransmissionBufMetaWritten( - stream, frameOffset, frameLen, frameFin, lossBufMetaIter); - conn.lossState.totalBytesRetransmitted += frameLen; - VLOG(10) << nodeToString(conn.nodeType) << " sent retransmission" - << " packetNum=" << packetNum << " " << conn; - QUIC_STATS(conn.statsCallback, onPacketRetransmission); - return false; -} - quic::Expected updateConnection( QuicConnectionStateBase& conn, const PathInfo& pathInfo, @@ -715,8 +611,7 @@ quic::Expected updateConnection( RegularQuicWritePacket packet, TimePoint sentTime, uint32_t encodedSize, - uint32_t encodedBodySize, - bool isDSRPacket) { + uint32_t encodedBodySize) { auto packetNum = packet.header.getPacketSequenceNum(); // AckFrame, PaddingFrame and Datagrams are not retx-able. bool retransmittable = false; @@ -730,8 +625,7 @@ quic::Expected updateConnection( auto packetNumberSpace = packet.header.getPacketNumberSpace(); VLOG(10) << nodeToString(conn.nodeType) << " sent packetNum=" << packetNum << " in space=" << packetNumberSpace << " size=" << encodedSize - << " bodySize: " << encodedBodySize << " isDSR=" << isDSRPacket - << " " << conn; + << " bodySize: " << encodedBodySize << " " << conn; if (conn.qLogger) { conn.qLogger->addPacket(packet, encodedSize); } @@ -748,29 +642,18 @@ quic::Expected updateConnection( } auto stream = streamResult.value(); bool newStreamDataWritten = false; - if (writeStreamFrame.fromBufMeta) { - newStreamDataWritten = handleStreamBufMetaWritten( - conn, - *stream, - writeStreamFrame.offset, - writeStreamFrame.len, - writeStreamFrame.fin, - packetNum, - packetNumberSpace); - } else { - auto streamWrittenResult = handleStreamWritten( - conn, - *stream, - writeStreamFrame.offset, - writeStreamFrame.len, - writeStreamFrame.fin, - packetNum, - packetNumberSpace); - if (!streamWrittenResult.has_value()) { - return quic::make_unexpected(streamWrittenResult.error()); - } - newStreamDataWritten = streamWrittenResult.value(); + auto streamWrittenResult = handleStreamWritten( + conn, + *stream, + writeStreamFrame.offset, + writeStreamFrame.len, + writeStreamFrame.fin, + packetNum, + packetNumberSpace); + if (!streamWrittenResult.has_value()) { + return quic::make_unexpected(streamWrittenResult.error()); } + newStreamDataWritten = streamWrittenResult.value(); if (newStreamDataWritten) { auto flowControlResult = updateFlowControlOnWriteToSocket(*stream, writeStreamFrame.len); @@ -936,17 +819,13 @@ quic::Expected updateConnection( } } - // This increments the next packet number and (potentially) the next non-DSR - // packet sequence number. Capture the non DSR sequence number before - // increment. auto& ackState = getAckState(conn, packetNumberSpace); - auto nonDsrPacketSequenceNumber = ackState.nonDsrPacketSequenceNumber; - increaseNextPacketNum(conn, packetNumberSpace, isDSRPacket); + increaseNextPacketNum(conn, packetNumberSpace); if (!ackState.skippedPacketNum.has_value() && folly::Random::oneIn( conn.transportSettings.skipOneInNPacketSequenceNumber)) { ackState.skippedPacketNum = ackState.nextPacketNum; - increaseNextPacketNum(conn, packetNumberSpace, isDSRPacket); + increaseNextPacketNum(conn, packetNumberSpace); } conn.lossState.largestSent = std::max(conn.lossState.largestSent.value_or(packetNum), packetNum); @@ -1042,15 +921,6 @@ quic::Expected updateConnection( pkt.maybeClonedPacketIdentifier = std::move(clonedPacketIdentifier); conn.lossState.totalBytesCloned += encodedSize; } - pkt.isDSRPacket = isDSRPacket; - if (isDSRPacket) { - ++conn.outstandings.dsrCount; - QUIC_STATS(conn.statsCallback, onDSRPacketSent, encodedSize); - } else { - // If it's not a DSR packet, set the sequence number to the previous one, - // as the state currently is the _next_ one after this packet. - pkt.nonDsrPacketSequenceNumber = nonDsrPacketSequenceNumber; - } if (conn.congestionController) { addAndCheckOverflow( @@ -1916,8 +1786,7 @@ quic::Expected writeConnectionDataToSocket( std::move(result->packet->packet), sentTime, static_cast(ret->encodedSize), - static_cast(ret->encodedBodySize), - false /* isDSRPacket */); + static_cast(ret->encodedBodySize)); if (!updateConnResult.has_value()) { return quic::make_unexpected(updateConnResult.error()); } @@ -2553,7 +2422,6 @@ writePathValidationDataForAlternatePaths( QuicVersion version, uint64_t /*packetLimit*/, TimePoint writeLoopBeginTime) { - auto builder = ShortHeaderBuilder(connection.oneRttWritePhase); WriteQuicDataResult result; auto& packetsWritten = result.packetsWritten; auto& probesWritten = result.probesWritten; @@ -2572,6 +2440,7 @@ writePathValidationDataForAlternatePaths( } for (const auto& pathId : pathIdUnion) { + auto builder = ShortHeaderBuilder(connection.oneRttWritePhase); auto schedulerBuilder = FrameScheduler::Builder( connection, EncryptionLevel::AppData, diff --git a/quic/api/QuicTransportFunctions.h b/quic/api/QuicTransportFunctions.h index b4caca2f0..0a7dbffab 100644 --- a/quic/api/QuicTransportFunctions.h +++ b/quic/api/QuicTransportFunctions.h @@ -226,8 +226,7 @@ bool handleStreamBufMetaWritten( RegularQuicWritePacket packet, TimePoint time, uint32_t encodedSize, - uint32_t encodedBodySize, - bool isDSRPacket); + uint32_t encodedBodySize); /** * Returns the number of writable bytes available for constructing a PTO packet. diff --git a/quic/api/test/BUCK b/quic/api/test/BUCK index 867f64c16..24e85d5fc 100644 --- a/quic/api/test/BUCK +++ b/quic/api/test/BUCK @@ -18,7 +18,6 @@ mvfst_cpp_library( "//quic/common:network_data", "//quic/common/events:folly_eventbase", "//quic/common/events:quic_timer", - "//quic/dsr:types", "//quic/server:server", "//quic/state:quic_state_machine", ], @@ -55,8 +54,6 @@ mvfst_cpp_test( "//quic/common/testutil:mock_async_udp_socket", "//quic/congestion_control:ecn_l4s_tracker", "//quic/congestion_control:static_cwnd_congestion_controller", - "//quic/dsr:types", - "//quic/dsr/test:mocks", "//quic/handshake/test:mocks", "//quic/logging/test:mocks", "//quic/priority:http_priority_queue", @@ -126,8 +123,6 @@ mvfst_cpp_test( "//quic/codec:pktbuilder", "//quic/codec/test:mocks", "//quic/common/test:test_utils", - "//quic/dsr:types", - "//quic/dsr/test:mocks", "//quic/fizz/client/handshake:fizz_client_handshake", "//quic/fizz/server/handshake:fizz_server_handshake", "//quic/priority:http_priority_queue", @@ -238,7 +233,6 @@ mvfst_cpp_library( "//quic/api:transport", "//quic/api:transport_helpers", "//quic/common/test:test_utils", - "//quic/dsr/frontend:write_functions", "//quic/fizz/server/handshake:fizz_server_handshake", ], ) diff --git a/quic/api/test/MockQuicSocket.h b/quic/api/test/MockQuicSocket.h index 29459aa29..41b8cf825 100644 --- a/quic/api/test/MockQuicSocket.h +++ b/quic/api/test/MockQuicSocket.h @@ -7,10 +7,10 @@ #pragma once +#include #include #include -#include namespace quic { @@ -261,14 +261,6 @@ class MockQuicSocket : public QuicSocket { WriteResult, writeChain, (StreamId, SharedBuf, bool, ByteEventCallback*)); - MOCK_METHOD( - WriteResult, - writeBufMeta, - (StreamId, const BufferMeta&, bool, ByteEventCallback*)); - MOCK_METHOD( - WriteResult, - setDSRPacketizationRequestSender, - (StreamId, std::unique_ptr)); MOCK_METHOD( (quic::Expected), registerDeliveryCallback, diff --git a/quic/api/test/QuicPacketSchedulerTest.cpp b/quic/api/test/QuicPacketSchedulerTest.cpp index 3b89a3962..2aa7fce27 100644 --- a/quic/api/test/QuicPacketSchedulerTest.cpp +++ b/quic/api/test/QuicPacketSchedulerTest.cpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include @@ -630,33 +628,6 @@ TEST_P(QuicPacketSchedulerTest, StreamFrameSchedulerStreamNotExists) { EXPECT_EQ(builder.remainingSpaceInPkt(), originalSpace); } -TEST_P(QuicPacketSchedulerTest, NoCloningForDSR) { - QuicClientConnectionState conn( - FizzClientQuicHandshakeContext::Builder().build()); - FrameScheduler noopScheduler("frame", conn); - ASSERT_FALSE(noopScheduler.hasData()); - CloningScheduler cloningScheduler(noopScheduler, conn, "Juice WRLD", 0); - EXPECT_FALSE(cloningScheduler.hasData()); - addOutstandingPacket(conn); - EXPECT_TRUE(cloningScheduler.hasData()); - conn.outstandings.packets.back().isDSRPacket = true; - conn.outstandings.dsrCount++; - EXPECT_FALSE(cloningScheduler.hasData()); - ShortHeader header( - ProtectionType::KeyPhaseOne, - conn.clientConnectionId.value_or(getTestConnectionId()), - getNextPacketNum(conn, PacketNumberSpace::AppData)); - RegularQuicPacketBuilder builder( - conn.udpSendPacketLen, - std::move(header), - conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0)); - auto result = cloningScheduler.scheduleFramesForPacket( - std::move(builder), kDefaultUDPSendPacketLen); - ASSERT_FALSE(result.hasError()); - EXPECT_FALSE(result->clonedPacketIdentifier.has_value()); - EXPECT_FALSE(result->packet.has_value()); -} - TEST_P(QuicPacketSchedulerTest, CloningSchedulerTest) { QuicClientConnectionState conn( FizzClientQuicHandshakeContext::Builder().build()); @@ -1328,8 +1299,7 @@ TEST_P(QuicPacketSchedulerTest, CloningSchedulerWithInplaceBuilderFullPacket) { result->packet->packet, Clock::now(), bufferLength, - 0, - false /* isDSRPacket */); + 0); ASSERT_FALSE(updateResult.hasError()); buf = bufAccessor.obtain(); ASSERT_EQ(conn.udpSendPacketLen, buf->length()); @@ -1410,8 +1380,7 @@ TEST_P(QuicPacketSchedulerTest, CloneLargerThanOriginalPacket) { packetResult->packet->packet, Clock::now(), encodedSize, - 0, - false /* isDSRPacket */); + 0); ASSERT_FALSE(updateResult.hasError()); // make packetNum too larger to be encoded into the same size: @@ -1637,68 +1606,6 @@ TEST_P(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinStreamPerPacket) { verifyStreamFrames(*builder2, {f1}); } -TEST_P( - QuicPacketSchedulerTest, - StreamFrameSchedulerRoundRobinStreamPerPacketHitsDsr) { - auto connPtr = createConn(10, 100000, 100000, GetParam()); - auto& conn = *connPtr; - conn.transportSettings.streamFramePerPacket = true; - StreamFrameScheduler scheduler(conn); - - auto stream1 = createStream(conn); - auto stream2 = createStream(conn); - auto stream3 = createStream(conn); - auto stream4 = createStream(conn); - - auto largeBuf = createLargeBuffer(conn.udpSendPacketLen * 2); - writeDataToStream(conn, stream1, std::move(largeBuf)); - auto f2 = writeDataToStream(conn, stream2, "some data"); - auto f3 = writeDataToStream(conn, stream3, "some data"); - - // Set up DSR - auto sender = std::make_unique(); - ON_CALL(*sender, addSendInstruction(testing::_)) - .WillByDefault(testing::Return(true)); - ON_CALL(*sender, flush()).WillByDefault(testing::Return(true)); - auto dsrStream = conn.streamManager->findStream(stream4); - dsrStream->dsrSender = std::move(sender); - - BufferMeta bufMeta(20); - writeDataToStream(conn, stream4, "some data"); - ASSERT_FALSE(writeBufMetaToQuicStream( - *conn.streamManager->findStream(stream4), bufMeta, true) - .hasError()); - - // Pretend we sent the non DSR data - dsrStream->ackedIntervals.insert(0, dsrStream->writeBuffer.chainLength() - 1); - dsrStream->currentWriteOffset = dsrStream->writeBuffer.chainLength(); - dsrStream->writeBuffer.move(); - ChainedByteRangeHead( - std::move( - dsrStream->pendingWrites)); // Move and destruct the pending writes - conn.streamManager->updateWritableStreams(*dsrStream); - - // Write a normal size packet from stream1 - auto builder1 = createPacketBuilder(conn); - auto result = scheduler.writeStreams(builder1); - ASSERT_FALSE(result.hasError()); - - EXPECT_EQ(nextScheduledStreamID(conn), stream2); - - // Should write frames for stream2, stream3, followed by an empty write. - auto builder2 = setupMockPacketBuilder(); - ASSERT_TRUE(scheduler.hasPendingData()); - ASSERT_FALSE(scheduler.writeStreams(*builder2).hasError()); - ASSERT_EQ(builder2->frames_.size(), 1); - ASSERT_TRUE(scheduler.hasPendingData()); - ASSERT_FALSE(scheduler.writeStreams(*builder2).hasError()); - ASSERT_EQ(builder2->frames_.size(), 2); - EXPECT_FALSE(scheduler.hasPendingData()); - ASSERT_FALSE(scheduler.writeStreams(*builder2).hasError()); - - verifyStreamFrames(*builder2, {f2, f3}); -} - TEST_P(QuicPacketSchedulerTest, StreamFrameSchedulerSequential) { auto connPtr = createConn(10, 100000, 100000, GetParam()); auto& conn = *connPtr; @@ -1994,8 +1901,7 @@ TEST_P(QuicPacketSchedulerTest, WriteLossWithoutFlowControl) { packet1, Clock::now(), 1000, - 0, - false /* isDSR */) + 0) .hasError()); EXPECT_EQ(1, packet1.frames.size()); auto& writeStreamFrame1 = *packet1.frames[0].asWriteStreamFrame(); @@ -2031,8 +1937,7 @@ TEST_P(QuicPacketSchedulerTest, WriteLossWithoutFlowControl) { packet2, Clock::now(), 1000, - 0, - false /* isDSR */) + 0) .hasError()); EXPECT_EQ(1, packet2.frames.size()); auto& writeStreamFrame2 = *packet2.frames[0].asWriteStreamFrame(); @@ -2043,64 +1948,6 @@ TEST_P(QuicPacketSchedulerTest, WriteLossWithoutFlowControl) { EXPECT_EQ(1000, stream->retransmissionBuffer[0]->data.chainLength()); } -TEST_P(QuicPacketSchedulerTest, WriteLossWithoutFlowControlIgnoreDSR) { - QuicServerConnectionState conn( - FizzServerQuicHandshakeContext::Builder().build()); - ASSERT_FALSE( - conn.streamManager->setMaxLocalBidirectionalStreams(10).hasError()); - conn.flowControlState.peerAdvertisedMaxOffset = 1000; - conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote = 1000; - initializePathManagerState(conn); - - auto streamId = (*conn.streamManager->createNextBidirectionalStream())->id; - auto dsrStream = conn.streamManager->createNextBidirectionalStream().value(); - auto stream = conn.streamManager->findStream(streamId); - auto data = buildRandomInputData(1000); - ASSERT_FALSE( - writeDataToQuicStream(*stream, std::move(data), true).hasError()); - WriteBufferMeta bufMeta{}; - bufMeta.offset = 0; - bufMeta.length = 100; - bufMeta.eof = false; - dsrStream->insertIntoLossBufMeta(bufMeta); - conn.streamManager->updateWritableStreams(*stream); - conn.streamManager->updateWritableStreams(*dsrStream); - - StreamFrameScheduler scheduler(conn); - EXPECT_TRUE(scheduler.hasPendingData()); - ShortHeader shortHeader1( - ProtectionType::KeyPhaseZero, - getTestConnectionId(), - getNextPacketNum(conn, PacketNumberSpace::AppData)); - RegularQuicPacketBuilder builder1( - conn.udpSendPacketLen, - std::move(shortHeader1), - conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0)); - ASSERT_FALSE(builder1.encodePacketHeader().hasError()); - ASSERT_FALSE(scheduler.writeStreams(builder1).hasError()); - auto packet1 = std::move(builder1).buildPacket().packet; - ASSERT_FALSE( - updateConnection( - conn, - *CHECK_NOTNULL(conn.pathManager->getPath(conn.currentPathId)), - std::nullopt, - packet1, - Clock::now(), - 1000, - 0, - false /* isDSR */) - .hasError()); - EXPECT_EQ(1, packet1.frames.size()); - auto& writeStreamFrame1 = *packet1.frames[0].asWriteStreamFrame(); - EXPECT_EQ(streamId, writeStreamFrame1.streamId); - EXPECT_EQ(0, getSendConnFlowControlBytesWire(conn)); - EXPECT_EQ(0, stream->pendingWrites.chainLength()); - EXPECT_EQ(1, stream->retransmissionBuffer.size()); - EXPECT_EQ(1000, stream->retransmissionBuffer[0]->data.chainLength()); - - EXPECT_FALSE(scheduler.hasPendingData()); -} - TEST_P(QuicPacketSchedulerTest, WriteLossWithoutFlowControlSequential) { QuicServerConnectionState conn( FizzServerQuicHandshakeContext::Builder().build()); @@ -2140,8 +1987,7 @@ TEST_P(QuicPacketSchedulerTest, WriteLossWithoutFlowControlSequential) { packet1, Clock::now(), 1000, - 0, - false /* isDSR */) + 0) .hasError()); EXPECT_EQ(1, packet1.frames.size()); auto& writeStreamFrame1 = *packet1.frames[0].asWriteStreamFrame(); @@ -2177,8 +2023,7 @@ TEST_P(QuicPacketSchedulerTest, WriteLossWithoutFlowControlSequential) { packet2, Clock::now(), 1000, - 0, - false /* isDSR */) + 0) .hasError()); EXPECT_EQ(1, packet2.frames.size()); auto& writeStreamFrame2 = *packet2.frames[0].asWriteStreamFrame(); @@ -2234,8 +2079,7 @@ TEST_P(QuicPacketSchedulerTest, MultipleStreamsRunOutOfFlowControl) { packet1, Clock::now(), 1200, - 0, - false /* isDSR */)); + 0)); ASSERT_EQ(2, packet1.frames.size()); auto& writeStreamFrame1 = *packet1.frames[0].asWriteStreamFrame(); EXPECT_EQ(highPriStreamId, writeStreamFrame1.streamId); @@ -2276,8 +2120,7 @@ TEST_P(QuicPacketSchedulerTest, MultipleStreamsRunOutOfFlowControl) { packet2, Clock::now(), 1000, - 0, - false /* isDSR */)); + 0)); ASSERT_EQ(1, packet2.frames.size()); auto& writeStreamFrame3 = *packet2.frames[0].asWriteStreamFrame(); EXPECT_EQ(highPriStreamId, writeStreamFrame3.streamId); @@ -2332,8 +2175,7 @@ TEST_P(QuicPacketSchedulerTest, RunOutFlowControlDuringStreamWrite) { packet1, Clock::now(), 1200, - 0, - false /* isDSR */) + 0) .hasError()); ASSERT_EQ(2, packet1.frames.size()); auto& writeStreamFrame1 = *packet1.frames[0].asWriteStreamFrame(); @@ -2351,98 +2193,6 @@ TEST_P(QuicPacketSchedulerTest, RunOutFlowControlDuringStreamWrite) { EXPECT_EQ(200, stream2->retransmissionBuffer[0]->data.chainLength()); } -TEST_P(QuicPacketSchedulerTest, WritingFINFromBufWithBufMetaFirst) { - QuicServerConnectionState conn( - FizzServerQuicHandshakeContext::Builder().build()); - ASSERT_FALSE( - conn.streamManager->setMaxLocalBidirectionalStreams(10).hasError()); - conn.flowControlState.peerAdvertisedMaxOffset = 100000; - auto* stream = *(conn.streamManager->createNextBidirectionalStream()); - stream->flowControlState.peerAdvertisedMaxOffset = 100000; - initializePathManagerState(conn); - - ASSERT_FALSE( - writeDataToQuicStream(*stream, folly::IOBuf::copyBuffer("Ascent"), false) - .hasError()); - stream->dsrSender = std::make_unique(); - BufferMeta bufferMeta(5000); - ASSERT_FALSE(writeBufMetaToQuicStream(*stream, bufferMeta, true).hasError()); - EXPECT_TRUE(stream->finalWriteOffset.has_value()); - - stream->writeBufMeta.split(5000); - ASSERT_EQ(0, stream->writeBufMeta.length); - ASSERT_GT(stream->writeBufMeta.offset, 0); - conn.streamManager->updateWritableStreams(*stream); - - PacketNum packetNum = 0; - ShortHeader header( - ProtectionType::KeyPhaseOne, - conn.clientConnectionId.value_or(getTestConnectionId()), - packetNum); - RegularQuicPacketBuilder builder( - conn.udpSendPacketLen, - std::move(header), - conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0)); - ASSERT_FALSE(builder.encodePacketHeader().hasError()); - StreamFrameScheduler scheduler(conn); - ASSERT_FALSE(scheduler.writeStreams(builder).hasError()); - auto packet = std::move(builder).buildPacket().packet; - ASSERT_EQ(1, packet.frames.size()); - auto streamFrame = *packet.frames[0].asWriteStreamFrame(); - EXPECT_EQ(streamFrame.len, 6); - EXPECT_EQ(streamFrame.offset, 0); - EXPECT_FALSE(streamFrame.fin); - handleNewStreamDataWritten(*stream, streamFrame.len, streamFrame.fin); - EXPECT_EQ(stream->currentWriteOffset, 6); -} - -TEST_P(QuicPacketSchedulerTest, NoFINWriteWhenBufMetaWrittenFIN) { - QuicServerConnectionState conn( - FizzServerQuicHandshakeContext::Builder().build()); - ASSERT_FALSE( - conn.streamManager->setMaxLocalBidirectionalStreams(10).hasError()); - conn.flowControlState.peerAdvertisedMaxOffset = 100000; - auto* stream = *(conn.streamManager->createNextBidirectionalStream()); - stream->flowControlState.peerAdvertisedMaxOffset = 100000; - initializePathManagerState(conn); - - ASSERT_FALSE( - writeDataToQuicStream(*stream, folly::IOBuf::copyBuffer("Ascent"), false) - .hasError()); - stream->dsrSender = std::make_unique(); - BufferMeta bufferMeta(5000); - ASSERT_FALSE(writeBufMetaToQuicStream(*stream, bufferMeta, true).hasError()); - EXPECT_TRUE(stream->finalWriteOffset.has_value()); - PacketNum packetNum = 0; - ShortHeader header( - ProtectionType::KeyPhaseOne, - conn.clientConnectionId.value_or(getTestConnectionId()), - packetNum); - RegularQuicPacketBuilder builder( - conn.udpSendPacketLen, - std::move(header), - conn.ackStates.appDataAckState.largestAckedByPeer.value_or(0)); - ASSERT_FALSE(builder.encodePacketHeader().hasError()); - StreamFrameScheduler scheduler(conn); - ASSERT_FALSE(scheduler.writeStreams(builder).hasError()); - auto packet = std::move(builder).buildPacket().packet; - EXPECT_EQ(1, packet.frames.size()); - auto streamFrame = *packet.frames[0].asWriteStreamFrame(); - EXPECT_EQ(streamFrame.len, 6); - EXPECT_EQ(streamFrame.offset, 0); - EXPECT_FALSE(streamFrame.fin); - handleNewStreamDataWritten(*stream, streamFrame.len, streamFrame.fin); - - // Pretent all the bufMetas were sent, without FIN bit - stream->writeBufMeta.split(5000); - stream->writeBufMeta.offset++; - ASSERT_EQ(0, stream->writeBufMeta.length); - ASSERT_GT(stream->writeBufMeta.offset, 0); - conn.streamManager->updateWritableStreams(*stream); - StreamFrameScheduler scheduler2(conn); - EXPECT_FALSE(scheduler2.hasPendingData()); -} - TEST_P(QuicPacketSchedulerTest, DatagramFrameSchedulerMultipleFramesPerPacket) { QuicClientConnectionState conn( FizzClientQuicHandshakeContext::Builder().build()); @@ -2895,8 +2645,7 @@ TEST_P(QuicPacketSchedulerTest, RstStreamSchedulerReliableReset) { packetResult1.value().packet->packet, Clock::now(), encodedSize1, - 0, - false /* isDSRPacket */) + 0) .hasError()); // We shouldn't send the reliable reset just yet, because we haven't yet @@ -2927,8 +2676,7 @@ TEST_P(QuicPacketSchedulerTest, RstStreamSchedulerReliableReset) { packetResult2.value().packet->packet, Clock::now(), encodedSize2, - 0, - false /* isDSRPacket */) + 0) .hasError()); // Now we should have egressed all the stream data upto the reliable offset, diff --git a/quic/api/test/QuicTransportBaseTest.cpp b/quic/api/test/QuicTransportBaseTest.cpp index 452a7e520..184f36249 100644 --- a/quic/api/test/QuicTransportBaseTest.cpp +++ b/quic/api/test/QuicTransportBaseTest.cpp @@ -279,20 +279,6 @@ class TestQuicTransport closeUdpSocket(); } - WriteResult writeBufMeta( - StreamId /* id */, - const BufferMeta& /* data */, - bool /* eof */, - ByteEventCallback* /* cb */) override { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - - WriteResult setDSRPacketizationRequestSender( - StreamId /* id */, - std::unique_ptr /* sender */) override { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - Optional> getPeerTransportParams() const override { return std::nullopt; diff --git a/quic/api/test/QuicTransportFunctionsTest.cpp b/quic/api/test/QuicTransportFunctionsTest.cpp index 86ab52c80..38a37ea18 100644 --- a/quic/api/test/QuicTransportFunctionsTest.cpp +++ b/quic/api/test/QuicTransportFunctionsTest.cpp @@ -241,8 +241,7 @@ TEST_F(QuicTransportFunctionsTest, PingPacketGoesToOPListAndLossAlarm) { packet.packet, Clock::now(), 50, - 0, - false /* isDSRPacket */); + 0); ASSERT_FALSE(result.hasError()); EXPECT_EQ(1, conn->outstandings.packets.size()); EXPECT_TRUE(conn->pendingEvents.setLossDetectionAlarm); @@ -294,8 +293,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnection) { packet.packet, TimePoint{}, getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); EXPECT_EQ( @@ -360,8 +358,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnection) { packet2.packet, TimePoint(), getEncodedSize(packet2), - getEncodedBodySize(packet2), - false /* isDSRPacket */); + getEncodedBodySize(packet2)); ASSERT_FALSE(result.hasError()); EXPECT_EQ( conn->ackStates.initialAckState->nextPacketNum, @@ -493,8 +490,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionPacketRetrans) { packet1.packet, TimePoint{}, getEncodedSize(packet1), - getEncodedBodySize(packet1), - false /* isDSRPacket */); + getEncodedBodySize(packet1)); ASSERT_FALSE(result.hasError()); // appData packet number should increase @@ -559,8 +555,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionPacketRetrans) { packet2.packet, TimePoint(), getEncodedSize(packet2), - getEncodedBodySize(packet2), - false /* isDSRPacket */); + getEncodedBodySize(packet2)); ASSERT_FALSE(result.hasError()); EXPECT_EQ( conn->ackStates.initialAckState->nextPacketNum, @@ -668,8 +663,7 @@ TEST_F( packet1.packet, TimePoint{}, getEncodedSize(packet1), - getEncodedBodySize(packet1), - false /* isDSRPacket */) + getEncodedBodySize(packet1)) .hasError()); // appData packet number should increase @@ -759,8 +753,7 @@ TEST_F( packet2.packet, TimePoint(), getEncodedSize(packet2), - getEncodedBodySize(packet2), - false /* isDSRPacket */) + getEncodedBodySize(packet2)) .hasError()); EXPECT_EQ( conn->ackStates.initialAckState->nextPacketNum, @@ -830,8 +823,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionPacketSorting) { handshakePacket.packet, TimePoint{}, getEncodedSize(handshakePacket), - getEncodedBodySize(handshakePacket), - false /* isDSRPacket */) + getEncodedBodySize(handshakePacket)) .hasError()); ASSERT_FALSE(updateConnection( *conn, @@ -840,8 +832,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionPacketSorting) { initialPacket.packet, TimePoint{}, getEncodedSize(initialPacket), - getEncodedBodySize(initialPacket), - false /* isDSRPacket */) + getEncodedBodySize(initialPacket)) .hasError()); ASSERT_FALSE(updateConnection( *conn, @@ -850,8 +841,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionPacketSorting) { appDataPacket.packet, TimePoint{}, getEncodedSize(appDataPacket), - getEncodedBodySize(appDataPacket), - false /* isDSRPacket */) + getEncodedBodySize(appDataPacket)) .hasError()); // verify qLogger added correct logs std::shared_ptr qLogger = @@ -904,8 +894,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionFinOnly) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); // verify QLogger contains correct packet information @@ -957,8 +946,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionAllBytesExceptFin) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); // verify QLogger contains correct packet information @@ -1007,8 +995,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionEmptyAckWriteResult) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); // verify QLogger contains correct packet information @@ -1048,8 +1035,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionPureAckCounter) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result2.hasError()); auto nonHandshake = buildEmptyPacket(*conn, PacketNumberSpace::Handshake); @@ -1070,8 +1056,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionPureAckCounter) { packet2.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result4.hasError()); // verify QLogger contains correct packet and frame information @@ -1105,8 +1090,7 @@ TEST_F(QuicTransportFunctionsTest, TestPaddingPureAckPacketIsStillPureAck) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); // verify QLogger contains correct packet and frames information @@ -1145,8 +1129,7 @@ TEST_F(QuicTransportFunctionsTest, TestImplicitAck) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result1.hasError()); EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::Initial]); EXPECT_EQ(0, conn->outstandings.packetCount[PacketNumberSpace::Handshake]); @@ -1169,8 +1152,7 @@ TEST_F(QuicTransportFunctionsTest, TestImplicitAck) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result2.hasError()); EXPECT_EQ(2, conn->outstandings.packetCount[PacketNumberSpace::Initial]); EXPECT_EQ(0, conn->outstandings.packetCount[PacketNumberSpace::Handshake]); @@ -1203,8 +1185,7 @@ TEST_F(QuicTransportFunctionsTest, TestImplicitAck) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result3.hasError()); EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::Initial]); EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::Handshake]); @@ -1223,8 +1204,7 @@ TEST_F(QuicTransportFunctionsTest, TestImplicitAck) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result4.hasError()); EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::Initial]); EXPECT_EQ(2, conn->outstandings.packetCount[PacketNumberSpace::Handshake]); @@ -1284,8 +1264,7 @@ TEST_F(QuicTransportFunctionsTest, TestImplicitAckWithSkippedPacketNumber) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result1.hasError()); EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::Initial]); EXPECT_EQ(1, conn->outstandings.packets.size()); @@ -1312,8 +1291,7 @@ TEST_F(QuicTransportFunctionsTest, TestImplicitAckWithSkippedPacketNumber) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result2.hasError()); EXPECT_EQ(2, conn->outstandings.packetCount[PacketNumberSpace::Initial]); EXPECT_EQ(2, conn->outstandings.packets.size()); @@ -1351,8 +1329,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionHandshakeCounter) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result2.hasError()); EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::Handshake]); @@ -1376,8 +1353,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionHandshakeCounter) { nonHandshake.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result4.hasError()); // verify QLogger contains correct packet information @@ -1432,8 +1408,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionForOneRttCryptoData) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); EXPECT_EQ(0, conn->outstandings.packetCount[PacketNumberSpace::Handshake]); @@ -1452,8 +1427,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionForOneRttCryptoData) { nonHandshake.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); // verify QLogger contains correct packet information @@ -1518,8 +1492,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionWithPureAck) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); EXPECT_EQ(1, conn->lossState.totalPacketsSent); EXPECT_EQ(0, conn->lossState.totalAckElicitingPacketsSent); @@ -1572,8 +1545,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionWithBytesStats) { packet.packet, TimePoint(), 555, - 500, - false /* isDSRPacket */) + 500) .hasError()); EXPECT_EQ(21, conn->lossState.totalPacketsSent); EXPECT_EQ(16, conn->lossState.totalAckElicitingPacketsSent); @@ -1663,8 +1635,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionWithAppLimitedStats) { packet.packet, TimePoint(), 555, - 500, - false /* isDSRPacket */) + 500) .hasError()); // should have the current app limited time recorded in metadata @@ -1725,8 +1696,7 @@ TEST_F( packet.packet, TimePoint(), 555, - 500, - false /* isDSRPacket */) + 500) .hasError()); // should have the current app limited time recorded in metadata @@ -1767,8 +1737,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionWithCloneResult) { std::move(writePacket), MockClock::now(), 1500, - 1400, - false /* isDSRPacket */); + 1400); ASSERT_FALSE(result.hasError()); // verify QLogger contains correct packet information std::shared_ptr qLogger = @@ -1821,8 +1790,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionStreamWindowUpdate) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); // verify QLogger contains correct packet information @@ -1859,8 +1827,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionConnWindowUpdate) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); // verify QLogger contains correct packet information @@ -1900,8 +1867,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionSkipAPacketNumber) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); ASSERT_FALSE(conn->ackStates.appDataAckState.skippedPacketNum.has_value()); @@ -1921,8 +1887,7 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnectionSkipAPacketNumber) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); ASSERT_TRUE(conn->ackStates.appDataAckState.skippedPacketNum.has_value()); @@ -1943,8 +1908,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsEmptyPacket) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); // Since there is no ACK eliciting frame in this packet, // it is not included as an outstanding packet, and there's no StreamDetails @@ -1965,8 +1929,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsNoStreamsInPacket) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); // If we have only control frames sent, there should be no stream data in the // outstanding packet. @@ -1988,8 +1951,7 @@ TEST_F(QuicTransportFunctionsTest, TestPingFrameCounter) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); ASSERT_EQ(1, conn->numPingFramesSent); } @@ -2014,8 +1976,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStream) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); const auto streamMatcher = testing::Pair( @@ -2061,8 +2022,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStreamMultipleFrames) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); const auto streamMatcher = testing::Pair( @@ -2105,8 +2065,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStreamRetransmit) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); ASSERT_EQ(1, conn->outstandings.packets.size()); @@ -2146,8 +2105,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStreamRetransmit) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); ASSERT_EQ(2, conn->outstandings.packets.size()); @@ -2194,8 +2152,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStreamRetransmit) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); ASSERT_EQ(3, conn->outstandings.packets.size()); @@ -2237,8 +2194,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStreamRetransmit) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */); + getEncodedBodySize(packet)); ASSERT_FALSE(result.hasError()); ASSERT_EQ(4, conn->outstandings.packets.size()); @@ -2291,8 +2247,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStreamFinWithRetransmit) { packet1.packet, TimePoint(), getEncodedSize(packet1), - getEncodedBodySize(packet1), - false /* isDSRPacket */) + getEncodedBodySize(packet1)) .hasError()); ASSERT_FALSE(writeDataToQuicStream( @@ -2309,8 +2264,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStreamFinWithRetransmit) { packet2.packet, TimePoint(), getEncodedSize(packet2), - getEncodedBodySize(packet2), - false /* isDSRPacket */) + getEncodedBodySize(packet2)) .hasError()); // Should be two packets at this point, each with 1 frame of data @@ -2364,8 +2318,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsSingleStreamFinWithRetransmit) { packet3.packet, TimePoint(), getEncodedSize(packet3), - getEncodedBodySize(packet3), - false /* isDSRPacket */) + getEncodedBodySize(packet3)) .hasError()); // Should be three packets at this point @@ -2421,8 +2374,7 @@ TEST_F( packet1.packet, TimePoint(), getEncodedSize(packet1), - getEncodedBodySize(packet1), - false /* isDSRPacket */) + getEncodedBodySize(packet1)) .hasError()); ASSERT_FALSE(writeDataToQuicStream( @@ -2439,8 +2391,7 @@ TEST_F( packet2.packet, TimePoint(), getEncodedSize(packet2), - getEncodedBodySize(packet2), - false /* isDSRPacket */) + getEncodedBodySize(packet2)) .hasError()); ASSERT_FALSE(writeDataToQuicStream( @@ -2457,8 +2408,7 @@ TEST_F( packet3.packet, TimePoint(), getEncodedSize(packet3), - getEncodedBodySize(packet3), - false /* isDSRPacket */) + getEncodedBodySize(packet3)) .hasError()); // Should be three packets at this point, each with 1 frame of data @@ -2522,8 +2472,7 @@ TEST_F( packet4.packet, TimePoint(), getEncodedSize(packet4), - getEncodedBodySize(packet4), - false /* isDSRPacket */) + getEncodedBodySize(packet4)) .hasError()); // Should be four packets at this point @@ -2579,8 +2528,7 @@ TEST_F( packet1.packet, TimePoint(), getEncodedSize(packet1), - getEncodedBodySize(packet1), - false /* isDSRPacket */) + getEncodedBodySize(packet1)) .hasError()); ASSERT_FALSE(writeDataToQuicStream( @@ -2598,8 +2546,7 @@ TEST_F( packet2.packet, TimePoint(), getEncodedSize(packet2), - getEncodedBodySize(packet2), - false /* isDSRPacket */) + getEncodedBodySize(packet2)) .hasError()); ASSERT_FALSE(writeDataToQuicStream( @@ -2617,8 +2564,7 @@ TEST_F( packet3.packet, TimePoint(), getEncodedSize(packet3), - getEncodedBodySize(packet3), - false /* isDSRPacket */) + getEncodedBodySize(packet3)) .hasError()); // Should be three packets at this point, each with 1 frame of data @@ -2682,8 +2628,7 @@ TEST_F( packet4.packet, TimePoint(), getEncodedSize(packet4), - getEncodedBodySize(packet4), - false /* isDSRPacket */) + getEncodedBodySize(packet4)) .hasError()); // Should be four packets at this point @@ -2762,8 +2707,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsMultipleStreams) { packet1.packet, TimePoint(), getEncodedSize(packet1), - getEncodedBodySize(packet1), - false /* isDSRPacket */) + getEncodedBodySize(packet1)) .hasError()); // check stream details for the sent packet @@ -2838,8 +2782,7 @@ TEST_F(QuicTransportFunctionsTest, StreamDetailsMultipleStreams) { packet2.packet, TimePoint(), getEncodedSize(packet1), - getEncodedBodySize(packet1), - false /* isDSRPacket */) + getEncodedBodySize(packet1)) .hasError()); // check stream details for the retransmitted packet @@ -4356,8 +4299,7 @@ TEST_F(QuicTransportFunctionsTest, UpdateConnectionCloneCounterAppData) { packet.packet, TimePoint(), 123, - 100, - false /* isDSRPacket */) + 100) .hasError()); EXPECT_EQ( 0, conn->outstandings.clonedPacketCount[PacketNumberSpace::Initial]); @@ -4386,8 +4328,7 @@ TEST_F(QuicTransportFunctionsTest, UpdateConnectionCloneCounterHandshake) { packet.packet, TimePoint(), 123, - 123, - false /* isDSRPacket */) + 123) .hasError()); EXPECT_EQ( 0, conn->outstandings.clonedPacketCount[PacketNumberSpace::Initial]); @@ -4416,8 +4357,7 @@ TEST_F(QuicTransportFunctionsTest, UpdateConnectionCloneCounterInitial) { packet.packet, TimePoint(), 123, - 123, - false /* isDSRPacket */) + 123) .hasError()); EXPECT_EQ( 1, conn->outstandings.clonedPacketCount[PacketNumberSpace::Initial]); @@ -4441,8 +4381,7 @@ TEST_F(QuicTransportFunctionsTest, ClearBlockedFromPendingEvents) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); EXPECT_FALSE(conn->streamManager->hasBlocked()); EXPECT_FALSE(conn->outstandings.packets.empty()); @@ -4467,8 +4406,7 @@ TEST_F(QuicTransportFunctionsTest, ClonedBlocked) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); EXPECT_FALSE(conn->outstandings.packets.empty()); EXPECT_EQ( @@ -4491,8 +4429,7 @@ TEST_F(QuicTransportFunctionsTest, TwoConnWindowUpdateWillCrash) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */), + getEncodedBodySize(packet)), ".*Send more than one connection window update.*"); } @@ -4514,8 +4451,7 @@ TEST_F(QuicTransportFunctionsTest, WriteStreamFrameIsNotPureAck) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); EXPECT_FALSE(conn->outstandings.packets.empty()); } @@ -4535,8 +4471,7 @@ TEST_F(QuicTransportFunctionsTest, ClearRstFromPendingEvents) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); EXPECT_TRUE(conn->pendingEvents.resets.empty()); EXPECT_FALSE(conn->outstandings.packets.empty()); @@ -4562,8 +4497,7 @@ TEST_F(QuicTransportFunctionsTest, ClonedRst) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); EXPECT_FALSE(conn->outstandings.packets.empty()); EXPECT_EQ(1, conn->outstandings.numClonedPackets()); @@ -4581,8 +4515,7 @@ TEST_F(QuicTransportFunctionsTest, TotalBytesSentUpdate) { packet.packet, TimePoint{}, 4321, - 4000, - false /* isDSRPacket */) + 4000) .hasError()); EXPECT_EQ(5555, conn->lossState.totalBytesSent); EXPECT_EQ(5000, conn->lossState.totalBodyBytesSent); @@ -4600,8 +4533,7 @@ TEST_F(QuicTransportFunctionsTest, TotalPacketsSentUpdate) { packet.packet, TimePoint{}, 4321, - 0, - false /* isDSRPacket */) + 0) .hasError()); EXPECT_EQ(startTotalPacketsSent + 1, conn->lossState.totalPacketsSent); } @@ -4624,8 +4556,7 @@ TEST_F(QuicTransportFunctionsTest, TimeoutBasedRetxCountUpdate) { packet.packet, TimePoint(), 0, - 0, - false /* isDSRPacket */) + 0) .hasError()); EXPECT_EQ(247, conn->lossState.timeoutBasedRtxCount); } @@ -5184,81 +5115,6 @@ TEST_F(QuicTransportFunctionsTest, WriteProbingWithInplaceBuilder) { EXPECT_EQ(conn->outstandings.packets.size(), outstandingPacketsCount + 3); } -TEST_F(QuicTransportFunctionsTest, UpdateConnectionWithBufferMeta) { - auto conn = createConn(); - // Builds a fake packet to test with. - auto packet = buildEmptyPacket(*conn, PacketNumberSpace::AppData); - - auto streamId = - conn->streamManager->createNextBidirectionalStream().value()->id; - auto stream = conn->streamManager->findStream(streamId); - EXPECT_TRUE(stream->retransmissionBufMetas.empty()); - ASSERT_FALSE(writeDataToQuicStream( - *stream, - IOBuf::copyBuffer("Wear a face mask please!"), - false /* eof */) - .hasError()); - BufferMeta bufMeta(2000); - ASSERT_FALSE( - writeBufMetaToQuicStream(*stream, bufMeta, true /* eof */).hasError()); - EXPECT_TRUE(stream->writeBufMeta.eof); - EXPECT_EQ(2000, stream->writeBufMeta.length); - auto bufMetaStartingOffset = stream->writeBufMeta.offset; - WriteStreamFrame writeStreamFrame( - streamId, bufMetaStartingOffset, 1000, false /* fin */); - writeStreamFrame.fromBufMeta = true; - packet.packet.frames.push_back(writeStreamFrame); - - ASSERT_FALSE(updateConnection( - *conn, - *currentPathInfo_, - std::nullopt, - packet.packet, - TimePoint(), - getEncodedSize(packet), - getEncodedBodySize(packet), - true /* dsr */) - .hasError()); - EXPECT_EQ(1000 + bufMetaStartingOffset, stream->writeBufMeta.offset); - EXPECT_EQ(1000, stream->writeBufMeta.length); - EXPECT_FALSE(stream->retransmissionBufMetas.empty()); - auto retxBufMetaIter = - stream->retransmissionBufMetas.find(bufMetaStartingOffset); - EXPECT_NE(retxBufMetaIter, stream->retransmissionBufMetas.end()); - EXPECT_EQ(bufMetaStartingOffset, retxBufMetaIter->second.offset); - EXPECT_EQ(1000, retxBufMetaIter->second.length); - EXPECT_FALSE(retxBufMetaIter->second.eof); - EXPECT_TRUE(conn->outstandings.packets.back().isDSRPacket); - - // Manually lose this packet: - stream->lossBufMetas.push_back(retxBufMetaIter->second); - stream->retransmissionBufMetas.erase(retxBufMetaIter); - ASSERT_FALSE(stream->lossBufMetas.empty()); - ASSERT_TRUE(stream->retransmissionBufMetas.empty()); - - // Retransmit it: - auto retxPacket = buildEmptyPacket(*conn, PacketNumberSpace::AppData); - // Retx of the stream looks exactly the same - retxPacket.packet.frames.push_back(writeStreamFrame); - ASSERT_FALSE(updateConnection( - *conn, - *currentPathInfo_, - std::nullopt, - retxPacket.packet, - TimePoint(), - getEncodedSize(retxPacket), - getEncodedBodySize(packet), - true /* dsr */) - .hasError()); - EXPECT_TRUE(stream->lossBufMetas.empty()); - retxBufMetaIter = stream->retransmissionBufMetas.find(bufMetaStartingOffset); - EXPECT_NE(retxBufMetaIter, stream->retransmissionBufMetas.end()); - EXPECT_EQ(bufMetaStartingOffset, retxBufMetaIter->second.offset); - EXPECT_EQ(1000, retxBufMetaIter->second.length); - EXPECT_FALSE(retxBufMetaIter->second.eof); - EXPECT_TRUE(conn->outstandings.packets.back().isDSRPacket); -} - TEST_F(QuicTransportFunctionsTest, MissingStreamFrameBytes) { auto conn = createConn(); auto packet = buildEmptyPacket(*conn, PacketNumberSpace::AppData); @@ -5279,8 +5135,7 @@ TEST_F(QuicTransportFunctionsTest, MissingStreamFrameBytes) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); } @@ -5297,8 +5152,7 @@ TEST_F(QuicTransportFunctionsTest, MissingStreamFrameBytes) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); } } @@ -5324,8 +5178,7 @@ TEST_F(QuicTransportFunctionsTest, MissingStreamFrameBytesEof) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); } @@ -5347,8 +5200,7 @@ TEST_F(QuicTransportFunctionsTest, MissingStreamFrameBytesEof) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); } } @@ -5374,8 +5226,7 @@ TEST_F(QuicTransportFunctionsTest, MissingStreamFrameBytesSingleByteWrite) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); } @@ -5392,8 +5243,7 @@ TEST_F(QuicTransportFunctionsTest, MissingStreamFrameBytesSingleByteWrite) { packet.packet, TimePoint(), getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); } } diff --git a/quic/api/test/TestQuicTransport.h b/quic/api/test/TestQuicTransport.h index 9388ea110..4447cb59c 100644 --- a/quic/api/test/TestQuicTransport.h +++ b/quic/api/test/TestQuicTransport.h @@ -10,7 +10,6 @@ #include #include #include -#include #include namespace quic { @@ -50,20 +49,6 @@ class TestQuicTransport closeUdpSocket(); } - WriteResult writeBufMeta( - StreamId /* id */, - const BufferMeta& /* data */, - bool /* eof */, - ByteEventCallback* /* cb */) override { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - - WriteResult setDSRPacketizationRequestSender( - StreamId /* id */, - std::unique_ptr /* sender */) override { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - Optional> getPeerTransportParams() const override { return std::nullopt; @@ -111,14 +96,6 @@ class TestQuicTransport if (result.hasError()) { return quic::make_unexpected(result.error()); } - [[maybe_unused]] auto writePacketization = writePacketizationRequest( - *dynamic_cast(conn_.get()), - *conn_->clientConnectionId, - (isConnectionPaced(*conn_) - ? conn_->pacer->updateAndGetWriteBatchSize(Clock::now()) - : conn_->transportSettings.writeConnectionDataPacketsLimit), - *aead, - Clock::now()); auto pathValidationResult = writePathValidationDataForAlternatePaths( *socket_, *conn_, diff --git a/quic/client/QuicClientTransportLite.cpp b/quic/client/QuicClientTransportLite.cpp index 40341000a..fdaab72bf 100644 --- a/quic/client/QuicClientTransportLite.cpp +++ b/quic/client/QuicClientTransportLite.cpp @@ -1073,21 +1073,6 @@ quic::Expected QuicClientTransportLite::onReadData( return {}; } -QuicSocketLite::WriteResult QuicClientTransportLite::writeBufMeta( - StreamId /* id */, - const BufferMeta& /* data */, - bool /* eof */, - ByteEventCallback* /* cb */) { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); -} - -QuicSocketLite::WriteResult -QuicClientTransportLite::setDSRPacketizationRequestSender( - StreamId /* id */, - std::unique_ptr /* sender */) { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); -} - quic::Expected QuicClientTransportLite::writeData() { QuicVersion version = conn_->version.value_or(*conn_->originalVersion); const ConnectionId& srcConnId = *conn_->clientConnectionId; diff --git a/quic/client/QuicClientTransportLite.h b/quic/client/QuicClientTransportLite.h index 367b4f751..0c4121e4d 100644 --- a/quic/client/QuicClientTransportLite.h +++ b/quic/client/QuicClientTransportLite.h @@ -129,16 +129,6 @@ class QuicClientTransportLite return clientConn_->clientHandshakeLayer->getCertificateVerifyEndTimeMS(); } - WriteResult writeBufMeta( - StreamId /* id */, - const BufferMeta& /* data */, - bool /* eof */, - ByteEventCallback* /* cb */) override; - - WriteResult setDSRPacketizationRequestSender( - StreamId /* id */, - std::unique_ptr /* sender */) override; - enum class ZeroRttAttemptState : uint8_t { NotAttempted = 0, Accepted, diff --git a/quic/codec/QuicWriteCodec.cpp b/quic/codec/QuicWriteCodec.cpp index f3063f63c..db6870314 100644 --- a/quic/codec/QuicWriteCodec.cpp +++ b/quic/codec/QuicWriteCodec.cpp @@ -164,12 +164,7 @@ quic::Expected, QuicError> writeStreamFrameHeader( } if (appendFrame) { builder.appendFrame(WriteStreamFrame( - id, - offset, - dataLen, - streamType.hasFin(), - false /* fromBufMetaIn */, - streamGroupId)); + id, offset, dataLen, streamType.hasFin(), streamGroupId)); } else { builder.markNonEmpty(); } diff --git a/quic/codec/Types.h b/quic/codec/Types.h index 0c7903260..b55b24367 100644 --- a/quic/codec/Types.h +++ b/quic/codec/Types.h @@ -466,33 +466,21 @@ struct WriteStreamFrame { uint64_t len; bool fin; - // Whether this WriteStreamFrame is created from a BufMeta, instead of real - // write buffer data. - bool fromBufMeta{false}; - - uint64_t streamPacketIdx{0}; - WriteStreamFrame( StreamId streamIdIn, uint64_t offsetIn, uint64_t lenIn, bool finIn, - bool fromBufMetaIn = false, - OptionalIntegral streamGroupIdIn = std::nullopt, - uint64_t streamPacketIdxIn = 0) + OptionalIntegral streamGroupIdIn = std::nullopt) : streamId(streamIdIn), streamGroupId(streamGroupIdIn), offset(offsetIn), len(lenIn), - fin(finIn), - fromBufMeta(fromBufMetaIn), - streamPacketIdx(streamPacketIdxIn) {} + fin(finIn) {} bool operator==(const WriteStreamFrame& rhs) const { return streamId == rhs.streamId && offset == rhs.offset && len == rhs.len && - fin == rhs.fin && fromBufMeta == rhs.fromBufMeta && - streamGroupId == rhs.streamGroupId && - streamPacketIdx == rhs.streamPacketIdx; + fin == rhs.fin && streamGroupId == rhs.streamGroupId; } }; diff --git a/quic/common/test/TestUtils.cpp b/quic/common/test/TestUtils.cpp index 472d2371d..85c723a48 100644 --- a/quic/common/test/TestUtils.cpp +++ b/quic/common/test/TestUtils.cpp @@ -635,7 +635,6 @@ CongestionController::AckEvent makeAck( ack.ackedPackets.emplace_back( CongestionController::AckEvent::AckPacket::Builder() .setPacketNum(seq) - .setNonDsrPacketSequenceNumber(seq) .setOutstandingPacketMetadata(opm) .setDetailsPerStream(AckEvent::AckPacket::DetailsPerStream()) .build()); @@ -783,8 +782,6 @@ CongestionController::AckEvent::AckPacket makeAckPacketFromOutstandingPacket( OutstandingPacketWrapper outstandingPacket) { return CongestionController::AckEvent::AckPacket::Builder() .setPacketNum(outstandingPacket.packet.header.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber( - outstandingPacket.packet.header.getPacketSequenceNum()) .setOutstandingPacketMetadata(outstandingPacket.metadata) .setLastAckedPacketInfo( outstandingPacket.lastAckedPacketInfo.has_value() diff --git a/quic/congestion_control/test/Bbr2Test.cpp b/quic/congestion_control/test/Bbr2Test.cpp index 4a7a4ba5d..48c343eab 100644 --- a/quic/congestion_control/test/Bbr2Test.cpp +++ b/quic/congestion_control/test/Bbr2Test.cpp @@ -101,8 +101,8 @@ TEST_F(Bbr2Test, StartupCwndGrowthBasic) { auto packet = makeTestingWritePacket( pn, packetSize, totalSent += packetSize, testStart_ + 10ms); quic::test::onPacketsSentWrapper(conn_.get(), &bbr2, packet); - packet.nonDsrPacketSequenceNumber = pn++; conn_->outstandings.packets.emplace_back(std::move(packet)); + pn++; ASSERT_EQ(conn_->lossState.inflightBytes, totalSent); } @@ -127,8 +127,6 @@ TEST_F(Bbr2Test, StartupCwndGrowthBasic) { auto ackPkt = CongestionController::AckEvent::AckPacket::Builder() .setPacketNum(pkt.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber( - pkt.nonDsrPacketSequenceNumber.value()) .setOutstandingPacketMetadata(pkt.metadata) .setLastAckedPacketInfo( pkt.lastAckedPacketInfo ? &*pkt.lastAckedPacketInfo : nullptr) diff --git a/quic/dsr/BUCK b/quic/dsr/BUCK deleted file mode 100644 index e497d3a92..000000000 --- a/quic/dsr/BUCK +++ /dev/null @@ -1,25 +0,0 @@ -load("@fbcode//quic:defs.bzl", "mvfst_cpp_library") - -oncall("traffic_protocols") - -mvfst_cpp_library( - name = "types", - srcs = [ - "Types.cpp", - ], - headers = [ - "Types.h", - ], - exported_deps = [ - "//folly:network_address", - "//quic/codec:types", - "//quic/common:optional", - "//quic/server/state:server", - "//quic/state:quic_state_machine", - ], -) - -mvfst_cpp_library( - name = "dsr_packetization_request_sender", - headers = ["DSRPacketizationRequestSender.h"], -) diff --git a/quic/dsr/CMakeLists.txt b/quic/dsr/CMakeLists.txt deleted file mode 100644 index f0978c8e4..000000000 --- a/quic/dsr/CMakeLists.txt +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -add_library( - mvfst_dsr_sender INTERFACE -) - -target_include_directories( - mvfst_dsr_sender INTERFACE - $ - $ -) - -add_library( - mvfst_dsr_types - Types.cpp -) - -set_property(TARGET mvfst_dsr_types PROPERTY VERSION ${PACKAGE_VERSION}) - -target_include_directories( - mvfst_dsr_types PUBLIC - $ - $ -) - -add_dependencies( - mvfst_dsr_types - mvfst_codec_types - mvfst_folly_utils -) - -target_link_libraries( - mvfst_dsr_types PUBLIC - Folly::folly - mvfst_codec_types - mvfst_folly_utils -) - -target_compile_options( - mvfst_dsr_types - PRIVATE - ${_QUIC_COMMON_COMPILE_OPTIONS} -) - -add_library( - mvfst_dsr_frontend - frontend/Scheduler.cpp - frontend/WriteCodec.cpp - frontend/WriteFunctions.cpp) - -set_property(TARGET mvfst_dsr_frontend PROPERTY VERSION ${PACKAGE_VERSION}) - -target_include_directories( - mvfst_dsr_frontend PUBLIC - $ - $ -) - -add_dependencies( - mvfst_dsr_frontend - mvfst_dsr_types - mvfst_flowcontrol -) - -target_link_libraries( - mvfst_dsr_frontend PUBLIC - Folly::folly - mvfst_codec_types - mvfst_folly_utils - mvfst_dsr_types -) - -target_compile_options( - mvfst_dsr_frontend - PRIVATE - ${_QUIC_COMMON_COMPILE_OPTIONS} -) - -add_library( - mvfst_dsr_backend - backend/DSRPacketizer.cpp) - -set_property(TARGET mvfst_dsr_backend PROPERTY VERSION ${PACKAGE_VERSION}) - -target_include_directories( - mvfst_dsr_backend PUBLIC - $ - $ -) - -add_dependencies( - mvfst_dsr_backend - mvfst_dsr_types - mvfst_transport - mvfst_xsk -) - -target_link_libraries( - mvfst_dsr_backend PUBLIC - Folly::folly - mvfst_codec_types - mvfst_folly_utils - mvfst_dsr_types - mvfst_transport - mvfst_xsk -) - -target_compile_options( - mvfst_dsr_frontend - PRIVATE - ${_QUIC_COMMON_COMPILE_OPTIONS} -) - -file( - GLOB_RECURSE QUIC_API_HEADERS_TOINSTALL - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - *.h -) -list(FILTER QUIC_API_HEADERS_TOINSTALL EXCLUDE REGEX test/) -foreach(header ${QUIC_API_HEADERS_TOINSTALL}) - get_filename_component(header_dir ${header} DIRECTORY) - install(FILES ${header} DESTINATION include/quic/dsr/${header_dir}) -endforeach() - -install( - TARGETS mvfst_dsr_sender - EXPORT mvfst-exports -) - -install( - TARGETS mvfst_dsr_types - EXPORT mvfst-exports - DESTINATION ${CMAKE_INSTALL_LIBDIR} -) - -install( - TARGETS mvfst_dsr_frontend - EXPORT mvfst-exports - DESTINATION ${CMAKE_INSTALL_LIBDIR} -) - -add_subdirectory(test) diff --git a/quic/dsr/DSRPacketizationRequestSender.h b/quic/dsr/DSRPacketizationRequestSender.h deleted file mode 100644 index 7679b1cad..000000000 --- a/quic/dsr/DSRPacketizationRequestSender.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -namespace quic { - -struct SendInstruction; - -class DSRPacketizationRequestSender { - public: - virtual ~DSRPacketizationRequestSender() = default; - - /** - * addSendInstruction() adds a single SendInstruction to the packetization - * request sender. The sender can accumulate the instructions then send them - * out as a batch when flush() is called. - */ - virtual bool addSendInstruction(const SendInstruction&) = 0; - - // flush() tells the sender that it can send out packetization requests - virtual bool flush() = 0; - - /** - * release() tells the sender that it should release resources. - * After release() is called, the sender should not receive any additional - * instructions - */ - virtual void release() = 0; -}; - -} // namespace quic diff --git a/quic/dsr/Types.cpp b/quic/dsr/Types.cpp deleted file mode 100644 index 31861a1d3..000000000 --- a/quic/dsr/Types.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -namespace quic { -WriteStreamFrame sendInstructionToWriteStreamFrame( - const SendInstruction& sendInstruction, - uint64_t streamPacketIdx) { - WriteStreamFrame frame( - sendInstruction.streamId, - sendInstruction.streamOffset, - sendInstruction.len, - sendInstruction.fin); - frame.fromBufMeta = true; - frame.streamPacketIdx = streamPacketIdx; - return frame; -} -} // namespace quic diff --git a/quic/dsr/Types.h b/quic/dsr/Types.h deleted file mode 100644 index 8b9a3fc7c..000000000 --- a/quic/dsr/Types.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace quic { - -// TODO: I don't think i need client address here. -struct ConnKey { - ConnectionId scid; - ConnectionId dcid; -}; - -struct ConnKeyHash { - std::size_t operator()(const ConnKey& key) const { - return folly::hash::hash_combine( - ConnectionIdHash()(key.scid), ConnectionIdHash()(key.dcid)); - } -}; - -struct ConnKeyEq { - bool operator()(const ConnKey& first, const ConnKey& second) const { - return first.scid == second.scid && first.dcid == second.dcid; - } -}; - -/** - * The SendInstruction that frontend sends to backend to build a short-header - * QUIC packet that contains a single Stream Frame. - * - * For now, a DSR packet will only have one stream frame, and nothing else. So - * we are always gonna omit the Length field in the stream frame. - * - * TODO: Consider adding the type field here so that backend doesn't have to - * to calculate it. - * - * TODO: We can also send over the encoded QuicInteger of some of these values. - * Then the backends do not have to encode them again. - * - * TODO: Or even better: why don't I just send over the encoded short header - * and stream fields as well as the meta info? - */ - -struct SendInstruction { - explicit SendInstruction(const SendInstruction& other) - : dcid(other.dcid), - scid(other.scid), - clientAddress(other.clientAddress), - packetNum(other.packetNum), - largestAckedPacketNum(other.largestAckedPacketNum), - writeOffset(other.writeOffset), - largestAckedStreamOffset(other.largestAckedStreamOffset), - streamId(other.streamId), - streamOffset(other.streamOffset), - len(other.len), - fin(other.fin), - bufMetaStartingOffset(other.bufMetaStartingOffset) {} - - explicit SendInstruction(SendInstruction&& other) - : dcid(other.dcid), - scid(other.scid), - clientAddress(other.clientAddress), - packetNum(other.packetNum), - largestAckedPacketNum(other.largestAckedPacketNum), - writeOffset(other.writeOffset), - largestAckedStreamOffset(other.largestAckedStreamOffset), - streamId(other.streamId), - streamOffset(other.streamOffset), - len(other.len), - fin(other.fin), - bufMetaStartingOffset(other.bufMetaStartingOffset) {} - - // Connection info: - const ConnectionId& dcid; - const ConnectionId& scid; - const folly::SocketAddress& clientAddress; - PacketNum packetNum{0}; - PacketNum largestAckedPacketNum{0}; - std::chrono::microseconds writeOffset{0us}; - - // QUIC Stream info - Optional largestAckedStreamOffset; - StreamId streamId; - uint64_t streamOffset; - uint64_t len; - bool fin; - uint64_t bufMetaStartingOffset; - - struct Builder { - explicit Builder(const QuicServerConnectionState& conn, StreamId idIn) - : dcid(*conn.clientConnectionId), - scid(*conn.serverConnectionId), - clientAddr(conn.peerAddress), - streamId(idIn) {} - - SendInstruction build() { - return SendInstruction( - dcid, - scid, - clientAddr, - packetNum, - largestAckedPacketNum, - writeOffset, - largestAckedStreamOffset, - streamId, - *streamOffset, - *len, - fin, - *bufMetaStartingOffset); - } - - Builder& setPacketNum(PacketNum val) { - packetNum = val; - return *this; - } - - Builder& setLargestAckedPacketNum(PacketNum val) { - largestAckedPacketNum = val; - return *this; - } - - Builder& setWriteOffset(std::chrono::microseconds val) { - writeOffset = val; - return *this; - } - - Builder& setLargestAckedStreamOffset(uint64_t val) { - largestAckedStreamOffset = val; - return *this; - } - - Builder& setStreamOffset(uint64_t val) { - streamOffset = val; - return *this; - } - - Builder& setLength(uint64_t val) { - len = val; - return *this; - } - - Builder& setFin(bool val) { - fin = val; - return *this; - } - - Builder& setBufMetaStartingOffset(uint64_t val) { - bufMetaStartingOffset = val; - return *this; - } - - private: - const ConnectionId& dcid; - const ConnectionId& scid; - const folly::SocketAddress& clientAddr; - PacketNum packetNum{0}; - PacketNum largestAckedPacketNum{0}; - Optional largestAckedStreamOffset; - std::chrono::microseconds writeOffset{0us}; - StreamId streamId; - Optional streamOffset; - Optional len; - bool fin{false}; - Optional bufMetaStartingOffset; - }; - - private: - SendInstruction( - const ConnectionId& dcidIn, - const ConnectionId& scidIn, - const folly::SocketAddress& clientAddrIn, - PacketNum packetNumIn, - PacketNum largestAckedPacketNumIn, - std::chrono::microseconds writeOffsetIn, - Optional largestAckedStreamOffsetIn, - StreamId idIn, - uint64_t streamOffsetIn, - uint64_t lenIn, - bool finIn, - uint64_t bufMetaStartingOffsetIn) - : dcid(dcidIn), - scid(scidIn), - clientAddress(clientAddrIn), - packetNum(packetNumIn), - largestAckedPacketNum(largestAckedPacketNumIn), - writeOffset(writeOffsetIn), - largestAckedStreamOffset(largestAckedStreamOffsetIn), - streamId(idIn), - streamOffset(streamOffsetIn), - len(lenIn), - fin(finIn), - bufMetaStartingOffset(bufMetaStartingOffsetIn) {} -}; - -WriteStreamFrame sendInstructionToWriteStreamFrame( - const SendInstruction& sendInstruction, - uint64_t streamPacketIdx); - -} // namespace quic diff --git a/quic/dsr/backend/BUCK b/quic/dsr/backend/BUCK deleted file mode 100644 index 02087e137..000000000 --- a/quic/dsr/backend/BUCK +++ /dev/null @@ -1,30 +0,0 @@ -load("@fbcode//quic:defs.bzl", "mvfst_cpp_library") - -oncall("traffic_protocols") - -mvfst_cpp_library( - name = "dsr_packetizer", - srcs = ["DSRPacketizer.cpp"], - headers = ["DSRPacketizer.h"], - deps = [ - "//quic/api:quic_batch_writer", - ], - exported_deps = [ - "//fizz/crypto/aead:aead", - "//fizz/protocol:default_factory", - "//fizz/protocol:protocol", - "//fizz/record:record", - "//folly:hash", - "//folly:network_address", - "//folly/container:evicting_cache_map", - "//folly/io/async:async_udp_socket", - "//quic/api:transport_helpers", - "//quic/codec:packet_number_cipher", - "//quic/codec:pktbuilder", - "//quic/codec:types", - "//quic/dsr:types", - "//quic/fizz/handshake:fizz_handshake", - "//quic/handshake:aead", - "//quic/xsk:xsk_sender", - ], -) diff --git a/quic/dsr/backend/DSRPacketizer.cpp b/quic/dsr/backend/DSRPacketizer.cpp deleted file mode 100644 index a9198d182..000000000 --- a/quic/dsr/backend/DSRPacketizer.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -namespace quic { -bool PacketGroupWriter::writeSingleQuicPacket( - BufAccessor& accessor, - ConnectionId dcid, - PacketNum packetNum, - PacketNum largestAckedByPeer, - const Aead& aead, - const PacketNumberCipher& headerCipher, - StreamId streamId, - size_t offset, - size_t length, - bool eof, - BufPtr buf) { - if (buf->computeChainDataLength() < length) { - LOG(ERROR) << "Insufficient data buffer"; - return false; - } - auto buildBuf = accessor.obtain(); - prevSize_ = buildBuf->length(); - accessor.release(std::move(buildBuf)); - - ShortHeader shortHeader(ProtectionType::KeyPhaseZero, dcid, packetNum); - InplaceQuicPacketBuilder builder( - accessor, - kDefaultMaxUDPPayload, - std::move(shortHeader), - largestAckedByPeer, - 0); - CHECK(!builder.encodePacketHeader().hasError()); - builder.accountForCipherOverhead(aead.getCipherOverhead()); - // frontend has already limited the length to flow control, thus - // flowControlLen == length - auto res = writeStreamFrameHeader( - builder, - streamId, - offset, - length, - length /* flow control len*/, - eof, - true /* skip length field in stream header */, - std::nullopt, /* stream group id */ - false /* don't append frame to builder */); - if (res.hasError()) { - throw QuicInternalException( - res.error().message, *res.error().code.asLocalErrorCode()); - } - auto dataLen = *res; - ChainedByteRangeHead chainedByteRangeHead(buf); - writeStreamFrameData(builder, chainedByteRangeHead, *dataLen); - auto packet = std::move(builder).buildPacket(); - CHECK(accessor.ownsBuffer()); - - if (packet.packet.empty) { - LOG(ERROR) << "DSR Send failed: Build empty packet."; - rollback(); - flush(); - return false; - } - if (packet.body.empty()) { - LOG(ERROR) << "DSR Send failed: Build empty body buffer"; - rollback(); - flush(); - return false; - } - CHECK(!packet.header.isChained()); - - auto headerLen = packet.header.length(); - buildBuf = accessor.obtain(); - CHECK( - packet.body.data() > buildBuf->data() && - packet.body.tail() <= buildBuf->tail()); - CHECK( - packet.header.data() >= buildBuf->data() && - packet.header.tail() < buildBuf->tail()); - // Trim off everything before the current packet, and the header length, so - // buildBuf's data starts from the body part of buildBuf. - buildBuf->trimStart(prevSize_ + headerLen); - // buildBuf and packetbuildBuf is actually the same. - auto encryptResult = - aead.inplaceEncrypt(std::move(buildBuf), &packet.header, packetNum); - if (encryptResult.hasError()) { - throw QuicInternalException( - "DSR Send failed: Encryption error: " + encryptResult.error().message, - LocalErrorCode::INTERNAL_ERROR); - } - auto packetbuildBuf = std::move(encryptResult.value()); - CHECK_EQ(packetbuildBuf->headroom(), headerLen + prevSize_); - // Include header back. - packetbuildBuf->prepend(headerLen); - - HeaderForm headerForm = packet.packet.header.getHeaderForm(); - auto headerEncryptResult = encryptPacketHeader( - headerForm, - packetbuildBuf->writableData(), - headerLen, - packetbuildBuf->data() + headerLen, - packetbuildBuf->length() - headerLen, - headerCipher); - if (headerEncryptResult.hasError()) { - throw QuicInternalException( - "DSR Send failed: Header encryption error: " + - headerEncryptResult.error().message, - LocalErrorCode::INTERNAL_ERROR); - } - CHECK(!packetbuildBuf->isChained()); - auto encodedSize = packetbuildBuf->length(); - // Include previous packets back. - packetbuildBuf->prepend(prevSize_); - accessor.release(std::move(packetbuildBuf)); - bool ret = send(encodedSize); - return ret; -} - -BufQuicBatchResult PacketGroupWriter::writePacketsGroup( - RequestGroup& reqGroup, - const std::function& bufProvider) { - if (reqGroup.requests.empty()) { - LOG(ERROR) << "Empty packetization request"; - return {}; - } - if (!reqGroup.cipherPair->aead || !reqGroup.cipherPair->headerCipher) { - LOG(ERROR) << "Missing ciphers"; - return {}; - } - // It's ok if reqGourp's size is larger than ioBufBatch's batch size. The - // ioBufBatch will flush when it hits the limit then start a new batch - // transparently. - for (const auto& request : reqGroup.requests) { - auto bufAccessor = getBufAccessor(); - if (!bufAccessor) { - // We hit this path only when there are no free UMEM frames when we're - // using AF_XDP. - return getResult(); - } - auto ret = writeSingleQuicPacket( - *bufAccessor, - reqGroup.dcid, - request.packetNum, - request.largestAckedPacketNum, - *reqGroup.cipherPair->aead, - *reqGroup.cipherPair->headerCipher, - request.streamId, - request.offset, - request.len, - request.fin, - bufProvider(request)); - if (!ret) { - return getResult(); - } - } - flush(); - return getResult(); -} - -static auto& getThreadLocalConn(size_t maxPackets = 44) { - static thread_local QuicConnectionStateBase fakeConn{QuicNodeType::Server}; - static thread_local bool initAccessor [[maybe_unused]] = [&]() { - fakeConn.bufAccessor = new BufAccessor{kDefaultMaxUDPPayload * maxPackets}; - // Store this so we can use it to set the batch writer. - fakeConn.transportSettings.maxBatchSize = maxPackets; - return true; - }(); - return fakeConn; -} - -UdpSocketPacketGroupWriter::UdpSocketPacketGroupWriter( - QuicAsyncUDPSocket& sock, - const folly::SocketAddress& clientAddress, - BatchWriterPtr&& batchWriter) - : sock_(sock), - fakeConn_(getThreadLocalConn()), - ioBufBatch_( - std::move(batchWriter), - sock_, - clientAddress, - nullptr /* statsCallback */, - nullptr /* happyEyeballsState */) {} - -UdpSocketPacketGroupWriter::UdpSocketPacketGroupWriter( - QuicAsyncUDPSocket& sock, - const folly::SocketAddress& clientAddress) - : sock_(sock), - fakeConn_(getThreadLocalConn()), - ioBufBatch_( - BatchWriterPtr(new GSOInplacePacketBatchWriter( - fakeConn_, - fakeConn_.transportSettings.maxBatchSize)), - sock_, - clientAddress, - nullptr /* statsCallback */, - nullptr /* happyEyeballsState */) {} - -BufAccessor* UdpSocketPacketGroupWriter::getBufAccessor() { - return fakeConn_.bufAccessor; -} - -void UdpSocketPacketGroupWriter::rollback() { - auto buildBuf = getBufAccessor()->obtain(); - buildBuf->trimEnd(buildBuf->length() - prevSize_); - getBufAccessor()->release(std::move(buildBuf)); -} - -bool UdpSocketPacketGroupWriter::send(uint32_t size) { - auto result = ioBufBatch_.write(nullptr /* no need to pass buildBuf */, size); - CHECK(!result.hasError()); - return result.value(); -} - -void UdpSocketPacketGroupWriter::flush() { - CHECK(!ioBufBatch_.flush().hasError()); -} - -BufQuicBatchResult UdpSocketPacketGroupWriter::getResult() { - return ioBufBatch_.getResult(); -} - -#if defined(__linux__) && !defined(ANDROID) - -void XskPacketGroupWriter::flush() { - // Leaving this blank because the XskContainer does some flushing internally -} - -BufAccessor* XskPacketGroupWriter::getBufAccessor() { - auto maybeXskBuffer = - xskSender_->getXskBuffer(vipAddress_.getIPAddress().isV6()); - if (!maybeXskBuffer) { - LOG(ERROR) << "Failed to get XskBuffer, no free UMEM frames"; - currentXskBuffer_.buffer = nullptr; - currentXskBuffer_.payloadLength = 0; - currentXskBuffer_.frameIndex = 0; - return nullptr; - } - currentXskBuffer_ = *maybeXskBuffer; - auto ioBuf = BufHelpers::takeOwnership( - currentXskBuffer_.buffer, - kDefaultMaxUDPPayload, - 0, - [](void* /* buf */, void* /* userData */) { - // Empty destructor because we don't own the buffer - }); - bufAccessor_ = std::make_unique(std::move(ioBuf)); - return bufAccessor_.get(); -} - -void XskPacketGroupWriter::rollback() { - xskSender_->returnBuffer(currentXskBuffer_); -} - -bool XskPacketGroupWriter::send(uint32_t size) { - currentXskBuffer_.payloadLength = size; - xskSender_->writeXskBuffer(currentXskBuffer_, clientAddress_, vipAddress_); - result_.bytesSent += size; - result_.packetsSent++; - return true; -} - -BufQuicBatchResult XskPacketGroupWriter::getResult() { - return result_; -} - -#endif - -} // namespace quic diff --git a/quic/dsr/backend/DSRPacketizer.h b/quic/dsr/backend/DSRPacketizer.h deleted file mode 100644 index 769b8aa79..000000000 --- a/quic/dsr/backend/DSRPacketizer.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) && !defined(ANDROID) -#include -#endif - -namespace quic { - -/** - * For now, each packetization request builds only one QUIC packet. I think - * it's easier to batch packetization requests than to make one request build - * multiple packets. But I'm open to discussion. - * - * What a Packetization request is supposed to include: - * - * All parems in CipherBuilder::buildCiphers(): - * TrafficKey (key + iv), CipherSuite, packet protection key - * - * Then all the non-cipher params in DSRBackenderSender::sendQuicPacket: - * DCID, Client addr, Packet Number, Stream Id, Stream offset, Stream data - * length, Stream data EOF. - * - */ - -struct CipherPair { - std::unique_ptr aead; - std::unique_ptr headerCipher; -}; - -class CipherBuilder { - public: - CipherPair buildCiphers( - fizz::TrafficKey&& trafficKey, - fizz::CipherSuite cipherSuite, - BufPtr packetProtectionKey) { - auto aead = FizzAead::wrap(deriveRecordAeadWithLabel( - *quicFizzCryptoFactory_.getFizzFactory(), - std::move(trafficKey), - cipherSuite)); - auto headerCipherResult = quicFizzCryptoFactory_.makePacketNumberCipher( - fizz::CipherSuite::TLS_AES_128_GCM_SHA256); - if (headerCipherResult.hasError()) { - throw std::runtime_error("Failed to create header cipher"); - } - auto headerCipher = std::move(headerCipherResult.value()); - if (headerCipher->setKey(packetProtectionKey->coalesce()).hasError()) { - throw std::runtime_error("Failed to set header cipher key"); - } - - return {std::move(aead), std::move(headerCipher)}; - } - - private: - std::unique_ptr deriveRecordAeadWithLabel( - const fizz::Factory& factory, - fizz::TrafficKey trafficKey, - fizz::CipherSuite cipher) { - auto aead = factory.makeAead(cipher); - aead->setKey(std::move(trafficKey)); - return aead; - } - - FizzCryptoFactory quicFizzCryptoFactory_; -}; - -class QuicPacketizer { - public: - virtual ~QuicPacketizer() = default; - - virtual BufPtr sendQuicPacket( - ConnectionId dcid, - const folly::SocketAddress& clientAddr, - PacketNum packetNum, - const Aead& aead, - const PacketNumberCipher& headerCipher, - StreamId streamId, - size_t offset, - size_t length, - bool eof) = 0; -}; - -struct PacketizationRequest { - PacketizationRequest( - PacketNum packetNumIn, - PacketNum largestAckedPacketNumIn, - StreamId streamIdIn, - uint64_t offsetIn, - uint64_t lenIn, - bool finIn, - uint64_t payloadOffsetIn) - : packetNum(packetNumIn), - largestAckedPacketNum(largestAckedPacketNumIn), - streamId(streamIdIn), - offset(offsetIn), - len(lenIn), - fin(finIn), - payloadOffset(payloadOffsetIn) {} - - PacketNum packetNum; - PacketNum largestAckedPacketNum; - - // QUIC Stream info - StreamId streamId; - uint64_t offset; - uint64_t len; - bool fin; - // This is the offset of the buffer payload. It is different from the offset - // above which is the stream bytes offset. - uint64_t payloadOffset; -}; - -struct RequestGroup { - ConnectionId dcid; - ConnectionId scid; - folly::SocketAddress clientAddress; - const CipherPair* cipherPair{nullptr}; - SmallVec requests; - std::chrono::microseconds writeOffset{0us}; -}; - -class PacketGroupWriter { - public: - virtual ~PacketGroupWriter() = default; - - BufQuicBatchResult writePacketsGroup( - RequestGroup& reqGroup, - const std::function& - bufProvider); - - bool writeSingleQuicPacket( - BufAccessor& accessor, - ConnectionId dcid, - PacketNum packetNum, - PacketNum largestAckedByPeer, - const Aead& aead, - const PacketNumberCipher& headerCipher, - StreamId streamId, - size_t offset, - size_t length, - bool eof, - BufPtr buf); - - protected: - uint32_t prevSize_{0}; - - private: - virtual void flush() = 0; - - virtual BufAccessor* getBufAccessor() = 0; - - virtual void rollback() = 0; - - virtual bool send(uint32_t size) = 0; - - virtual BufQuicBatchResult getResult() = 0; -}; - -class UdpSocketPacketGroupWriter : public PacketGroupWriter { - public: - // This constructor is for testing only. - UdpSocketPacketGroupWriter( - QuicAsyncUDPSocket& sock, - const folly::SocketAddress& clientAddress, - BatchWriterPtr&& batchWriter); - - UdpSocketPacketGroupWriter( - QuicAsyncUDPSocket& sock, - const folly::SocketAddress& clientAddress); - - ~UdpSocketPacketGroupWriter() override = default; - - IOBufQuicBatch& getIOBufQuicBatch() { - return ioBufBatch_; - } - - private: - void flush() override; - - BufAccessor* getBufAccessor() override; - - void rollback() override; - - bool send(uint32_t size) override; - - BufQuicBatchResult getResult() override; - - QuicAsyncUDPSocket& sock_; - quic::QuicConnectionStateBase& fakeConn_; - IOBufQuicBatch ioBufBatch_; - BufQuicBatchResult result_; -}; - -#if defined(__linux__) && !defined(ANDROID) - -class XskPacketGroupWriter : public PacketGroupWriter { - public: - XskPacketGroupWriter( - facebook::xdpsocket::XskSender* xskSender, - folly::SocketAddress clientAddress, - folly::SocketAddress vipAddress) - : xskSender_(xskSender), - clientAddress_(std::move(clientAddress)), - vipAddress_(std::move(vipAddress)) {} - - ~XskPacketGroupWriter() override = default; - - private: - void flush() override; - - BufAccessor* getBufAccessor() override; - - void rollback() override; - - bool send(uint32_t size) override; - - BufQuicBatchResult getResult() override; - - facebook::xdpsocket::XskSender* xskSender_; - folly::SocketAddress clientAddress_; - folly::SocketAddress vipAddress_; - facebook::xdpsocket::XskBuffer currentXskBuffer_; - BufQuicBatchResult result_; - std::unique_ptr bufAccessor_; -}; - -#endif - -} // namespace quic diff --git a/quic/dsr/backend/test/BUCK b/quic/dsr/backend/test/BUCK deleted file mode 100644 index e7ab56679..000000000 --- a/quic/dsr/backend/test/BUCK +++ /dev/null @@ -1,32 +0,0 @@ -load("@fbcode//quic:defs.bzl", "mvfst_cpp_library", "mvfst_cpp_test") - -oncall("traffic_protocols") - -mvfst_cpp_library( - name = "test_utils", - headers = [ - "TestUtils.h", - ], - exported_deps = [ - "//quic/dsr:types", - "//quic/dsr/backend:dsr_packetizer", - ], -) - -mvfst_cpp_test( - name = "dsr_packetizer_test", - srcs = [ - "DSRPacketizerTest.cpp", - ], - deps = [ - ":test_utils", - "//folly/portability:gtest", - "//quic/common/events:folly_eventbase", - "//quic/common/test:test_utils", - "//quic/common/testutil:mock_async_udp_socket", - "//quic/common/udpsocket:quic_async_udp_socket", - "//quic/dsr/backend:dsr_packetizer", - "//quic/dsr/frontend:write_functions", - "//quic/dsr/test:test_common", - ], -) diff --git a/quic/dsr/backend/test/DSRPacketizerTest.cpp b/quic/dsr/backend/test/DSRPacketizerTest.cpp deleted file mode 100644 index 7c6a9efce..000000000 --- a/quic/dsr/backend/test/DSRPacketizerTest.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace testing; - -namespace { -fizz::TrafficKey getFizzTestKey() { - fizz::TrafficKey testKey; - auto quicKey = quic::test::getQuicTestKey(); - testKey.key = std::move(quicKey.key); - testKey.iv = std::move(quicKey.iv); - return testKey; -} -} // namespace - -namespace quic::test { - -class DSRPacketizerTest : public DSRCommonTestFixture {}; - -TEST_F(DSRPacketizerTest, BuildCipher) { - CipherBuilder cipherBuilder; - auto cipherPair = cipherBuilder.buildCiphers( - getFizzTestKey(), - fizz::CipherSuite::TLS_AES_128_GCM_SHA256, - packetProtectionKey_->clone()); - EXPECT_NE(cipherPair.aead, nullptr); - EXPECT_NE(cipherPair.headerCipher, nullptr); -} - -class DSRPacketizerSingleWriteTest : public Test { - protected: - void SetUp() override { - aead = test::createNoOpAead(); - headerCipher = test::createNoOpHeaderCipher().value(); - qEvb_ = std::make_shared(&evb); - } - - folly::EventBase evb; - std::shared_ptr qEvb_; - folly::SocketAddress peerAddress{"127.0.0.1", 1234}; - std::unique_ptr aead; - std::unique_ptr headerCipher; -}; - -TEST_F(DSRPacketizerSingleWriteTest, SingleWrite) { - auto testBatchWriter = new test::TestPacketBatchWriter(16); - auto batchWriter = BatchWriterPtr(testBatchWriter); - auto socket = - std::make_unique>(qEvb_); - PacketNum packetNum = 20; - PacketNum largestAckedByPeer = 0; - StreamId streamId = 0; - size_t offset = 0; - size_t length = 100; - bool eof = false; - auto dcid = test::getTestConnectionId(); - BufAccessor accessor{16 * kDefaultMaxUDPPayload}; - UdpSocketPacketGroupWriter packetGroupWriter( - *socket, peerAddress, std::move(batchWriter)); - auto ret = packetGroupWriter.writeSingleQuicPacket( - accessor, - dcid, - packetNum, - largestAckedByPeer, - *aead, - *headerCipher, - streamId, - offset, - length, - eof, - test::buildRandomInputData(5000)); - EXPECT_TRUE(ret); - // This sucks. But i can't think of a better way to verify we do not - // write a stream frame length into the packet. - EXPECT_EQ( - testBatchWriter->getBufSize(), - 1 /* short header initial byte */ + 1 /* packet num */ + - dcid.size() /* dcid */ + 1 /* stream frame initial byte */ + - 1 /* stream id */ + length /* actual data */ + - aead->getCipherOverhead()); - ASSERT_FALSE(packetGroupWriter.getIOBufQuicBatch().flush().hasError()); - EXPECT_EQ(1, packetGroupWriter.getIOBufQuicBatch().getPktSent()); -} - -TEST_F(DSRPacketizerSingleWriteTest, NotEnoughData) { - auto batchWriter = BatchWriterPtr(new test::TestPacketBatchWriter(16)); - auto socket = - std::make_unique>(qEvb_); - UdpSocketPacketGroupWriter packetGroupWriter( - *socket, peerAddress, std::move(batchWriter)); - PacketNum packetNum = 20; - PacketNum largestAckedByPeer = 0; - StreamId streamId = 0; - size_t offset = 0; - size_t length = 100; - bool eof = false; - BufAccessor accessor{16 * kDefaultMaxUDPPayload}; - auto ret = packetGroupWriter.writeSingleQuicPacket( - accessor, - test::getTestConnectionId(), - packetNum, - largestAckedByPeer, - *aead, - *headerCipher, - streamId, - offset, - length, - eof, - folly::IOBuf::copyBuffer("Clif")); - EXPECT_FALSE(ret); - ASSERT_FALSE(packetGroupWriter.getIOBufQuicBatch().flush().hasError()); - EXPECT_EQ(0, packetGroupWriter.getIOBufQuicBatch().getPktSent()); -} - -class DSRMultiWriteTest : public DSRCommonTestFixture { - void SetUp() override { - qEvb_ = std::make_shared(&evb_); - } - - protected: - FizzCryptoFactory factory_; - folly::EventBase evb_; - std::shared_ptr qEvb_; -}; - -TEST_F(DSRMultiWriteTest, TwoRequestsWithLoss) { - prepareFlowControlAndStreamLimit(); - auto streamId = prepareOneStream(1000); - auto stream = conn_.streamManager->findStream(streamId); - // Pretend we sent the non DSR data - stream->ackedIntervals.insert(0, stream->writeBuffer.chainLength() - 1); - stream->currentWriteOffset = stream->writeBuffer.chainLength(); - stream->writeBuffer.move(); - ChainedByteRangeHead(std::move(stream->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream); - auto bufMetaStartingOffset = stream->writeBufMeta.offset; - // Move part of the BufMetas to lossBufMetas - auto split = stream->writeBufMeta.split(500); - stream->lossBufMetas.push_back(split); - size_t packetLimit = 10; - auto packetizationResult = writePacketizationRequest( - conn_, getTestConnectionId(), packetLimit, *aead_); - ASSERT_FALSE(packetizationResult.hasError()); - EXPECT_EQ(2, packetizationResult.value()); - EXPECT_EQ(2, countInstructions(streamId)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - auto& packet1 = conn_.outstandings.packets.front().packet; - auto& packet2 = conn_.outstandings.packets.back().packet; - EXPECT_EQ(1, packet1.frames.size()); - WriteStreamFrame expectedFirstFrame( - streamId, bufMetaStartingOffset, 500, false, true, std::nullopt, 0); - WriteStreamFrame expectedSecondFrame( - streamId, 500 + bufMetaStartingOffset, 500, true, true, std::nullopt, 1); - EXPECT_EQ(expectedFirstFrame, *packet1.frames[0].asWriteStreamFrame()); - EXPECT_EQ(expectedSecondFrame, *packet2.frames[0].asWriteStreamFrame()); - - std::vector sentData; - auto sock = std::make_unique>(qEvb_); - EXPECT_CALL(*sock, writeGSO(conn_.peerAddress, _, _, _)) - .WillRepeatedly(Invoke([&](const folly::SocketAddress&, - const struct iovec* vec, - size_t iovec_len, - QuicAsyncUDPSocket::WriteOptions) { - sentData.push_back(copyChain(folly::IOBuf::wrapIov(vec, iovec_len))); - return getTotalIovecLen(vec, iovec_len); - })); - EXPECT_CALL(*sock, write(conn_.peerAddress, _, _)) - .WillRepeatedly(Invoke([&](const folly::SocketAddress&, - const struct iovec* vec, - size_t iovec_len) { - sentData.push_back(copyChain(folly::IOBuf::wrapIov(vec, iovec_len))); - return getTotalIovecLen(vec, iovec_len); - })); - auto& instruction = pendingInstructions_.front(); - CipherBuilder builder; - auto cipherPair = builder.buildCiphers( - getFizzTestKey(), - fizz::CipherSuite::TLS_AES_128_GCM_SHA256, - packetProtectionKey_->clone()); - - RequestGroup requests{ - .dcid = instruction.dcid, - .scid = instruction.scid, - .clientAddress = instruction.clientAddress, - .cipherPair = &cipherPair, - .requests = {}}; - - for (const auto& i : pendingInstructions_) { - requests.requests.push_back(sendInstructionToPacketizationRequest(i)); - } - - UdpSocketPacketGroupWriter packetGroupWriter(*sock, requests.clientAddress); - auto result = packetGroupWriter.writePacketsGroup( - requests, [](const PacketizationRequest& req) { - return buildRandomInputData(req.len); - }); - ASSERT_EQ(2, result.packetsSent); - ASSERT_EQ(2, sentData.size()); - EXPECT_GT(sentData[0]->computeChainDataLength(), 500); - EXPECT_GT(sentData[1]->computeChainDataLength(), 500); -} - -} // namespace quic::test diff --git a/quic/dsr/backend/test/TestUtils.h b/quic/dsr/backend/test/TestUtils.h deleted file mode 100644 index e831ee907..000000000 --- a/quic/dsr/backend/test/TestUtils.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -#pragma once - -namespace quic::test { - -inline quic::PacketizationRequest sendInstructionToPacketizationRequest( - const quic::SendInstruction& instruction) { - quic::PacketizationRequest request( - instruction.packetNum, - instruction.largestAckedPacketNum, - instruction.streamId, - instruction.streamOffset, - instruction.len, - instruction.fin, - instruction.streamOffset - instruction.bufMetaStartingOffset); - return request; -} - -} // namespace quic::test diff --git a/quic/dsr/frontend/BUCK b/quic/dsr/frontend/BUCK deleted file mode 100644 index 7dd911f12..000000000 --- a/quic/dsr/frontend/BUCK +++ /dev/null @@ -1,74 +0,0 @@ -load("@fbcode//quic:defs.bzl", "mvfst_cpp_library") - -oncall("traffic_protocols") - -mvfst_cpp_library( - name = "write_codec", - srcs = [ - "WriteCodec.cpp", - ], - headers = [ - "WriteCodec.h", - ], - deps = [ - "//quic/common:optional", - ], - exported_deps = [ - ":packet_builder", - "//quic/dsr:types", - ], -) - -mvfst_cpp_library( - name = "packet_builder", - headers = [ - "PacketBuilder.h", - ], - exported_deps = [ - "//quic/codec:packet_number", - "//quic/codec:types", - "//quic/dsr:types", - ], -) - -mvfst_cpp_library( - name = "scheduler", - srcs = [ - "Scheduler.cpp", - ], - headers = [ - "Scheduler.h", - ], - deps = [ - ":write_codec", - "//quic/flowcontrol:flow_control", - "//quic/state:state_functions", - "//quic/state:stream_functions", - ], - exported_deps = [ - ":packet_builder", - "//quic/server/state:server", - "//quic/state:quic_state_machine", - ], -) - -mvfst_cpp_library( - name = "write_functions", - srcs = [ - "WriteFunctions.cpp", - ], - headers = [ - "WriteFunctions.h", - ], - deps = [ - "//folly:scope_guard", - ], - exported_deps = [ - ":scheduler", - "//quic/api:transport_helpers", - "//quic/codec:types", - "//quic/dsr:dsr_packetization_request_sender", - "//quic/handshake:aead", - "//quic/server/state:server", - ], -) diff --git a/quic/dsr/frontend/PacketBuilder.h b/quic/dsr/frontend/PacketBuilder.h deleted file mode 100644 index 9bc5a8806..000000000 --- a/quic/dsr/frontend/PacketBuilder.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include - -namespace quic { - -struct DSRPacketBuilderBase { - virtual ~DSRPacketBuilderBase() = default; - virtual size_t remainingSpace() const noexcept = 0; - virtual void addSendInstruction( - SendInstruction&&, - uint32_t streamEncodedSize, - uint64_t streamPacketIdx) = 0; -}; - -/** - * This is likely a bad name. The point of having a "Packet Builder" is to - * create the OutstandingPacketWrapper when we send out send instructions. - * - * I do think from perf perspective we can do better than this in the future. - */ -class DSRPacketBuilder : public DSRPacketBuilderBase { - public: - explicit DSRPacketBuilder( - size_t packetSize, - ShortHeader header, - PacketNum largestAckedPacketNum) - : packetSize_(packetSize), packet_(std::move(header)) { - updatePacketSizeWithHeader(largestAckedPacketNum); - } - - void addSendInstruction( - SendInstruction&& sendInstruction, - uint32_t streamEncodedSize, - uint64_t streamPacketIdx) override { - CHECK( - sendInstructions_.empty() || - sendInstructions_.back().streamId == sendInstruction.streamId); - packet_.frames.push_back( - sendInstructionToWriteStreamFrame(sendInstruction, streamPacketIdx)); - sendInstructions_.push_back(std::move(sendInstruction)); - packetSize_ -= streamEncodedSize; - encodedSize_ += streamEncodedSize; - } - - struct Packet { - RegularQuicWritePacket packet; - SmallVec sendInstructions; - uint32_t encodedSize; - - Packet( - RegularQuicWritePacket pkt, - SmallVec instructions, - uint32_t size) - : packet(std::move(pkt)), - sendInstructions(std::move(instructions)), - encodedSize(size) {} - }; - - Packet buildPacket() && { - CHECK(!sendInstructions_.empty()); - CHECK_EQ(sendInstructions_.size(), packet_.frames.size()); - return Packet(packet_, std::move(sendInstructions_), encodedSize_); - } - - size_t remainingSpace() const noexcept override { - return packetSize_; - } - - private: - void updatePacketSizeWithHeader(PacketNum largestAckedPacketNum) { - auto shortHeader = packet_.header.asShort(); - CHECK(shortHeader); - auto packetNumEncoding = encodePacketNumber( - shortHeader->getPacketSequenceNum(), largestAckedPacketNum); - auto connIdLen = shortHeader->getConnectionId().size(); - if (packetNumEncoding.length + connIdLen + 1 > packetSize_) { - packetSize_ = 0; - return; - } - auto headerSize = packetNumEncoding.length + connIdLen + 1; - encodedSize_ += headerSize; - packetSize_ -= headerSize; - } - - private: - size_t packetSize_; - RegularQuicWritePacket packet_; - SmallVec sendInstructions_; - uint32_t encodedSize_{0}; -}; - -} // namespace quic diff --git a/quic/dsr/frontend/Scheduler.cpp b/quic/dsr/frontend/Scheduler.cpp deleted file mode 100644 index 4709c045d..000000000 --- a/quic/dsr/frontend/Scheduler.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include - -namespace quic { - -DSRStreamFrameScheduler::DSRStreamFrameScheduler( - QuicServerConnectionState& conn) - : conn_(conn) {} - -bool DSRStreamFrameScheduler::hasPendingData() const { - return !nextStreamNonDsr_ && - (conn_.streamManager->hasDSRLoss() || - (conn_.streamManager->hasDSRWritable() && - getSendConnFlowControlBytesWire(conn_) > 0)); -} - -DSRStreamFrameScheduler::SchedulingResult -DSRStreamFrameScheduler::enrichAndAddSendInstruction( - uint32_t encodedSize, - DSRStreamFrameScheduler::SchedulingResult result, - DSRPacketBuilderBase& packetBuilder, - SendInstruction::Builder& instructionBuilder, - const deprecated::PriorityQueue& writeQueue, - const deprecated::PriorityQueue::LevelItr& levelIter, - QuicStreamState& stream) { - enrichInstruction(instructionBuilder, stream); - packetBuilder.addSendInstruction( - instructionBuilder.build(), encodedSize, stream.streamPacketIdx++); - result.writeSuccess = true; - result.sender = stream.dsrSender.get(); - levelIter->iterator->next(); - auto nextStreamId = writeQueue.getNextScheduledStream(); - auto nextStream = - CHECK_NOTNULL(conn_.streamManager->findStream(nextStreamId)); - if (nextStream->hasSchedulableData()) { - nextStreamNonDsr_ = true; - } - return result; -} - -DSRStreamFrameScheduler::SchedulingResult -DSRStreamFrameScheduler::enrichAndAddSendInstruction( - uint32_t encodedSize, - DSRStreamFrameScheduler::SchedulingResult result, - DSRPacketBuilderBase& packetBuilder, - SendInstruction::Builder& instructionBuilder, - const PriorityQueue& writeQueue, - QuicStreamState& stream) { - enrichInstruction(instructionBuilder, stream); - packetBuilder.addSendInstruction( - instructionBuilder.build(), encodedSize, stream.streamPacketIdx++); - result.writeSuccess = true; - result.sender = stream.dsrSender.get(); - auto id = writeQueue.peekNextScheduledID(); - CHECK(id.isStreamID()); - auto nextStreamId = id.asStreamID(); - auto nextStream = - CHECK_NOTNULL(conn_.streamManager->findStream(nextStreamId)); - if (nextStream->hasSchedulableData()) { - nextStreamNonDsr_ = true; - } - return result; -} - -/** - * Note the difference between this and the regular StreamFrameScheduler. - * There is no current way of knowing if two streams can be DSR-ed from the - * same backend. Thus one SendInstruction can only have one stream. So this API - * only write a single stream. - */ -quic::Expected -DSRStreamFrameScheduler::writeStream(DSRPacketBuilderBase& builder) { - auto oldWriteQueue = conn_.streamManager->oldWriteQueue(); - if (oldWriteQueue) { - return writeStreamImpl(builder, *oldWriteQueue); - } else { - return writeStreamImpl(builder, conn_.streamManager->writeQueue()); - } -} - -quic::Expected -DSRStreamFrameScheduler::writeStreamImpl( - DSRPacketBuilderBase& builder, - PriorityQueue& writeQueue) { - SchedulingResult result; - if (writeQueue.empty()) { - return result; - } - auto txn = writeQueue.beginTransaction(); - auto guard = - folly::makeGuard([&] { writeQueue.rollbackTransaction(std::move(txn)); }); - auto id = writeQueue.getNextScheduledID(std::nullopt); - CHECK(id.isStreamID()); - auto streamId = id.asStreamID(); - auto stream = conn_.streamManager->findStream(streamId); - CHECK(stream); - if (!stream->dsrSender || !stream->hasSchedulableDsr()) { - nextStreamNonDsr_ = true; - return result; - } - bool hasFreshBufMeta = stream->writeBufMeta.length > 0; - bool hasLossBufMeta = !stream->lossBufMetas.empty(); - CHECK(stream->hasSchedulableDsr()); - if (hasLossBufMeta) { - SendInstruction::Builder instructionBuilder(conn_, streamId); - auto encodedSizeExpected = writeDSRStreamFrame( - builder, - instructionBuilder, - streamId, - stream->lossBufMetas.front().offset, - stream->lossBufMetas.front().length, - stream->lossBufMetas.front() - .length, // flowControlLen shouldn't be used to limit loss write - stream->lossBufMetas.front().eof, - stream->currentWriteOffset + stream->pendingWrites.chainLength()); - if (encodedSizeExpected.hasError()) { - return quic::make_unexpected(encodedSizeExpected.error()); - } - - auto encodedSize = encodedSizeExpected.value(); - if (encodedSize > 0) { - if (builder.remainingSpace() < encodedSize) { - return result; - } - guard.dismiss(); - writeQueue.commitTransaction(std::move(txn)); - return enrichAndAddSendInstruction( - encodedSize, - std::move(result), - builder, - instructionBuilder, - writeQueue, - *stream); - } - } - if (!hasFreshBufMeta || builder.remainingSpace() == 0) { - return result; - } - // If we have fresh BufMeta to write, the offset cannot be 0. This is based on - // the current limit that some real data has to be written into the stream - // before BufMetas. - CHECK_NE(stream->writeBufMeta.offset, 0); - uint64_t connWritableBytes = getSendConnFlowControlBytesWire(conn_); - if (connWritableBytes == 0) { - return result; - } - // When stream still has pendingWrites, getSendStreamFlowControlBytesWire - // counts from currentWriteOffset which isn't right for BufMetas. - auto streamFlowControlLen = std::min( - getSendStreamFlowControlBytesWire(*stream), - stream->flowControlState.peerAdvertisedMaxOffset - - stream->writeBufMeta.offset); - auto flowControlLen = std::min(streamFlowControlLen, connWritableBytes); - bool canWriteFin = stream->finalWriteOffset.has_value() && - stream->writeBufMeta.length <= flowControlLen; - SendInstruction::Builder instructionBuilder(conn_, streamId); - auto encodedSizeExpected = writeDSRStreamFrame( - builder, - instructionBuilder, - streamId, - stream->writeBufMeta.offset, - stream->writeBufMeta.length, - flowControlLen, - canWriteFin, - stream->currentWriteOffset + stream->pendingWrites.chainLength()); - if (encodedSizeExpected.hasError()) { - return quic::make_unexpected(encodedSizeExpected.error()); - } - - auto encodedSize = encodedSizeExpected.value(); - if (encodedSize > 0) { - if (builder.remainingSpace() < encodedSize) { - return result; - } - guard.dismiss(); - writeQueue.commitTransaction(std::move(txn)); - return enrichAndAddSendInstruction( - encodedSize, - std::move(result), - builder, - instructionBuilder, - writeQueue, - *stream); - } - return result; -} - -quic::Expected -DSRStreamFrameScheduler::writeStreamImpl( - DSRPacketBuilderBase& builder, - const deprecated::PriorityQueue& writeQueue) { - SchedulingResult result; - const auto& levelIter = std::find_if( - writeQueue.levels.cbegin(), - writeQueue.levels.cend(), - [&](const auto& level) { return !level.empty(); }); - if (levelIter == writeQueue.levels.cend()) { - return result; - } - levelIter->iterator->begin(); - auto streamId = levelIter->iterator->current(); - auto stream = conn_.streamManager->findStream(streamId); - CHECK(stream); - if (!stream->dsrSender || !stream->hasSchedulableDsr()) { - nextStreamNonDsr_ = true; - return result; - } - bool hasFreshBufMeta = stream->writeBufMeta.length > 0; - bool hasLossBufMeta = !stream->lossBufMetas.empty(); - CHECK(stream->hasSchedulableDsr()); - if (hasLossBufMeta) { - SendInstruction::Builder instructionBuilder(conn_, streamId); - auto encodedSizeExpected = writeDSRStreamFrame( - builder, - instructionBuilder, - streamId, - stream->lossBufMetas.front().offset, - stream->lossBufMetas.front().length, - stream->lossBufMetas.front() - .length, // flowControlLen shouldn't be used to limit loss write - stream->lossBufMetas.front().eof, - stream->currentWriteOffset + stream->pendingWrites.chainLength()); - - if (encodedSizeExpected.hasError()) { - return quic::make_unexpected(encodedSizeExpected.error()); - } - - auto encodedSize = encodedSizeExpected.value(); - if (encodedSize > 0) { - if (builder.remainingSpace() < encodedSize) { - return result; - } - return enrichAndAddSendInstruction( - encodedSize, - std::move(result), - builder, - instructionBuilder, - writeQueue, - levelIter, - *stream); - } - } - if (!hasFreshBufMeta || builder.remainingSpace() == 0) { - return result; - } - // If we have fresh BufMeta to write, the offset cannot be 0. This is based on - // the current limit that some real data has to be written into the stream - // before BufMetas. - CHECK_NE(stream->writeBufMeta.offset, 0); - uint64_t connWritableBytes = getSendConnFlowControlBytesWire(conn_); - if (connWritableBytes == 0) { - return result; - } - // When stream still has pendingWrites, getSendStreamFlowControlBytesWire - // counts from currentWriteOffset which isn't right for BufMetas. - auto streamFlowControlLen = std::min( - getSendStreamFlowControlBytesWire(*stream), - stream->flowControlState.peerAdvertisedMaxOffset - - stream->writeBufMeta.offset); - auto flowControlLen = std::min(streamFlowControlLen, connWritableBytes); - bool canWriteFin = stream->finalWriteOffset.has_value() && - stream->writeBufMeta.length <= flowControlLen; - SendInstruction::Builder instructionBuilder(conn_, streamId); - auto encodedSizeExpected = writeDSRStreamFrame( - builder, - instructionBuilder, - streamId, - stream->writeBufMeta.offset, - stream->writeBufMeta.length, - flowControlLen, - canWriteFin, - stream->currentWriteOffset + stream->pendingWrites.chainLength()); - - if (encodedSizeExpected.hasError()) { - return quic::make_unexpected(encodedSizeExpected.error()); - } - - auto encodedSize = encodedSizeExpected.value(); - if (encodedSize > 0) { - if (builder.remainingSpace() < encodedSize) { - return result; - } - return enrichAndAddSendInstruction( - encodedSize, - std::move(result), - builder, - instructionBuilder, - writeQueue, - levelIter, - *stream); - } - return result; -} - -void DSRStreamFrameScheduler::enrichInstruction( - SendInstruction::Builder& builder, - const QuicStreamState& stream) { - builder.setPacketNum(getNextPacketNum(conn_, PacketNumberSpace::AppData)) - .setLargestAckedPacketNum(getAckState(conn_, PacketNumberSpace::AppData) - .largestAckedByPeer.value_or(0)); - - auto largestDeliverableOffset = getLargestDeliverableOffset(stream); - if (largestDeliverableOffset) { - builder.setLargestAckedStreamOffset(*largestDeliverableOffset); - } - // TODO set to actual write delay. - builder.setWriteOffset(0us); -} - -} // namespace quic diff --git a/quic/dsr/frontend/Scheduler.h b/quic/dsr/frontend/Scheduler.h deleted file mode 100644 index 4a57f9ec2..000000000 --- a/quic/dsr/frontend/Scheduler.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -namespace quic { -class DSRStreamFrameScheduler { - public: - explicit DSRStreamFrameScheduler(QuicServerConnectionState& conn); - - [[nodiscard]] bool hasPendingData() const; - - struct SchedulingResult { - bool writeSuccess{false}; - DSRPacketizationRequestSender* sender{nullptr}; - - explicit SchedulingResult( - bool written, - DSRPacketizationRequestSender* senderIn) - : writeSuccess(written), sender(senderIn) {} - - SchedulingResult() : writeSuccess(false), sender(nullptr) {} - }; - - // Write a single stream's data into builder. - [[nodiscard]] quic::Expected writeStream( - DSRPacketBuilderBase& builder); - - private: - void enrichInstruction( - SendInstruction::Builder& builder, - const QuicStreamState& stream); - SchedulingResult enrichAndAddSendInstruction( - uint32_t, - SchedulingResult, - DSRPacketBuilderBase&, - SendInstruction::Builder&, - const deprecated::PriorityQueue&, - const deprecated::PriorityQueue::LevelItr&, - QuicStreamState&); - - SchedulingResult enrichAndAddSendInstruction( - uint32_t, - SchedulingResult, - DSRPacketBuilderBase&, - SendInstruction::Builder&, - const PriorityQueue&, - QuicStreamState&); - - quic::Expected - writeStreamImpl( - DSRPacketBuilderBase& builder, - const deprecated::PriorityQueue&); - quic::Expected - writeStreamImpl(DSRPacketBuilderBase& builder, PriorityQueue&); - - private: - QuicServerConnectionState& conn_; - bool nextStreamNonDsr_{false}; -}; -} // namespace quic diff --git a/quic/dsr/frontend/WriteCodec.cpp b/quic/dsr/frontend/WriteCodec.cpp deleted file mode 100644 index 4b497703d..000000000 --- a/quic/dsr/frontend/WriteCodec.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -namespace quic { - -quic::Expected writeDSRStreamFrame( - DSRPacketBuilderBase& packetBuilder, - SendInstruction::Builder& instructionBuilder, - StreamId id, - uint64_t offset, - uint64_t writeBufferLen, - uint64_t flowControlLen, - bool fin, - uint64_t bufMetaStartingOffset) { - if (packetBuilder.remainingSpace() == 0) { - return 0; - } - if (writeBufferLen == 0 && !fin) { - return quic::make_unexpected(QuicError( - TransportErrorCode::INTERNAL_ERROR, - "No data or fin supplied when writing stream.")); - } - - QuicInteger idInt(id); - auto idIntSize = idInt.getSize(); - if (idIntSize.hasError()) { - return quic::make_unexpected(idIntSize.error()); - } - uint64_t headerSize = sizeof(uint8_t) + idIntSize.value(); - if (packetBuilder.remainingSpace() < headerSize) { - VLOG(4) << "No space in packet for stream header. stream=" << id - << " limit=" << packetBuilder.remainingSpace(); - return 0; - } - - QuicInteger offsetInt(offset); - if (offset != 0) { - auto offsetIntSize = offsetInt.getSize(); - if (offsetIntSize.hasError()) { - return quic::make_unexpected(offsetIntSize.error()); - } - headerSize += offsetIntSize.value(); - } - instructionBuilder.setStreamOffset(offset); - - uint64_t dataLen = std::min(writeBufferLen, flowControlLen); - dataLen = std::min(dataLen, packetBuilder.remainingSpace() - headerSize); - bool shouldSetFin = fin && dataLen == writeBufferLen; - if (dataLen == 0 && !shouldSetFin) { - return 0; - } - if (packetBuilder.remainingSpace() < headerSize) { - VLOG(4) << "No space in packet for stream header. stream=" << id - << " limit=" << packetBuilder.remainingSpace(); - return 0; - } - DCHECK(dataLen + headerSize <= packetBuilder.remainingSpace()); - instructionBuilder.setLength(dataLen); - instructionBuilder.setFin(shouldSetFin); - instructionBuilder.setBufMetaStartingOffset(bufMetaStartingOffset); - return dataLen + headerSize; -} -} // namespace quic diff --git a/quic/dsr/frontend/WriteCodec.h b/quic/dsr/frontend/WriteCodec.h deleted file mode 100644 index f08458ba6..000000000 --- a/quic/dsr/frontend/WriteCodec.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -namespace quic { -[[nodiscard]] quic::Expected writeDSRStreamFrame( - DSRPacketBuilderBase& packetBuilder, - SendInstruction::Builder& instructionBuilder, - StreamId id, - uint64_t offset, - uint64_t writeBufferLen, - uint64_t flowControlLen, - bool fin, - uint64_t bufMetaStartingOffset); - -} // namespace quic diff --git a/quic/dsr/frontend/WriteFunctions.cpp b/quic/dsr/frontend/WriteFunctions.cpp deleted file mode 100644 index efd0137ff..000000000 --- a/quic/dsr/frontend/WriteFunctions.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -namespace quic { -quic::Expected writePacketizationRequest( - QuicServerConnectionState& connection, - const ConnectionId& dstCid, - size_t packetLimit, - const Aead& aead, - TimePoint writeLoopBeginTime) { - DSRStreamFrameScheduler scheduler(connection); - uint64_t packetCounter = 0; - folly::F14FastSet senders; - SCOPE_EXIT { - for (auto sender : senders) { - if (connection.qLogger) { - connection.qLogger->addTransportStateUpdate("DSR flushing sender"); - } - sender->flush(); - } - }; - if (!writeLoopTimeLimit(writeLoopBeginTime, connection)) { - return packetCounter; - } - while (scheduler.hasPendingData() && packetCounter < packetLimit && - (packetCounter < connection.transportSettings.maxBatchSize || - writeLoopTimeLimit(writeLoopBeginTime, connection))) { - auto packetNum = getNextPacketNum(connection, PacketNumberSpace::AppData); - ShortHeader header(ProtectionType::KeyPhaseZero, dstCid, packetNum); - auto writableBytes = std::min( - connection.udpSendPacketLen, - congestionControlWritableBytes(connection)); - uint64_t cipherOverhead = aead.getCipherOverhead(); - if (writableBytes < cipherOverhead) { - writableBytes = 0; - } else { - writableBytes -= cipherOverhead; - } - - DSRPacketBuilder packetBuilder( - writableBytes, - std::move(header), - getAckState(connection, PacketNumberSpace::AppData) - .largestAckedByPeer.value_or(0)); - auto schedulerResult = scheduler.writeStream(packetBuilder); - if (schedulerResult.hasError()) { - return quic::make_unexpected(schedulerResult.error()); - } - if (!schedulerResult->writeSuccess) { - /** - * Scheduling can fail when we: - * (1) run out of flow control - * (2) there is actually no DSR stream to write - we shouldn't come here - * in the first place though. - * (3) Packet is no space left - e.g., due to CC - * (4) Error in write codec - Can that happen? - * - * At least for (1) and (3), we should flush the sender. - */ - if (schedulerResult->sender) { - senders.insert(schedulerResult->sender); - } - return packetCounter; - } - CHECK(schedulerResult->sender); - auto packet = std::move(packetBuilder).buildPacket(); - // The contract is that if scheduler can schedule, builder has to be able to - // build. - CHECK_GT(packet.encodedSize, 0u); - bool instructionAddError = false; - for (const auto& instruction : packet.sendInstructions) { - if (!schedulerResult->sender->addSendInstruction(instruction)) { - instructionAddError = true; - break; - } - } - - // Similar to the regular write case, if we build, we update connection - // states. The connection states are changed already no matter the result - // of addSendInstruction() call. - auto& currentPath = - *connection.pathManager->getPath(connection.currentPathId); - auto updateResult = updateConnection( - connection, - currentPath, - std::nullopt /* Packet Event */, - packet.packet, - Clock::now(), - packet.encodedSize + cipherOverhead, - // TODO: (yangchi) Figure out how to calculate the - // packet.encodedBodySize for the DSR case. For now, it's not being - // used, so setting it to 0 - 0, - true /* isDSRPacket */); - - if (updateResult.hasError()) { - return quic::make_unexpected(updateResult.error()); - } - connection.dsrPacketCount++; - - if (instructionAddError) { - // TODO: Support empty write loop detection - senders.insert(schedulerResult->sender); - return packetCounter; - } - ++packetCounter; - senders.insert(schedulerResult->sender); - } - return packetCounter; -} - -} // namespace quic diff --git a/quic/dsr/frontend/WriteFunctions.h b/quic/dsr/frontend/WriteFunctions.h deleted file mode 100644 index fa0c8ed93..000000000 --- a/quic/dsr/frontend/WriteFunctions.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace quic { -quic::Expected writePacketizationRequest( - QuicServerConnectionState& connection, - const ConnectionId& dstCid, - size_t packetLimit, - const Aead& aead, - TimePoint writeLoopBeginTime = Clock::now()); -} // namespace quic diff --git a/quic/dsr/frontend/test/BUCK b/quic/dsr/frontend/test/BUCK deleted file mode 100644 index 5fe2d6dd0..000000000 --- a/quic/dsr/frontend/test/BUCK +++ /dev/null @@ -1,79 +0,0 @@ -load("@fbcode//quic:defs.bzl", "mvfst_cpp_library", "mvfst_cpp_test") - -oncall("traffic_protocols") - -mvfst_cpp_library( - name = "mocks", - headers = [ - "Mocks.h", - ], - exported_deps = [ - "//folly/portability:gmock", - "//quic/dsr/frontend:packet_builder", - ], -) - -mvfst_cpp_test( - name = "write_codec_test", - srcs = [ - "WriteCodecTest.cpp", - ], - deps = [ - ":mocks", - "//folly/portability:gtest", - "//quic:constants", - "//quic/common/test:test_utils", - "//quic/dsr/frontend:write_codec", - "//quic/dsr/test:test_common", - "//quic/fizz/server/handshake:fizz_server_handshake", - "//quic/handshake/test:mocks", - "//quic/server/state:server", - ], -) - -mvfst_cpp_test( - name = "packet_builder_test", - srcs = [ - "PacketBuilderTest.cpp", - ], - deps = [ - "//folly/portability:gtest", - "//quic/common/test:test_utils", - "//quic/dsr:types", - "//quic/dsr/frontend:packet_builder", - "//quic/dsr/test:test_common", - "//quic/fizz/server/handshake:fizz_server_handshake", - "//quic/handshake/test:mocks", - "//quic/server/state:server", - ], -) - -mvfst_cpp_test( - name = "scheduler_test", - srcs = [ - "SchedulerTest.cpp", - ], - deps = [ - ":mocks", - "//folly/portability:gtest", - "//quic/dsr/frontend:scheduler", - "//quic/dsr/test:mocks", - "//quic/dsr/test:test_common", - "//quic/fizz/server/handshake:fizz_server_handshake", - "//quic/server/state:server", - ], -) - -mvfst_cpp_test( - name = "write_functions_test", - srcs = [ - "WriteFunctionsTest.cpp", - ], - deps = [ - "//folly/portability:gtest", - "//quic/dsr/frontend:write_functions", - "//quic/dsr/test:test_common", - "//quic/priority:http_priority_queue", - "//quic/state/test:mocks", - ], -) diff --git a/quic/dsr/frontend/test/Mocks.h b/quic/dsr/frontend/test/Mocks.h deleted file mode 100644 index 109d3a6d0..000000000 --- a/quic/dsr/frontend/test/Mocks.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -namespace quic::test { - -class MockDSRPacketBuilder : public DSRPacketBuilderBase { - public: - MOCK_METHOD(size_t, remainingSpaceNonConst, (), (noexcept)); - - size_t remainingSpace() const noexcept override { - return const_cast(*this).remainingSpaceNonConst(); - } - - MOCK_METHOD( - void, - addSendInstruction, - (SendInstruction&&, uint32_t, uint64_t)); -}; - -} // namespace quic::test diff --git a/quic/dsr/frontend/test/PacketBuilderTest.cpp b/quic/dsr/frontend/test/PacketBuilderTest.cpp deleted file mode 100644 index e2822ea0b..000000000 --- a/quic/dsr/frontend/test/PacketBuilderTest.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include - -namespace quic::test { - -bool operator==( - const SendInstruction& instruction, - const WriteStreamFrame& frame) { - return instruction.streamId == frame.streamId && - instruction.streamOffset == frame.offset && - instruction.len == frame.len && instruction.fin == frame.fin; -} - -bool operator==( - const WriteStreamFrame& frame, - const SendInstruction& instruction) { - return instruction == frame; -} - -class PacketBuilderTest : public DSRCommonTestFixture { - public: - PacketBuilderTest() - : cid(getTestConnectionId(0)), - header(ProtectionType::KeyPhaseZero, cid) {} - - protected: - ConnectionId cid; - ShortHeader header; -}; - -TEST_F(PacketBuilderTest, SimpleBuild) { - StreamId id = 0; - uint64_t offset = 1; - uint64_t length = 1000; - bool fin = true; - uint64_t bufMetaStartingOffset = 333; - SendInstruction::Builder siBuilder(conn_, id); - siBuilder.setStreamOffset(offset); - siBuilder.setLength(length); - siBuilder.setFin(fin); - siBuilder.setBufMetaStartingOffset(bufMetaStartingOffset); - auto sendInstruction = siBuilder.build(); - DSRPacketBuilder packetBuilder(kDefaultUDPSendPacketLen, header, 0); - uint32_t streamEncodedSize = 1003; - SendInstruction instructionCopy(sendInstruction); - packetBuilder.addSendInstruction( - std::move(sendInstruction), streamEncodedSize, 5); - auto packet = std::move(packetBuilder).buildPacket(); - const auto& writePacket = packet.packet; - const auto& si = packet.sendInstructions.front(); - EXPECT_EQ(1, writePacket.frames.size()); - const auto& writeStreamFrame = - *writePacket.frames.front().asWriteStreamFrame(); - EXPECT_TRUE(writeStreamFrame == instructionCopy); - EXPECT_TRUE(writeStreamFrame == si); - EXPECT_TRUE(writeStreamFrame.fromBufMeta); - EXPECT_EQ(writeStreamFrame.streamPacketIdx, 5); - EXPECT_GT(packet.encodedSize, streamEncodedSize); -} - -TEST_F(PacketBuilderTest, SizeTooSmall) { - DSRPacketBuilder packetBuilder(5, header, 0); - EXPECT_EQ(0, packetBuilder.remainingSpace()); -} - -TEST_F(PacketBuilderTest, WriteTwoInstructions) { - DSRPacketBuilder packetBuilder(kDefaultUDPSendPacketLen, header, 0); - - StreamId id = 0; - packetBuilder.addSendInstruction( - SendInstruction::Builder(conn_, id) - .setStreamOffset(0) - .setLength(100) - .setFin(false) - .setBufMetaStartingOffset(333) - .build(), - 110, - 5); - packetBuilder.addSendInstruction( - SendInstruction::Builder(conn_, id) - .setStreamOffset(100) - .setLength(100) - .setFin(true) - .setBufMetaStartingOffset(333) - .build(), - 110, - 6); - auto packet = std::move(packetBuilder).buildPacket(); - const auto& writePacket = packet.packet; - EXPECT_EQ(2, packet.sendInstructions.size()); - EXPECT_EQ(2, writePacket.frames.size()); - WriteStreamFrame expectedFirstFrame(id, 0, 100, false, true, std::nullopt, 5); - WriteStreamFrame expectedSecondFrame( - id, 100, 100, true, true, std::nullopt, 6); - EXPECT_EQ(expectedFirstFrame, *writePacket.frames[0].asWriteStreamFrame()); - EXPECT_EQ(expectedSecondFrame, *writePacket.frames[1].asWriteStreamFrame()); - EXPECT_TRUE(expectedFirstFrame == packet.sendInstructions[0]); - EXPECT_TRUE(expectedSecondFrame == packet.sendInstructions[1]); -} - -} // namespace quic::test diff --git a/quic/dsr/frontend/test/SchedulerTest.cpp b/quic/dsr/frontend/test/SchedulerTest.cpp deleted file mode 100644 index 837bbb93e..000000000 --- a/quic/dsr/frontend/test/SchedulerTest.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include - -using namespace testing; - -namespace quic::test { - -class SchedulerTest : public DSRCommonTestFixture { - public: - SchedulerTest() { - prepareFlowControlAndStreamLimit(); - } - - protected: - MockDSRPacketBuilder builder_; -}; - -TEST_F(SchedulerTest, ScheduleStream) { - DSRStreamFrameScheduler scheduler(conn_); - EXPECT_FALSE(scheduler.hasPendingData()); - auto stream = *conn_.streamManager->createNextBidirectionalStream(); - stream->flowControlState.peerAdvertisedMaxOffset = 200; - stream->dsrSender = std::make_unique(); - ASSERT_FALSE(writeDataToQuicStream( - *stream, folly::IOBuf::copyBuffer("New York Bagles"), false) - .hasError()); - BufferMeta bufMeta(200); - ASSERT_FALSE(writeBufMetaToQuicStream(*stream, bufMeta, true).hasError()); - auto expectedBufMetaOffset = stream->writeBufMeta.offset; - ASSERT_TRUE( - conn_.streamManager->hasWritable() && - conn_.streamManager->hasDSRWritable()); - EXPECT_TRUE(scheduler.hasPendingData()); - EXPECT_CALL(builder_, remainingSpaceNonConst()).WillRepeatedly(Return(1000)); - uint64_t writtenLength = 0; - EXPECT_CALL(builder_, addSendInstruction(_, _, _)) - .WillOnce(Invoke([&](SendInstruction&& instruction, uint32_t, uint64_t) { - EXPECT_EQ(stream->id, (size_t)instruction.streamId); - EXPECT_EQ(expectedBufMetaOffset, instruction.streamOffset); - EXPECT_GT(200, instruction.len); - writtenLength = instruction.len; - EXPECT_FALSE(instruction.fin); - })); - auto result = scheduler.writeStream(builder_); - ASSERT_FALSE(result.hasError()); - EXPECT_TRUE(result.value().writeSuccess); - - auto writtenMeta = stream->writeBufMeta.split(writtenLength); - auto nextExpectedOffset = stream->writeBufMeta.offset; - EXPECT_GT(stream->writeBufMeta.length, 0); - stream->retransmissionBufMetas.emplace( - std::piecewise_construct, - std::forward_as_tuple(expectedBufMetaOffset), - std::forward_as_tuple(writtenMeta)); - // This is now flow control blocked: - EXPECT_FALSE(stream->hasWritableBufMeta()); - conn_.streamManager->updateWritableStreams(*stream); - EXPECT_FALSE(conn_.streamManager->hasDSRWritable()); - EXPECT_TRUE(conn_.streamManager->writableDSRStreams().empty()); - - stream->flowControlState.peerAdvertisedMaxOffset = 500; - conn_.streamManager->updateWritableStreams(*stream); - EXPECT_TRUE(conn_.streamManager->hasDSRWritable()); - EXPECT_FALSE(conn_.streamManager->writableDSRStreams().empty()); - EXPECT_CALL(builder_, addSendInstruction(_, _, _)) - .WillOnce(Invoke([&](SendInstruction&& instruction, uint32_t, uint64_t) { - EXPECT_EQ(stream->id, (size_t)instruction.streamId); - EXPECT_EQ(nextExpectedOffset, instruction.streamOffset); - EXPECT_GT(instruction.len, 0); - writtenLength = instruction.len; - EXPECT_TRUE(instruction.fin); - })); - result = scheduler.writeStream(builder_); - ASSERT_FALSE(result.hasError()); - EXPECT_TRUE(result.value().writeSuccess); - - auto nextWrittenMeta = stream->writeBufMeta.split(writtenLength); - EXPECT_EQ(stream->writeBufMeta.length, 0); - stream->writeBufMeta.offset++; - stream->retransmissionBufMetas.emplace( - std::piecewise_construct, - std::forward_as_tuple(nextExpectedOffset), - std::forward_as_tuple(nextWrittenMeta)); - EXPECT_FALSE(stream->hasWritableBufMeta()); - conn_.streamManager->updateWritableStreams(*stream); - EXPECT_FALSE(conn_.streamManager->hasDSRWritable()); - EXPECT_TRUE(conn_.streamManager->writableDSRStreams().empty()); -} - -} // namespace quic::test diff --git a/quic/dsr/frontend/test/WriteCodecTest.cpp b/quic/dsr/frontend/test/WriteCodecTest.cpp deleted file mode 100644 index 7db799f0c..000000000 --- a/quic/dsr/frontend/test/WriteCodecTest.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include -#include -#include -#include -#include -#include - -using namespace testing; - -namespace quic::test { - -class WriteCodecTest : public DSRCommonTestFixture { - public: - void SetUp() override { - EXPECT_CALL(builder_, remainingSpaceNonConst()) - .WillRepeatedly(Invoke([&]() { return packetSize_; })); - prepareFlowControlAndStreamLimit(); - } - - protected: - SendInstruction::Builder createBuilder() { - auto stream = *conn_.streamManager->createNextBidirectionalStream(); - SendInstruction::Builder builder(conn_, stream->id); - return builder; - } - - protected: - size_t packetSize_{kDefaultUDPSendPacketLen}; - MockDSRPacketBuilder builder_; -}; - -TEST_F(WriteCodecTest, NoPacketSize) { - packetSize_ = 0; - auto instructionBuilder = createBuilder(); - auto result = writeDSRStreamFrame( - builder_, instructionBuilder, 0, 0, 100, 100, true, 3); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(0, result.value()); -} - -TEST_F(WriteCodecTest, TooSmallPacketSize) { - packetSize_ = 1; - auto instructionBuilder = createBuilder(); - auto result = writeDSRStreamFrame( - builder_, instructionBuilder, 0, 0, 100, 100, true, 1); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(0, result.value()); -} - -TEST_F(WriteCodecTest, RegularWrite) { - StreamId stream = 1; - uint64_t offset = 65535; - bool fin = false; - uint64_t dataLen = 1000; - uint64_t flowControlLen = 1000; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - auto sendInstruction = instructionBuilder.build(); - EXPECT_GT(result.value(), 0); - EXPECT_EQ(stream, sendInstruction.streamId); - EXPECT_EQ(offset, sendInstruction.streamOffset); - EXPECT_EQ(dataLen, sendInstruction.len); - EXPECT_EQ(fin, sendInstruction.fin); - EXPECT_EQ(bufMetaStartingOffset, sendInstruction.bufMetaStartingOffset); -} - -TEST_F(WriteCodecTest, PacketSizeLimit) { - StreamId stream = 1; - uint64_t offset = 65535; - bool fin = false; - uint64_t dataLen = 1000 * 1000; - uint64_t flowControlLen = 1000 * 1000; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - auto sendInstruction = instructionBuilder.build(); - EXPECT_GT(result.value(), 0); - EXPECT_EQ(stream, sendInstruction.streamId); - EXPECT_EQ(offset, sendInstruction.streamOffset); - EXPECT_GT(dataLen, sendInstruction.len); - EXPECT_EQ(fin, sendInstruction.fin); - EXPECT_EQ(bufMetaStartingOffset, sendInstruction.bufMetaStartingOffset); -} - -TEST_F(WriteCodecTest, FlowControlLimit) { - StreamId stream = 1; - uint64_t offset = 65535; - bool fin = false; - uint64_t dataLen = 1000 * 1000; - uint64_t flowControlLen = 500; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - auto sendInstruction = instructionBuilder.build(); - EXPECT_GT(result.value(), 0); - EXPECT_EQ(stream, sendInstruction.streamId); - EXPECT_EQ(offset, sendInstruction.streamOffset); - EXPECT_EQ(flowControlLen, sendInstruction.len); - EXPECT_EQ(fin, sendInstruction.fin); - EXPECT_EQ(bufMetaStartingOffset, sendInstruction.bufMetaStartingOffset); -} - -TEST_F(WriteCodecTest, NoSpaceForData) { - StreamId stream = 1; - uint64_t offset = 1; - bool fin = false; - uint64_t dataLen = 1000; - uint64_t flowControlLen = 1000; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - packetSize_ = 3; - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(0, result.value()); -} - -TEST_F(WriteCodecTest, CanHaveOneByteData) { - StreamId stream = 1; - uint64_t offset = 1; - bool fin = false; - uint64_t dataLen = 10; - uint64_t flowControlLen = 10; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - packetSize_ = 4; - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - auto sendInstruction = instructionBuilder.build(); - EXPECT_GT(result.value(), 0); - EXPECT_EQ(stream, sendInstruction.streamId); - EXPECT_EQ(offset, sendInstruction.streamOffset); - EXPECT_EQ(1, sendInstruction.len); - EXPECT_EQ(fin, sendInstruction.fin); - EXPECT_EQ(bufMetaStartingOffset, sendInstruction.bufMetaStartingOffset); -} - -TEST_F(WriteCodecTest, PacketSpaceEqStreamHeaderSize) { - StreamId stream = 1; - uint64_t offset = 0; - bool fin = true; - uint64_t dataLen = 10; - uint64_t flowControlLen = 10; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - packetSize_ = 2; - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(0, result.value()); -} - -TEST_F(WriteCodecTest, PacketSpaceEqStreamHeaderSizeWithFIN) { - StreamId stream = 1; - uint64_t offset = 0; - bool fin = true; - uint64_t dataLen = 0; - uint64_t flowControlLen = 10; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - packetSize_ = 2; - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - auto sendInstruction = instructionBuilder.build(); - EXPECT_GT(result.value(), 0); - EXPECT_EQ(stream, sendInstruction.streamId); - EXPECT_EQ(offset, sendInstruction.streamOffset); - EXPECT_EQ(0, sendInstruction.len); - EXPECT_TRUE(sendInstruction.fin); - EXPECT_EQ(bufMetaStartingOffset, sendInstruction.bufMetaStartingOffset); -} - -TEST_F(WriteCodecTest, WriteFIN) { - StreamId stream = 1; - uint64_t offset = 1; - bool fin = true; - uint64_t dataLen = 10; - uint64_t flowControlLen = 10; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - auto sendInstruction = instructionBuilder.build(); - EXPECT_GT(result.value(), 0); - EXPECT_EQ(stream, sendInstruction.streamId); - EXPECT_EQ(offset, sendInstruction.streamOffset); - EXPECT_EQ(10, sendInstruction.len); - EXPECT_TRUE(sendInstruction.fin); - EXPECT_EQ(bufMetaStartingOffset, sendInstruction.bufMetaStartingOffset); -} - -TEST_F(WriteCodecTest, FINWithoutData) { - StreamId stream = 1; - uint64_t offset = 1; - bool fin = true; - uint64_t dataLen = 0; - uint64_t flowControlLen = 10; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - auto result = writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset); - ASSERT_FALSE(result.hasError()); - auto sendInstruction = instructionBuilder.build(); - EXPECT_GT(result.value(), 0); - EXPECT_EQ(stream, sendInstruction.streamId); - EXPECT_EQ(offset, sendInstruction.streamOffset); - EXPECT_EQ(0, sendInstruction.len); - EXPECT_TRUE(sendInstruction.fin); - EXPECT_EQ(bufMetaStartingOffset, sendInstruction.bufMetaStartingOffset); -} - -TEST_F(WriteCodecTest, NoFINNoData) { - StreamId stream = 1; - uint64_t offset = 1; - bool fin = false; - uint64_t dataLen = 0; - uint64_t flowControlLen = 10; - uint64_t bufMetaStartingOffset = 333; - auto instructionBuilder = createBuilder(); - EXPECT_TRUE(writeDSRStreamFrame( - builder_, - instructionBuilder, - stream, - offset, - dataLen, - flowControlLen, - fin, - bufMetaStartingOffset) - .hasError()); -} -} // namespace quic::test diff --git a/quic/dsr/frontend/test/WriteFunctionsTest.cpp b/quic/dsr/frontend/test/WriteFunctionsTest.cpp deleted file mode 100644 index 32836f375..000000000 --- a/quic/dsr/frontend/test/WriteFunctionsTest.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include - -using namespace testing; - -namespace quic::test { - -class WriteFunctionsTest : public DSRCommonTestFixture { - void SetUp() override { - aead_ = createNoOpAead(16); - } -}; - -TEST_F(WriteFunctionsTest, SchedulerNoData) { - prepareFlowControlAndStreamLimit(); - auto cid = getTestConnectionId(); - size_t packetLimit = 20; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(0, result.value()); -} - -TEST_F(WriteFunctionsTest, CwndBlockd) { - prepareOneStream(); - auto mockCongestionController = - std::make_unique>(); - auto rawCongestionController = mockCongestionController.get(); - conn_.congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, getWritableBytes()) - .WillRepeatedly(Return(0)); - auto cid = getTestConnectionId(); - size_t packetLimit = 20; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(0, result.value()); -} - -TEST_F(WriteFunctionsTest, FlowControlBlockded) { - prepareOneStream(); - auto mockCongestionController = - std::make_unique>(); - auto rawCongestionController = mockCongestionController.get(); - conn_.congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, getWritableBytes()) - .WillRepeatedly(Return(0)); - auto cid = getTestConnectionId(); - size_t packetLimit = 20; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(0, result.value()); -} - -TEST_F(WriteFunctionsTest, WriteOne) { - prepareFlowControlAndStreamLimit(); - auto streamId = prepareOneStream(); - auto cid = getTestConnectionId(); - auto stream = conn_.streamManager->findStream(streamId); - auto currentBufMetaOffset = stream->writeBufMeta.offset; - size_t packetLimit = 20; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(1, result.value()); - EXPECT_GT(stream->writeBufMeta.offset, currentBufMetaOffset); - EXPECT_EQ(1, stream->retransmissionBufMetas.size()); - EXPECT_EQ(1, countInstructions(streamId)); - EXPECT_EQ(1, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); -} - -TEST_F(WriteFunctionsTest, WriteLoopTimeLimit) { - prepareFlowControlAndStreamLimit(); - auto streamId = prepareOneStream(3000); - auto cid = getTestConnectionId(); - auto stream = conn_.streamManager->findStream(streamId); - // Pretend we sent the non DSR data - stream->ackedIntervals.insert(0, stream->writeBuffer.chainLength() - 1); - stream->currentWriteOffset = stream->writeBuffer.chainLength(); - ChainedByteRangeHead(std::move(stream->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream); - auto currentBufMetaOffset = stream->writeBufMeta.offset; - size_t packetLimit = 2; - conn_.lossState.srtt = 100ms; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(2, result.value()); - EXPECT_GT(stream->writeBufMeta.offset, currentBufMetaOffset); - EXPECT_EQ(2, stream->retransmissionBufMetas.size()); - EXPECT_EQ(2, countInstructions(streamId)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); - - // Fake the time so it's in the past. - auto writeLoopBeginTime = Clock::now() - 200ms; - result = writePacketizationRequest( - conn_, cid, packetLimit, *aead_, writeLoopBeginTime); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(0, result.value()); - EXPECT_EQ(2, stream->retransmissionBufMetas.size()); - EXPECT_EQ(2, countInstructions(streamId)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); -} - -TEST_F(WriteFunctionsTest, WriteLoopTimeLimitNoLimit) { - prepareFlowControlAndStreamLimit(); - auto streamId = prepareOneStream(3000); - auto cid = getTestConnectionId(); - auto stream = conn_.streamManager->findStream(streamId); - // Pretend we sent the non DSR data - stream->ackedIntervals.insert(0, stream->writeBuffer.chainLength() - 1); - stream->currentWriteOffset = stream->writeBuffer.chainLength(); - ChainedByteRangeHead(std::move(stream->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream); - auto currentBufMetaOffset = stream->writeBufMeta.offset; - size_t packetLimit = 2; - conn_.lossState.srtt = 100ms; - conn_.transportSettings.writeLimitRttFraction = 0; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(2, result.value()); - EXPECT_GT(stream->writeBufMeta.offset, currentBufMetaOffset); - EXPECT_EQ(2, stream->retransmissionBufMetas.size()); - EXPECT_EQ(2, countInstructions(streamId)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); - - // Fake the time so it's in the past. - auto writeLoopBeginTime = Clock::now() - 200ms; - result = writePacketizationRequest( - conn_, cid, packetLimit, *aead_, writeLoopBeginTime); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(1, result.value()); - EXPECT_EQ(3, stream->retransmissionBufMetas.size()); - EXPECT_EQ(3, countInstructions(streamId)); - EXPECT_EQ(3, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); -} - -TEST_F(WriteFunctionsTest, WriteTwoInstructions) { - prepareFlowControlAndStreamLimit(); - auto streamId = prepareOneStream(2000); - auto stream = conn_.streamManager->findStream(streamId); - // Pretend we sent the non DSR data - stream->ackedIntervals.insert(0, stream->writeBuffer.chainLength() - 1); - stream->currentWriteOffset = stream->writeBuffer.chainLength(); - ChainedByteRangeHead(std::move(stream->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream); - auto cid = getTestConnectionId(); - size_t packetLimit = 20; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(2, result.value()); - EXPECT_EQ(2, stream->retransmissionBufMetas.size()); - EXPECT_EQ(2, countInstructions(streamId)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); - // Check the packet size is full. - EXPECT_EQ( - conn_.outstandings.packets[0].metadata.encodedSize, - conn_.udpSendPacketLen); -} - -TEST_F(WriteFunctionsTest, PacketLimit) { - prepareFlowControlAndStreamLimit(); - auto streamId = prepareOneStream(2000 * 100); - auto stream = conn_.streamManager->findStream(streamId); - // Pretend we sent the non DSR data - stream->ackedIntervals.insert(0, stream->writeBuffer.chainLength() - 1); - stream->currentWriteOffset = stream->writeBuffer.chainLength(); - ChainedByteRangeHead(std::move(stream->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream); - auto mockCongestionController = - std::make_unique>(); - auto rawCongestionController = mockCongestionController.get(); - conn_.congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, getWritableBytes()) - .WillRepeatedly(Return(1000)); - auto cid = getTestConnectionId(); - size_t packetLimit = 20; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(20, result.value()); - EXPECT_EQ(20, stream->retransmissionBufMetas.size()); - EXPECT_EQ(20, countInstructions(streamId)); - EXPECT_EQ(20, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); - // All packets should be full. - for (auto& outstanding : conn_.outstandings.packets) { - EXPECT_EQ(outstanding.metadata.encodedSize, conn_.udpSendPacketLen); - } -} - -TEST_F(WriteFunctionsTest, WriteTwoStreams) { - prepareFlowControlAndStreamLimit(); - auto streamId1 = prepareOneStream(1000); - auto streamId2 = prepareOneStream(1000); - auto stream1 = conn_.streamManager->findStream(streamId1); - auto stream2 = conn_.streamManager->findStream(streamId2); - // Pretend we sent the non DSR data on second stream - stream2->ackedIntervals.insert(0, stream2->writeBuffer.chainLength() - 1); - stream2->currentWriteOffset = stream2->writeBuffer.chainLength(); - ChainedByteRangeHead( - std::move(stream2->pendingWrites)); // Destruct the pendingWrites - conn_.streamManager->updateWritableStreams(*stream2); - auto cid = getTestConnectionId(); - size_t packetLimit = 20; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(2, result.value()); - EXPECT_EQ(1, stream1->retransmissionBufMetas.size()); - EXPECT_EQ(1, stream2->retransmissionBufMetas.size()); - EXPECT_EQ(1, countInstructions(streamId1)); - EXPECT_EQ(1, countInstructions(streamId2)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); -} - -TEST_F(WriteFunctionsTest, WriteThreeStreamsNonDsrAndDsr) { - prepareFlowControlAndStreamLimit(); - auto streamId1 = prepareOneStream(1000); - auto streamId2 = prepareOneStream(1000); - auto streamId3 = prepareOneStream(1000); - auto stream1 = conn_.streamManager->findStream(streamId1); - auto stream2 = conn_.streamManager->findStream(streamId2); - auto stream3 = conn_.streamManager->findStream(streamId3); - auto cid = getTestConnectionId(); - size_t packetLimit = 20; - // First loop only write a single packet because it will find there's non-DSR - // data to write on the next stream. - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(1, result.value()); - // Pretend we sent the non DSR data for last stream - stream3->ackedIntervals.insert(0, stream3->writeBuffer.chainLength() - 1); - stream3->currentWriteOffset = stream3->writeBuffer.chainLength(); - ChainedByteRangeHead(std::move(stream3->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream3); - result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(2, result.value()); - EXPECT_EQ(1, stream1->retransmissionBufMetas.size()); - EXPECT_EQ(1, stream2->retransmissionBufMetas.size()); - EXPECT_EQ(1, stream3->retransmissionBufMetas.size()); - EXPECT_EQ(1, countInstructions(streamId1)); - EXPECT_EQ(1, countInstructions(streamId2)); - EXPECT_EQ(1, countInstructions(streamId3)); - EXPECT_EQ(3, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); -} - -TEST_F(WriteFunctionsTest, WriteTwoStreamsNonIncremental) { - prepareFlowControlAndStreamLimit(); - auto streamId1 = prepareOneStream(2000); - auto streamId2 = prepareOneStream(1000); - auto stream1 = conn_.streamManager->findStream(streamId1); - auto stream2 = conn_.streamManager->findStream(streamId2); - conn_.streamManager->setStreamPriority( - streamId1, HTTPPriorityQueue::Priority{3, false}); - conn_.streamManager->setStreamPriority( - streamId2, HTTPPriorityQueue::Priority{3, false}); - // Pretend we sent the non DSR data on first stream - stream1->ackedIntervals.insert(0, stream1->writeBuffer.chainLength() - 1); - stream1->currentWriteOffset = stream1->writeBuffer.chainLength(); - ChainedByteRangeHead(std::move(stream1->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream1); - auto cid = getTestConnectionId(); - size_t packetLimit = 2; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(2, result.value()); - EXPECT_EQ(2, stream1->retransmissionBufMetas.size()); - EXPECT_EQ(0, stream2->retransmissionBufMetas.size()); - EXPECT_EQ(2, countInstructions(streamId1)); - EXPECT_EQ(0, countInstructions(streamId2)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); -} - -TEST_F(WriteFunctionsTest, WriteTwoStreamsIncremental) { - prepareFlowControlAndStreamLimit(); - auto streamId1 = prepareOneStream(2000); - auto streamId2 = prepareOneStream(1000); - auto stream1 = conn_.streamManager->findStream(streamId1); - auto stream2 = conn_.streamManager->findStream(streamId2); - conn_.streamManager->setStreamPriority( - streamId1, HTTPPriorityQueue::Priority{3, true}); - conn_.streamManager->setStreamPriority( - streamId2, HTTPPriorityQueue::Priority{3, true}); - // Pretend we sent the non DSR data on second stream - stream2->ackedIntervals.insert(0, stream2->writeBuffer.chainLength() - 1); - stream2->currentWriteOffset = stream2->writeBuffer.chainLength(); - ChainedByteRangeHead(std::move(stream2->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream2); - auto cid = getTestConnectionId(); - size_t packetLimit = 2; - auto result = writePacketizationRequest(conn_, cid, packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(2, result.value()); - EXPECT_EQ(1, stream1->retransmissionBufMetas.size()); - EXPECT_EQ(1, stream2->retransmissionBufMetas.size()); - EXPECT_EQ(1, countInstructions(streamId1)); - EXPECT_EQ(1, countInstructions(streamId2)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - EXPECT_TRUE(verifyAllOutstandingsAreDSR()); -} - -TEST_F(WriteFunctionsTest, LossAndFreshTwoInstructionsInTwoPackets) { - prepareFlowControlAndStreamLimit(); - auto streamId = prepareOneStream(1000); - auto stream = conn_.streamManager->findStream(streamId); - // Pretend we sent the non DSR data - stream->ackedIntervals.insert(0, stream->writeBuffer.chainLength() - 1); - stream->currentWriteOffset = stream->writeBuffer.chainLength(); - ChainedByteRangeHead(std::move(stream->pendingWrites)); - conn_.streamManager->updateWritableStreams(*stream); - auto bufMetaStartingOffset = stream->writeBufMeta.offset; - // Move part of the BufMetas to lossBufMetas - auto split = stream->writeBufMeta.split(500); - stream->lossBufMetas.push_back(split); - size_t packetLimit = 10; - auto result = writePacketizationRequest( - conn_, getTestConnectionId(), packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(2, result.value()); - EXPECT_EQ(2, countInstructions(streamId)); - EXPECT_EQ(2, conn_.outstandings.packets.size()); - auto& packet1 = conn_.outstandings.packets.front().packet; - auto& packet2 = conn_.outstandings.packets.back().packet; - EXPECT_EQ(1, packet1.frames.size()); - EXPECT_EQ(1, packet2.frames.size()); - WriteStreamFrame expectedFirstFrame( - streamId, bufMetaStartingOffset, 500, false, true, std::nullopt, 0); - WriteStreamFrame expectedSecondFrame( - streamId, 500 + bufMetaStartingOffset, 500, true, true, std::nullopt, 1); - EXPECT_EQ(expectedFirstFrame, *packet1.frames[0].asWriteStreamFrame()); - EXPECT_EQ(expectedSecondFrame, *packet2.frames[0].asWriteStreamFrame()); -} - -TEST_F( - WriteFunctionsTest, - LossAndFreshTwoInstructionsInTwoPacketsNoFlowControl) { - prepareFlowControlAndStreamLimit(); - auto streamId = prepareOneStream(1000); - auto stream = conn_.streamManager->findStream(streamId); - auto bufMetaStartingOffset = stream->writeBufMeta.offset; - // Move part of the BufMetas to lossBufMetas - auto split = stream->writeBufMeta.split(500); - stream->lossBufMetas.push_back(split); - conn_.streamManager->updateWritableStreams(*stream); - // Zero out conn flow control. - conn_.flowControlState.sumCurWriteOffset = - conn_.flowControlState.peerAdvertisedMaxOffset; - size_t packetLimit = 10; - // Should only write lost data - auto result = writePacketizationRequest( - conn_, getTestConnectionId(), packetLimit, *aead_); - ASSERT_FALSE(result.hasError()); - EXPECT_EQ(1, result.value()); - EXPECT_EQ(1, countInstructions(streamId)); - ASSERT_EQ(1, conn_.outstandings.packets.size()); - auto& packet1 = conn_.outstandings.packets.front().packet; - EXPECT_EQ(1, packet1.frames.size()); - WriteStreamFrame expectedFirstFrame( - streamId, bufMetaStartingOffset, 500, false, true); - EXPECT_EQ(expectedFirstFrame, *packet1.frames[0].asWriteStreamFrame()); -} - -} // namespace quic::test diff --git a/quic/dsr/test/BUCK b/quic/dsr/test/BUCK deleted file mode 100644 index 1bffccf93..000000000 --- a/quic/dsr/test/BUCK +++ /dev/null @@ -1,27 +0,0 @@ -load("@fbcode//quic:defs.bzl", "mvfst_cpp_library") - -oncall("traffic_protocols") - -mvfst_cpp_library( - name = "mocks", - headers = [ - "Mocks.h", - ], - exported_deps = [ - "//folly/portability:gmock", - "//quic/dsr:dsr_packetization_request_sender", - ], -) - -mvfst_cpp_library( - name = "test_common", - headers = ["TestCommon.h"], - exported_deps = [ - ":mocks", - "//folly/portability:gtest", - "//quic/common/test:test_utils", - "//quic/dsr/frontend:scheduler", - "//quic/fizz/server/handshake:fizz_server_handshake", - "//quic/server/state:server", - ], -) diff --git a/quic/dsr/test/CMakeLists.txt b/quic/dsr/test/CMakeLists.txt deleted file mode 100644 index 9edd2411b..000000000 --- a/quic/dsr/test/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -install(FILES Mocks.h DESTINATION include/quic/dsr/test) - -if(NOT BUILD_TESTS) - return() -endif() diff --git a/quic/dsr/test/Mocks.h b/quic/dsr/test/Mocks.h deleted file mode 100644 index e2b0e0508..000000000 --- a/quic/dsr/test/Mocks.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -namespace quic { -struct SendInstruction; -} - -namespace quic::test { - -class MockDSRPacketizationRequestSender : public DSRPacketizationRequestSender { - public: - MOCK_METHOD(bool, addSendInstruction, (const SendInstruction&)); - MOCK_METHOD(bool, flush, ()); - MOCK_METHOD(void, release, ()); -}; - -} // namespace quic::test diff --git a/quic/dsr/test/TestCommon.h b/quic/dsr/test/TestCommon.h deleted file mode 100644 index a289edcd8..000000000 --- a/quic/dsr/test/TestCommon.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include -#include - -namespace quic::test { - -class DSRCommonTestFixture : public testing::Test { - public: - DSRCommonTestFixture() - : conn_(FizzServerQuicHandshakeContext::Builder().build()), - scheduler_(conn_), - aead_(createNoOpAead()) { - conn_.clientConnectionId = getTestConnectionId(0); - conn_.serverConnectionId = getTestConnectionId(1); - auto mockHeaderCipher = std::make_unique(); - packetProtectionKey_ = getProtectionKey(); - EXPECT_CALL(*mockHeaderCipher, getKey()) - .WillRepeatedly(testing::ReturnRef(packetProtectionKey_)); - conn_.oneRttWriteHeaderCipher = std::move(mockHeaderCipher); - auto mockCipher = std::make_unique(); - EXPECT_CALL(*mockCipher, getKey()).WillRepeatedly(testing::Invoke([] { - return getQuicTestKey(); - })); - conn_.oneRttWriteCipher = std::move(mockCipher); - - serverHandshake_ = std::make_unique( - conn_, - FizzServerQuicHandshakeContext::Builder() - .setFizzServerContext(createServerCtx()) - .build()); - serverHandshake_->setCipherSuite(fizz::CipherSuite::TLS_AES_128_GCM_SHA256); - conn_.serverHandshakeLayer = serverHandshake_.get(); - conn_.handshakeLayer = std::move(serverHandshake_); - initializePathManagerState(conn_); - } - - protected: - void prepareFlowControlAndStreamLimit() { - conn_.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiLocal = - kDefaultStreamFlowControlWindow; - conn_.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote = - kDefaultStreamFlowControlWindow; - conn_.flowControlState.peerAdvertisedInitialMaxStreamOffsetUni = - kDefaultStreamFlowControlWindow; - conn_.flowControlState.peerAdvertisedMaxOffset = - kDefaultConnectionFlowControlWindow; - CHECK( - !conn_.streamManager - ->setMaxLocalBidirectionalStreams(kDefaultMaxStreamsBidirectional) - .hasError()); - CHECK(!conn_.streamManager - ->setMaxLocalUnidirectionalStreams( - kDefaultMaxStreamsUnidirectional) - .hasError()); - } - - StreamId prepareOneStream( - size_t bufMetaLength = 1000, - uint64_t peeMaxOffsetSimulated = std::numeric_limits::max()) { - CHECK( - !conn_.streamManager - ->setMaxLocalBidirectionalStreams(kDefaultMaxStreamsBidirectional) - .hasError()); - CHECK(!conn_.streamManager - ->setMaxLocalUnidirectionalStreams( - kDefaultMaxStreamsUnidirectional) - .hasError()); - auto id = conn_.streamManager->createNextBidirectionalStream().value()->id; - auto stream = conn_.streamManager->findStream(id); - stream->flowControlState.peerAdvertisedMaxOffset = peeMaxOffsetSimulated; - - auto sender = std::make_unique(); - ON_CALL(*sender, addSendInstruction(testing::_)) - .WillByDefault(testing::Invoke([&](const SendInstruction& instruction) { - pendingInstructions_.push_back(instruction); - auto streamId = instruction.streamId; - if (instructionCounter_.count(streamId) == 0) { - instructionCounter_[streamId] = 1; - } else { - instructionCounter_[streamId] += 1; - } - return true; - })); - ON_CALL(*sender, flush()).WillByDefault(testing::Return(true)); - stream->dsrSender = std::move(sender); - CHECK(!writeDataToQuicStream( - *stream, - folly::IOBuf::copyBuffer("MetroCard Customer Claims"), - false /* eof */) - .hasError()); - BufferMeta bufMeta(bufMetaLength); - CHECK( - !writeBufMetaToQuicStream(*stream, bufMeta, true /* eof */).hasError()); - return id; - } - - size_t countInstructions(StreamId streamId) { - if (instructionCounter_.count(streamId) == 0) { - return 0; - } - return instructionCounter_[streamId]; - } - - bool verifyAllOutstandingsAreDSR() const { - return std::all_of( - conn_.outstandings.packets.begin(), - conn_.outstandings.packets.end(), - [](const OutstandingPacketWrapper& packet) { - return packet.isDSRPacket; - }); - } - - protected: - QuicServerConnectionState conn_; - DSRStreamFrameScheduler scheduler_; - std::unique_ptr aead_; - std::unordered_map instructionCounter_; - std::vector pendingInstructions_; - BufPtr packetProtectionKey_; - std::unique_ptr serverHandshake_; -}; -} // namespace quic::test diff --git a/quic/flowcontrol/QuicFlowController.cpp b/quic/flowcontrol/QuicFlowController.cpp index df2549d65..b589b0b50 100644 --- a/quic/flowcontrol/QuicFlowController.cpp +++ b/quic/flowcontrol/QuicFlowController.cpp @@ -320,22 +320,12 @@ quic::Expected updateFlowControlOnResetStream( // This is the amount of pending data that we are "throwing away" if (stream.pendingWrites.chainLength() + stream.currentWriteOffset > *reliableSize) { - // Non-DSR case decrementAmount += (stream.pendingWrites.chainLength() + stream.currentWriteOffset - std::max(*reliableSize, stream.currentWriteOffset)); } - - if (stream.writeBufMeta.offset + stream.writeBufMeta.length > - *reliableSize) { - // DSR case - decrementAmount += stream.writeBufMeta.length + - stream.writeBufMeta.offset - - std::max(*reliableSize, stream.writeBufMeta.offset); - } } else { - decrementAmount = static_cast( - stream.pendingWrites.chainLength() + stream.writeBufMeta.length); + decrementAmount = static_cast(stream.pendingWrites.chainLength()); } return decrementWithOverFlowCheck( @@ -345,7 +335,7 @@ quic::Expected updateFlowControlOnResetStream( void maybeWriteBlockAfterAPIWrite(QuicStreamState& stream) { // Only write blocked when stream becomes blocked if (getSendStreamFlowControlBytesWire(stream) == 0 && - stream.pendingWrites.empty() && stream.writeBufMeta.length == 0) { + stream.pendingWrites.empty()) { stream.conn.streamManager->queueBlocked( stream.id, stream.flowControlState.peerAdvertisedMaxOffset); if (stream.conn.qLogger) { @@ -385,7 +375,7 @@ void maybeWriteBlockAfterSocketWrite(QuicStreamState& stream) { } else { shouldEmitStreamBlockedFrame = getSendStreamFlowControlBytesWire(stream) == 0 && - (!stream.pendingWrites.empty() || stream.writeBufMeta.length > 0); + !stream.pendingWrites.empty(); } if (shouldEmitStreamBlockedFrame && @@ -414,8 +404,7 @@ void handleStreamWindowUpdate( stream.flowControlState.peerAdvertisedMaxOffset = maximumData; stream.flowControlState.pendingBlockedFrame = false; if (stream.flowControlState.peerAdvertisedMaxOffset > - stream.currentWriteOffset + stream.pendingWrites.chainLength() + - stream.writeBufMeta.length) { + stream.currentWriteOffset + stream.pendingWrites.chainLength()) { updateFlowControlList(stream); } stream.conn.streamManager->updateWritableStreams( @@ -469,8 +458,7 @@ uint64_t getSendStreamFlowControlBytesWire(const QuicStreamState& stream) { uint64_t getSendStreamFlowControlBytesAPI(const QuicStreamState& stream) { auto sendFlowControlBytes = getSendStreamFlowControlBytesWire(stream); - auto dataInBuffer = - stream.pendingWrites.chainLength() + stream.writeBufMeta.length; + auto dataInBuffer = stream.pendingWrites.chainLength(); if (dataInBuffer > sendFlowControlBytes) { return 0; } else { diff --git a/quic/flowcontrol/test/QuicFlowControlTest.cpp b/quic/flowcontrol/test/QuicFlowControlTest.cpp index ca9e29ef0..7c083a9db 100644 --- a/quic/flowcontrol/test/QuicFlowControlTest.cpp +++ b/quic/flowcontrol/test/QuicFlowControlTest.cpp @@ -1128,30 +1128,6 @@ TEST_F(QuicFlowControlTest, OnStreamWindowUpdateSentWithoutPendingEvent) { EXPECT_FALSE(conn_.streamManager->pendingWindowUpdate(id)); } -TEST_F(QuicFlowControlTest, StreamFlowControlWithBufMeta) { - StreamId id = 0; - QuicStreamState stream(id, conn_); - stream.flowControlState.peerAdvertisedMaxOffset = 1000; - stream.currentWriteOffset = 200; - auto inputData = buildRandomInputData(100); - stream.pendingWrites.append(inputData); - stream.writeBuffer.append(std::move(inputData)); - EXPECT_EQ(800, getSendStreamFlowControlBytesWire(stream)); - EXPECT_EQ(700, getSendStreamFlowControlBytesAPI(stream)); - - stream.writeBufMeta.offset = - stream.currentWriteOffset + stream.writeBuffer.chainLength(); - stream.writeBufMeta.length = 300; - EXPECT_EQ(800, getSendStreamFlowControlBytesWire(stream)); - EXPECT_EQ(400, getSendStreamFlowControlBytesAPI(stream)); - - stream.currentWriteOffset += stream.writeBuffer.chainLength(); - stream.writeBuffer.move(); - ChainedByteRangeHead(std::move(stream.pendingWrites)); - EXPECT_EQ(700, getSendStreamFlowControlBytesWire(stream)); - EXPECT_EQ(400, getSendStreamFlowControlBytesAPI(stream)); -} - // This tests the non-DSR case where // currentWriteOffset < reliableSize < (currentWriteOffset + // pendingWrites.chainLength()) @@ -1209,57 +1185,4 @@ TEST_F(QuicFlowControlTest, ReliableSizeNonDsrReset3) { EXPECT_EQ(stream.conn.flowControlState.sumCurStreamBufferLen, 5); } -// This tests the DSR case where -// writeBufMeta.offset < reliableSize < (writeBufMeta.offset + -// writeBufMeta.length) -TEST_F(QuicFlowControlTest, ReliableSizeDsrReset1) { - StreamId id = 0; - QuicStreamState stream(id, conn_); - stream.writeBufMeta.offset = 20; - stream.writeBufMeta.length = 5; - - stream.conn.flowControlState.sumCurStreamBufferLen = 5; - auto result = updateFlowControlOnResetStream(stream, 22); - ASSERT_FALSE(result.hasError()); - - // We threw away 3 bytes due to the reliable reset - EXPECT_EQ(stream.conn.flowControlState.sumCurStreamBufferLen, 2); -} - -// This tests the DSR case where -// reliableSize < writeBufMeta.offset < (writeBufMeta.offset + -// writeBufMeta.length) -TEST_F(QuicFlowControlTest, ReliableSizeDsrReset2) { - StreamId id = 0; - QuicStreamState stream(id, conn_); - stream.writeBufMeta.offset = 20; - stream.writeBufMeta.length = 5; - - stream.conn.flowControlState.sumCurStreamBufferLen = 5; - - auto result = updateFlowControlOnResetStream(stream, 10); - ASSERT_FALSE(result.hasError()); - - // We threw away all 5 bytes due to the reliable reset - EXPECT_EQ(stream.conn.flowControlState.sumCurStreamBufferLen, 0); -} - -// This tests the DSR case where -// writeBufMeta.offset < (writeBufMeta.offset + -// writeBufMeta.length) < reliableSize -TEST_F(QuicFlowControlTest, ReliableSizeDsrReset3) { - StreamId id = 0; - QuicStreamState stream(id, conn_); - stream.writeBufMeta.offset = 20; - stream.writeBufMeta.length = 5; - - stream.conn.flowControlState.sumCurStreamBufferLen = 5; - - auto result = updateFlowControlOnResetStream(stream, 30); - ASSERT_FALSE(result.hasError()); - - // We didn't throw away any bytes after the reliable reset - EXPECT_EQ(stream.conn.flowControlState.sumCurStreamBufferLen, 5); -} - } // namespace quic::test diff --git a/quic/logging/FileQLogger.cpp b/quic/logging/FileQLogger.cpp index aa588fd8e..1eaae9f8e 100644 --- a/quic/logging/FileQLogger.cpp +++ b/quic/logging/FileQLogger.cpp @@ -257,7 +257,6 @@ void FileQLogger::addTransportSummary(const TransportSummaryArgs& args) { args.finalPacketLossTimeReorderingThreshDividend, args.usedZeroRtt, args.quicVersion, - args.dsrPacketCount, args.initialPacketsReceived, args.uniqueInitialCryptoFramesReceived, args.timeUntilLastInitialCryptoFrameReceived, diff --git a/quic/logging/QLogger.h b/quic/logging/QLogger.h index b81fa7375..1d47a77b3 100644 --- a/quic/logging/QLogger.h +++ b/quic/logging/QLogger.h @@ -63,7 +63,6 @@ class QLogger { uint64_t finalPacketLossTimeReorderingThreshDividend{}; bool usedZeroRtt{}; QuicVersion quicVersion{QuicVersion::MVFST_INVALID}; - uint64_t dsrPacketCount{}; uint16_t initialPacketsReceived{}; uint16_t uniqueInitialCryptoFramesReceived{}; std::chrono::milliseconds timeUntilLastInitialCryptoFrameReceived; diff --git a/quic/logging/QLoggerCommon.cpp b/quic/logging/QLoggerCommon.cpp index b76f978ed..42efde389 100644 --- a/quic/logging/QLoggerCommon.cpp +++ b/quic/logging/QLoggerCommon.cpp @@ -79,7 +79,6 @@ void QLoggerCommon::addTransportSummary(const TransportSummaryArgs& args) { args.finalPacketLossTimeReorderingThreshDividend, args.usedZeroRtt, args.quicVersion, - args.dsrPacketCount, args.initialPacketsReceived, args.uniqueInitialCryptoFramesReceived, args.timeUntilLastInitialCryptoFrameReceived, diff --git a/quic/logging/QLoggerTypes.cpp b/quic/logging/QLoggerTypes.cpp index d5349f23e..fa3eabcbf 100644 --- a/quic/logging/QLoggerTypes.cpp +++ b/quic/logging/QLoggerTypes.cpp @@ -422,7 +422,6 @@ QLogTransportSummaryEvent::QLogTransportSummaryEvent( uint64_t finalPacketLossTimeReorderingThreshDividend, bool usedZeroRttIn, QuicVersion quicVersionIn, - uint64_t dsrPacketCountIn, uint16_t initialPacketsReceivedIn, uint16_t uniqueInitialCryptoFramesReceivedIn, std::chrono::milliseconds timeUntilLastInitialCryptoFrameReceivedIn, @@ -449,7 +448,6 @@ QLogTransportSummaryEvent::QLogTransportSummaryEvent( finalPacketLossTimeReorderingThreshDividend}, usedZeroRtt{usedZeroRttIn}, quicVersion{quicVersionIn}, - dsrPacketCount{dsrPacketCountIn}, initialPacketsReceived{initialPacketsReceivedIn}, uniqueInitialCryptoFramesReceived{uniqueInitialCryptoFramesReceivedIn}, timeUntilLastInitialCryptoFrameReceived{ @@ -491,7 +489,6 @@ folly::dynamic QLogTransportSummaryEvent::toDynamic() const { data["quic_version"] = static_cast::type>( quicVersion); - data["dsr_packet_count"] = dsrPacketCount; data["initial_packets_received"] = initialPacketsReceived; data["unique_initial_crypto_frames_received"] = uniqueInitialCryptoFramesReceived; diff --git a/quic/logging/QLoggerTypes.h b/quic/logging/QLoggerTypes.h index 911d5b536..363248249 100644 --- a/quic/logging/QLoggerTypes.h +++ b/quic/logging/QLoggerTypes.h @@ -505,7 +505,6 @@ class QLogTransportSummaryEvent : public QLogEvent { uint64_t finalPacketLossTimeReorderingThreshDividend, bool usedZeroRtt, QuicVersion version, - uint64_t dsrPacketCount, uint16_t initialPacketsReceived, uint16_t uniqueInitialCryptoFramesReceived, std::chrono::milliseconds timeUntilLastInitialCryptoFrameReceived, @@ -532,7 +531,6 @@ class QLogTransportSummaryEvent : public QLogEvent { uint64_t finalPacketLossTimeReorderingThreshDividend; bool usedZeroRtt; QuicVersion quicVersion; - uint64_t dsrPacketCount; uint16_t initialPacketsReceived; uint16_t uniqueInitialCryptoFramesReceived; std::chrono::milliseconds timeUntilLastInitialCryptoFrameReceived; diff --git a/quic/logging/test/QLoggerTest.cpp b/quic/logging/test/QLoggerTest.cpp index 7689e80c2..28876912c 100644 --- a/quic/logging/test/QLoggerTest.cpp +++ b/quic/logging/test/QLoggerTest.cpp @@ -116,7 +116,6 @@ TEST_F(QLoggerTest, TransportSummaryEvent) { .finalPacketLossTimeReorderingThreshDividend = 47, .usedZeroRtt = false, .quicVersion = QuicVersion::MVFST, - .dsrPacketCount = 37, /* numQuicInitialPacketReceived = */ .initialPacketsReceived = 1, /* numUniqueInitialCryptoFrameReceived = */ .uniqueInitialCryptoFramesReceived = 1, @@ -146,7 +145,6 @@ TEST_F(QLoggerTest, TransportSummaryEvent) { EXPECT_EQ(gotEvent->finalPacketLossReorderingThreshold, 46); EXPECT_EQ(gotEvent->finalPacketLossTimeReorderingThreshDividend, 47); EXPECT_EQ(gotEvent->usedZeroRtt, false); - EXPECT_EQ(gotEvent->dsrPacketCount, 37); EXPECT_EQ(gotEvent->initialPacketsReceived, 1); EXPECT_EQ(gotEvent->uniqueInitialCryptoFramesReceived, 1); EXPECT_EQ(gotEvent->timeUntilLastInitialCryptoFrameReceived.count(), 1); @@ -872,7 +870,6 @@ TEST_F(QLoggerTest, TransportSummaryFollyDynamic) { "final_packet_loss_time_reordering_threshold_dividend": 15, "used_zero_rtt": true, "quic_version": 4207849474, - "dsr_packet_count": 37, "initial_packets_received": 1, "unique_initial_crypto_frames_received": 1, "time_until_last_initial_crypto_frame_received": 1, @@ -903,7 +900,6 @@ TEST_F(QLoggerTest, TransportSummaryFollyDynamic) { .finalPacketLossTimeReorderingThreshDividend = 15, .usedZeroRtt = true, .quicVersion = QuicVersion::MVFST, - .dsrPacketCount = 37, /* numQuicInitialPacketReceived = */ .initialPacketsReceived = 1, /* numUniqueInitialCryptoFrameReceived = */ .uniqueInitialCryptoFramesReceived = 1, diff --git a/quic/loss/QuicLossFunctions.cpp b/quic/loss/QuicLossFunctions.cpp index 10fd2679b..3f83bebc9 100644 --- a/quic/loss/QuicLossFunctions.cpp +++ b/quic/loss/QuicLossFunctions.cpp @@ -175,36 +175,19 @@ quic::Expected markPacketLoss( break; } - if (!frame.fromBufMeta) { - auto bufferItr = stream->retransmissionBuffer.find(frame.offset); - if (bufferItr == stream->retransmissionBuffer.end()) { - break; - } - if (!streamRetransmissionDisabled(conn, *stream)) { - stream->insertIntoLossBuffer(std::move(bufferItr->second)); - } - if (streamsWithAddedStreamLossForPacket.find(frame.streamId) == - streamsWithAddedStreamLossForPacket.end()) { - stream->streamLossCount++; - streamsWithAddedStreamLossForPacket.insert(frame.streamId); - } - stream->retransmissionBuffer.erase(bufferItr); - } else { - auto retxBufMetaItr = - stream->retransmissionBufMetas.find(frame.offset); - if (retxBufMetaItr == stream->retransmissionBufMetas.end()) { - break; - } - if (!streamRetransmissionDisabled(conn, *stream)) { - stream->insertIntoLossBufMeta(retxBufMetaItr->second); - } - if (streamsWithAddedStreamLossForPacket.find(frame.streamId) == - streamsWithAddedStreamLossForPacket.end()) { - stream->streamLossCount++; - streamsWithAddedStreamLossForPacket.insert(frame.streamId); - } - stream->retransmissionBufMetas.erase(retxBufMetaItr); + auto bufferItr = stream->retransmissionBuffer.find(frame.offset); + if (bufferItr == stream->retransmissionBuffer.end()) { + break; } + if (!streamRetransmissionDisabled(conn, *stream)) { + stream->insertIntoLossBuffer(std::move(bufferItr->second)); + } + if (streamsWithAddedStreamLossForPacket.find(frame.streamId) == + streamsWithAddedStreamLossForPacket.end()) { + stream->streamLossCount++; + streamsWithAddedStreamLossForPacket.insert(frame.streamId); + } + stream->retransmissionBuffer.erase(bufferItr); conn.streamManager->updateWritableStreams(*stream); break; } @@ -287,8 +270,6 @@ quic::Expected processOutstandingsForLoss( QuicConnectionStateBase& conn, PacketNum largestAcked, const PacketNumberSpace& pnSpace, - const InlineMap& largestDsrAckedSequenceNumber, - const Optional& largestNonDsrAckedSequenceNumber, const TimePoint& lossTime, const std::chrono::microseconds& rttSample, const LossVisitor& lossVisitor, @@ -305,7 +286,6 @@ quic::Expected processOutstandingsForLoss( auto& pkt = *iter; auto currentPacketNum = pkt.packet.header.getPacketSequenceNum(); - Optional maybeCurrentStreamPacketIdx; if (currentPacketNum >= largestAcked) { break; } @@ -314,42 +294,8 @@ quic::Expected processOutstandingsForLoss( iter++; continue; } - // We now have to determine the largest ACKed packet number we should use - // for the reordering threshold loss determination. - auto maybeStreamFrame = pkt.packet.frames.empty() - ? nullptr - : pkt.packet.frames.front().asWriteStreamFrame(); - // Use the translated virtual number for the current packet if it's a DSR - // packet, or the non DSR sequence number otherwise. - if (maybeCurrentStreamPacketIdx.has_value()) { - currentPacketNum = *maybeCurrentStreamPacketIdx; - } else if (pkt.nonDsrPacketSequenceNumber.has_value()) { - currentPacketNum = pkt.nonDsrPacketSequenceNumber.value(); - } - - // For DSR we use the stream packet index (monotonic index of packets - // within a stream) to determine reordering loss. This effectively puts - // DSR packets on their own packet number timeline. - auto largestAckedForComparison = [&]() -> PacketNum { - if (maybeStreamFrame && maybeStreamFrame->fromBufMeta) { - maybeCurrentStreamPacketIdx = maybeStreamFrame->streamPacketIdx; - // If the packet being considered is a DSR packet, we use the - // largest ACKed for that stream. The default value here covers the - // case where no DSR packets were ACKed, in which case we should - // not declare reorder loss. - CHECK(pkt.isDSRPacket); - return folly::get_default( - largestDsrAckedSequenceNumber, - maybeStreamFrame->streamId, - *maybeCurrentStreamPacketIdx); - } else { - // If the packet being considered is a non-DSR packet, use the largest - // non-DSR ACKed sequence number. If there were no non-DSR ACKed, we - // shouldn't declare reorder loss. - return largestNonDsrAckedSequenceNumber.value_or(currentPacketNum); - } - }(); + auto largestAckedForComparison = largestAcked; // The max ensures that we don't overflow on the subtraction if the largest // ACKed is smaller. @@ -382,10 +328,6 @@ quic::Expected processOutstandingsForLoss( continue; } - if (pkt.isDSRPacket) { - CHECK_GT(conn.outstandings.dsrCount, 0); - --conn.outstandings.dsrCount; - } if (pkt.maybeClonedPacketIdentifier) { CHECK(conn.outstandings.clonedPacketCount[pnSpace]); --conn.outstandings.clonedPacketCount[pnSpace]; @@ -450,8 +392,7 @@ detectLossPackets( const AckState& ackState, const LossVisitor& lossVisitor, const TimePoint lossTime, - const PacketNumberSpace pnSpace, - const CongestionController::AckEvent* ackEvent) { + const PacketNumberSpace pnSpace) { getLossTime(conn, pnSpace).reset(); std::chrono::microseconds rttSample = std::max(conn.lossState.srtt, conn.lossState.lrtt); @@ -475,52 +416,12 @@ detectLossPackets( // Note that time based loss detection is also within the same PNSpace. - // Loop over all ACKed packets and collect the largest ACKed packet per DSR - // stream. This facilitates only considering the reordering threshold per DSR - // sender, which avoids the problem of "natural" reordering caused by - // multiple DSR senders. Similarly track the largest non-DSR ACKed, for the - // reason but when DSR packets are reordered "before" non-DSR packets. - // These two variables hold DSR and non-DSR sequence numbers not actual packet - // numbers InlineMap largestDsrAckedSeqNo; - InlineMap largestDsrAckedSeqNo; - Optional largestNonDsrAckedSeqNo; - if (ackEvent) { - for (const auto& ackPacket : ackEvent->ackedPackets) { - for (auto& [stream, details] : ackPacket.detailsPerStream) { - if (details.streamPacketIdx) { - largestDsrAckedSeqNo[stream] = std::max( - folly::get_default( - largestDsrAckedSeqNo, stream, *details.streamPacketIdx), - *details.streamPacketIdx); - } else { - largestNonDsrAckedSeqNo = std::max( - largestNonDsrAckedSeqNo.value_or(0), - ackPacket.nonDsrPacketSequenceNumber); - } - } - // If there are no streams, then it's not a DSR packet. - if (ackPacket.detailsPerStream.empty()) { - largestNonDsrAckedSeqNo = std::max( - largestNonDsrAckedSeqNo.value_or(0), - ackPacket.nonDsrPacketSequenceNumber); - } - } - } - // This covers the case where there's no ackedPackets. - if (largestDsrAckedSeqNo.empty() && - ackState.largestNonDsrSequenceNumberAckedByPeer.has_value()) { - largestNonDsrAckedSeqNo = largestNonDsrAckedSeqNo.value_or( - ackState.largestNonDsrSequenceNumberAckedByPeer.value()); - } - bool shouldSetTimer = false; if (ackState.largestAckedByPeer.has_value()) { auto processResult = processOutstandingsForLoss( conn, *ackState.largestAckedByPeer, pnSpace, - largestDsrAckedSeqNo, - largestNonDsrAckedSeqNo, lossTime, rttSample, lossVisitor, // Pass the visitor (which returns Expected) @@ -600,19 +501,9 @@ handleAckForLoss( ackState.largestAckedByPeer = std::max( ackState.largestAckedByPeer.value_or(*ack.largestNewlyAckedPacket), *ack.largestNewlyAckedPacket); - - // Update the largest non-DSR acked sequence number - auto largestNewlyAckedPacket = ack.getLargestNewlyAckedPacket(); - if (largestNewlyAckedPacket && - largestNewlyAckedPacket->nonDsrPacketSequenceNumber) { - ackState.largestNonDsrSequenceNumberAckedByPeer = std::max( - ackState.largestNonDsrSequenceNumberAckedByPeer.value_or( - largestNewlyAckedPacket->nonDsrPacketSequenceNumber), - largestNewlyAckedPacket->nonDsrPacketSequenceNumber); - } } - auto lossEventResult = detectLossPackets( - conn, ackState, lossVisitor, ack.ackTime, pnSpace, &ack); + auto lossEventResult = + detectLossPackets(conn, ackState, lossVisitor, ack.ackTime, pnSpace); if (!lossEventResult.has_value()) { return quic::make_unexpected(lossEventResult.error()); diff --git a/quic/loss/QuicLossFunctions.h b/quic/loss/QuicLossFunctions.h index e439d5721..a0920b608 100644 --- a/quic/loss/QuicLossFunctions.h +++ b/quic/loss/QuicLossFunctions.h @@ -183,8 +183,6 @@ void setLossDetectionAlarm(QuicConnectionStateBase& conn, Timeout& timeout) { QuicConnectionStateBase& conn, PacketNum largestAcked, const PacketNumberSpace& pnSpace, - const InlineMap& largestDsrAckedSequenceNumber, - const Optional& largestNonDsrAckedSequenceNumber, const TimePoint& lossTime, const std::chrono::microseconds& rttSample, const LossVisitor& lossVisitor, // Visitor now returns Expected @@ -204,8 +202,7 @@ void setLossDetectionAlarm(QuicConnectionStateBase& conn, Timeout& timeout) { const AckState& ackState, const LossVisitor& lossVisitor, const TimePoint lossTime, - const PacketNumberSpace pnSpace, - const CongestionController::AckEvent* ackEvent = nullptr); + const PacketNumberSpace pnSpace); /* * Function invoked when PTO alarm fires. Handles errors internally. diff --git a/quic/loss/test/BUCK b/quic/loss/test/BUCK index d9c012b10..aec2c4f76 100644 --- a/quic/loss/test/BUCK +++ b/quic/loss/test/BUCK @@ -19,8 +19,6 @@ mvfst_cpp_test( "//quic/common/events:folly_eventbase", "//quic/common/test:test_utils", "//quic/common/testutil:mock_async_udp_socket", - "//quic/dsr:types", - "//quic/dsr/test:mocks", "//quic/fizz/client/handshake:fizz_client_handshake", "//quic/fizz/server/handshake:fizz_server_handshake", "//quic/logging/test:mocks", diff --git a/quic/loss/test/QuicLossFunctionsTest.cpp b/quic/loss/test/QuicLossFunctionsTest.cpp index 2d550f536..0eb96645f 100644 --- a/quic/loss/test/QuicLossFunctionsTest.cpp +++ b/quic/loss/test/QuicLossFunctionsTest.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -104,11 +103,8 @@ class QuicLossFunctionsTest : public TestWithParam { conn->clientConnectionId = getTestConnectionId(); conn->version = QuicVersion::MVFST; conn->ackStates.initialAckState->nextPacketNum = 1; - conn->ackStates.initialAckState->nonDsrPacketSequenceNumber = 1; conn->ackStates.handshakeAckState->nextPacketNum = 1; - conn->ackStates.handshakeAckState->nonDsrPacketSequenceNumber = 1; conn->ackStates.appDataAckState.nextPacketNum = 1; - conn->ackStates.appDataAckState.nonDsrPacketSequenceNumber = 1; conn->flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiLocal = kDefaultStreamFlowControlWindow; conn->flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote = @@ -313,11 +309,8 @@ PacketNum QuicLossFunctionsTest::sendPacket( } conn.outstandings.packets.emplace_back(std::move(outstandingPacket)); conn.lossState.largestSent = getNextPacketNum(conn, packetNumberSpace); - increaseNextPacketNum(conn, packetNumberSpace, isDsr); - conn.outstandings.packets.back().isDSRPacket = isDsr; + increaseNextPacketNum(conn, packetNumberSpace); if (!isDsr) { - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, packetNumberSpace).nonDsrPacketSequenceNumber - 1; } conn.pendingEvents.setLossDetectionAlarm = true; return conn.lossState.largestSent.value(); @@ -387,8 +380,7 @@ TEST_F(QuicLossFunctionsTest, ClearEarlyRetranTimer) { return {}; }; auto& ackState = getAckState(*conn, PacketNumberSpace::Initial); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = secondPacketNum; + ackState.largestAckedByPeer = secondPacketNum; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -845,8 +837,7 @@ TEST_F(QuicLossFunctionsTest, TestReorderingThreshold) { firstHandshakeOpIter + 2, firstHandshakeOpIter + 5); // Ack for packet 9 arrives auto& ackState = getAckState(*conn, PacketNumberSpace::Handshake); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 9; + ackState.largestAckedByPeer = 9; auto lossResult = detectLossPackets( *conn, ackState, @@ -908,8 +899,7 @@ TEST_F(QuicLossFunctionsTest, TestReorderingThresholdWithSkippedPacket) { EXPECT_EQ(7, conn->outstandings.packetCount[PacketNumberSpace::Handshake]); // Ack for packet 8 arrives auto& ackState = getAckState(*conn, PacketNumberSpace::Handshake); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 8; + ackState.largestAckedByPeer = 8; auto lossResult = detectLossPackets( *conn, ackState, @@ -1130,8 +1120,7 @@ TEST_F(QuicLossFunctionsTest, ReorderingThresholdChecksSamePacketNumberSpace) { } auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = latestSent + 1; + ackState.largestAckedByPeer = latestSent; ASSERT_FALSE(detectLossPackets( *conn, @@ -1204,8 +1193,7 @@ TEST_F(QuicLossFunctionsTest, TestTimeReordering) { getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5); auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent; + ackState.largestAckedByPeer = largestSent; auto lossEventResult = detectLossPackets( *conn, ackState, @@ -1249,8 +1237,7 @@ TEST_F(QuicLossFunctionsTest, LossTimePreemptsCryptoTimer) { auto lossTime = sendTime + 50ms; auto& ackState = getAckState(*conn, PacketNumberSpace::Handshake); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = second; + ackState.largestAckedByPeer = second; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -1567,8 +1554,7 @@ TEST_F(QuicLossFunctionsTest, NoSkipLossVisitor) { } auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = lastSent; + ackState.largestAckedByPeer = lastSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -1605,8 +1591,7 @@ TEST_F(QuicLossFunctionsTest, SkipLossVisitor) { } auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = lastSent; + ackState.largestAckedByPeer = lastSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -1654,8 +1639,7 @@ TEST_F(QuicLossFunctionsTest, NoDoubleProcess) { // Ack the last sent packet. Despite three losses, lossVisitor only visit one // packet auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = lastSent; + ackState.largestAckedByPeer = lastSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -1681,14 +1665,13 @@ TEST_F(QuicLossFunctionsTest, DetectPacketLossClonedPacketsCounter) { sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); - auto ackedPacket = - sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); + sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); auto noopLossMarker = [](auto&, auto /* pathId */, auto&, bool) -> quic::Expected { return {}; }; auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = ackedPacket; + conn->ackStates.appDataAckState.nextPacketNum + 4; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -1815,8 +1798,7 @@ TEST_F(QuicLossFunctionsTest, TotalLossCount) { conn->lossState.rtxCount = 135; auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -1943,7 +1925,7 @@ TEST_F(QuicLossFunctionsTest, TimeThreshold) { auto referenceTime = Clock::now(); auto packet1 = sendPacket(*conn, referenceTime - 10ms, std::nullopt, PacketType::OneRtt); - auto packet2 = sendPacket( + sendPacket( *conn, referenceTime + conn->lossState.srtt / 2, std::nullopt, @@ -1957,8 +1939,7 @@ TEST_F(QuicLossFunctionsTest, TimeThreshold) { }; auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = packet2; + ackState.largestAckedByPeer = packet1 + 1; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -1987,8 +1968,7 @@ TEST_F(QuicLossFunctionsTest, OutstandingInitialCounting) { }; auto& ackState = getAckState(*conn, PacketNumberSpace::Initial); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2018,8 +1998,7 @@ TEST_F(QuicLossFunctionsTest, OutstandingHandshakeCounting) { return {}; }; auto& ackState = getAckState(*conn, PacketNumberSpace::Handshake); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2031,7 +2010,7 @@ TEST_F(QuicLossFunctionsTest, OutstandingHandshakeCounting) { EXPECT_EQ(4, conn->outstandings.packetCount[PacketNumberSpace::Handshake]); } -TEST_P(QuicLossFunctionsTest, CappedShiftNoCrash) { +TEST_F(QuicLossFunctionsTest, CappedShiftNoCrash) { auto conn = createConn(); conn->outstandings.reset(); conn->lossState.ptoCount = @@ -2112,7 +2091,6 @@ TEST_F(QuicLossFunctionsTest, PersistentCongestionAckOutsideWindow) { ack.ackedPackets.push_back( CongestionController::AckEvent::AckPacket::Builder() .setPacketNum(1) - .setNonDsrPacketSequenceNumber(1) .setOutstandingPacketMetadata(opm) .setDetailsPerStream(AckEvent::AckPacket::DetailsPerStream()) .build()); @@ -2147,7 +2125,6 @@ TEST_F(QuicLossFunctionsTest, PersistentCongestionAckInsideWindow) { ack.ackedPackets.push_back( CongestionController::AckEvent::AckPacket::Builder() .setPacketNum(1) - .setNonDsrPacketSequenceNumber(1) .setOutstandingPacketMetadata(opm) .setDetailsPerStream(AckEvent::AckPacket::DetailsPerStream()) .build()); @@ -2181,7 +2158,6 @@ TEST_F(QuicLossFunctionsTest, PersistentCongestionNoPTO) { ack.ackedPackets.push_back( CongestionController::AckEvent::AckPacket::Builder() .setPacketNum(1) - .setNonDsrPacketSequenceNumber(1) .setOutstandingPacketMetadata(opm) .setDetailsPerStream(AckEvent::AckPacket::DetailsPerStream()) .build()); @@ -2220,7 +2196,8 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventReorder) { TimePoint checkTime = TimePoint(200ms); // Out of 1, 2, 3, 4, 5, 6, 7 -- we deleted (acked) 3,4,5. - // 1, 2 and 6 are "lost" due to reodering. None lost due to timeout + // With reorderingThreshold=1 and largestAckedByPeer=7, packets < (7-1) are + // lost. So 1, 2 are "lost" due to reordering. None lost due to timeout. EXPECT_CALL( *obs1, packetLossDetected( @@ -2235,16 +2212,11 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventReorder) { getLossPacketMatcher( 2 /* packetNum */, true /* lossByReorder */, - false /* lossByTimeout */), - getLossPacketMatcher( - 6 /* packetNum */, - true /* lossByReorder */, false /* lossByTimeout */))))) .Times(1); auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent + 1; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2266,7 +2238,7 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventReorder) { false /* lossByTimeout */), getOutstandingPacketMatcher( 6 /* packetNum */, - true /* lossByReorder */, + false /* lossByReorder */, false /* lossByTimeout */), getOutstandingPacketMatcher( 7 /* packetNum */, @@ -2301,7 +2273,8 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventTimeout) { conn->transportSettings.timeReorderingThreshDivisor = 1.0; TimePoint checkTime = TimePoint(500ms); - // expect all packets to be lost due to timeout + // expect packets 1-6 to be lost due to timeout + // (packet 7 is largestAckedByPeer so it's not checked for loss) EXPECT_CALL( *obs1, packetLossDetected( @@ -2332,15 +2305,10 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventTimeout) { getLossPacketMatcher( 6 /* packetNum */, false /* lossByReorder */, - true /* lossByTimeout */), - getLossPacketMatcher( - 7 /* packetNum */, - false /* lossByReorder */, true /* lossByTimeout */))))) .Times(1); auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent + 1; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2379,7 +2347,7 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventTimeout) { getOutstandingPacketMatcher( 7 /* packetNum */, false /* lossByReorder */, - true /* lossByTimeout */))); + false /* lossByTimeout */))); CHECK_NOTNULL(conn->getSocketObserverContainer())->removeObserver(obs1.get()); } @@ -2416,8 +2384,10 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventTimeoutAndReorder) { TimePoint checkTime = TimePoint(500ms); // Out of 1, 2, 3, 4, 5, 6, 7 -- we deleted (acked) 3,4,5. - // 1, 2, 6 are lost due to reodering and timeout. - // 7 just timed out + // With reorderingThreshold=1 and largestAckedByPeer=7, packets < 6 are lost + // by reorder. All packets also timed out. So: 1, 2 lost by both reorder and + // timeout; 6 lost by timeout only. Packet 7 is not checked for loss (it's + // largestAckedByPeer). EXPECT_CALL( *obs1, packetLossDetected( @@ -2435,16 +2405,11 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventTimeoutAndReorder) { true /* lossByTimeout */), getLossPacketMatcher( 6 /* packetNum */, - true /* lossByReorder */, - true /* lossByTimeout */), - getLossPacketMatcher( - 7 /* packetNum */, false /* lossByReorder */, true /* lossByTimeout */))))) .Times(1); auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent + 1; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2466,12 +2431,12 @@ TEST_F(QuicLossFunctionsTest, ObserverLossEventTimeoutAndReorder) { true /* lossByTimeout */), getOutstandingPacketMatcher( 6 /* packetNum */, - true /* lossByReorder */, + false /* lossByReorder */, true /* lossByTimeout */), getOutstandingPacketMatcher( 7 /* packetNum */, false /* lossByReorder */, - true /* lossByTimeout */))); + false /* lossByTimeout */))); CHECK_NOTNULL(conn->getSocketObserverContainer())->removeObserver(obs1.get()); } @@ -2506,8 +2471,7 @@ TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByReordering) { TimePoint checkTime = TimePoint(200ms); auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent + 1; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2516,12 +2480,13 @@ TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByReordering) { PacketNumberSpace::AppData) .hasError()); - // Sent 7 packets, out of 0, 1, 2, 3, 4, 5, 6 -- we deleted (acked) 2,3,4 - // 0, 1, and 5 should be marked lost due to reordering, std::nullopt due to - // timeout 6 is outstanding / on the wire still (no determination made) - EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLost); + // Sent 7 packets (1-7), deleted (acked) 3,4,5 + // With reorderingThreshold=1 and largestAckedByPeer=7, packets < 6 are lost. + // So packets 1, 2 should be marked lost due to reordering (not packet 6). + // Packet 7 is not checked for loss. + EXPECT_EQ(2, conn->lossState.totalPacketsMarkedLost); EXPECT_EQ(0, conn->lossState.totalPacketsMarkedLostByTimeout); - EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLostByReorderingThreshold); + EXPECT_EQ(2, conn->lossState.totalPacketsMarkedLostByReorderingThreshold); } TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByTimeout) { @@ -2549,8 +2514,7 @@ TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByTimeout) { TimePoint checkTime = TimePoint(500ms); auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent + 1; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2559,9 +2523,10 @@ TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByTimeout) { PacketNumberSpace::AppData) .hasError()); - // All 7 packets should be marked as lost by PTO - EXPECT_EQ(7, conn->lossState.totalPacketsMarkedLost); - EXPECT_EQ(7, conn->lossState.totalPacketsMarkedLostByTimeout); + // Packets 1-6 should be marked as lost by PTO + // (packet 7 is largestAckedByPeer so it's not checked for loss) + EXPECT_EQ(6, conn->lossState.totalPacketsMarkedLost); + EXPECT_EQ(6, conn->lossState.totalPacketsMarkedLostByTimeout); EXPECT_EQ(0, conn->lossState.totalPacketsMarkedLostByReorderingThreshold); } @@ -2595,8 +2560,7 @@ TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByTimeoutPartial) { TimePoint checkTime = TimePoint(500ms); auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent + 1; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2605,11 +2569,12 @@ TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByTimeoutPartial) { PacketNumberSpace::AppData) .hasError()); - // Sent 7 packets, out of 0, 1, 2, 3, 4, 5, 6 -- we deleted (acked) 2,3,4 - // 0, 1, 5, and 6 should be marked lost due to timeout, std::nullopt due to - // reordering - EXPECT_EQ(4, conn->lossState.totalPacketsMarkedLost); - EXPECT_EQ(4, conn->lossState.totalPacketsMarkedLostByTimeout); + // Sent 7 packets (1-7), deleted (acked) 3,4,5 + // Remaining: 1, 2, 6, 7 + // Packet 7 is largestAckedByPeer so it's not checked for loss + // Packets 1, 2, 6 should be marked lost due to timeout + EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLost); + EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLostByTimeout); EXPECT_EQ(0, conn->lossState.totalPacketsMarkedLostByReorderingThreshold); } @@ -2644,8 +2609,7 @@ TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByTimeoutAndReordering) { TimePoint checkTime = TimePoint(500ms); auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = largestSent + 1; + ackState.largestAckedByPeer = largestSent; ASSERT_FALSE(detectLossPackets( *conn, ackState, @@ -2654,913 +2618,17 @@ TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByTimeoutAndReordering) { PacketNumberSpace::AppData) .hasError()); - // Sent 7 packets, out of 0, 1, 2, 3, 4, 5, 6 -- we deleted (acked) 2,3,4 - // 0, 1, and 5 should be marked lost due to reordering AND timeout - // 6 should be marked as lost due to timeout only - EXPECT_EQ(4, conn->lossState.totalPacketsMarkedLost); - EXPECT_EQ(4, conn->lossState.totalPacketsMarkedLostByTimeout); - EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLostByReorderingThreshold); + // Sent 7 packets (1-7), deleted (acked) 3,4,5 + // Remaining: 1, 2, 6, 7 + // With reorderingThreshold=1 and largestAckedByPeer=7, packets < 6 are lost + // by reorder. All packets also timed out. Packet 7 is not checked for loss. + // So: packets 1, 2 lost by both reorder and timeout; packet 6 lost by timeout + // only. + EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLost); + EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLostByTimeout); + EXPECT_EQ(2, conn->lossState.totalPacketsMarkedLostByReorderingThreshold); } -TEST_F(QuicLossFunctionsTest, LossVisitorDSRTest) { - auto conn = createConn(); - auto* stream = conn->streamManager->createNextBidirectionalStream().value(); - stream->dsrSender = std::make_unique(); - ASSERT_FALSE( - writeDataToQuicStream(*stream, folly::IOBuf::copyBuffer("grape"), false) - .hasError()); - ASSERT_FALSE( - writeBufMetaToQuicStream(*stream, BufferMeta(1000), true).hasError()); - auto bufMetaStartingOffset = stream->writeBufMeta.offset; - ASSERT_EQ(1000, stream->writeBufMeta.length); - ASSERT_TRUE(stream->writeBufMeta.eof); - ASSERT_EQ(bufMetaStartingOffset + 1000, *stream->finalWriteOffset); - // Send real data - ASSERT_FALSE(handleStreamWritten( - *conn, - *stream, - 0, - bufMetaStartingOffset, - false, - 0 /* PacketNum */, - PacketNumberSpace::AppData) - .hasError()); - ASSERT_EQ(0, stream->pendingWrites.chainLength()); - auto retxIter = stream->retransmissionBuffer.find(0); - ASSERT_NE(stream->retransmissionBuffer.end(), retxIter); - ASSERT_EQ(0, retxIter->second->offset); - ASSERT_FALSE(retxIter->second->eof); - auto expectedBuf = folly::IOBuf::copyBuffer("grape"); - ASSERT_EQ( - ByteRange(expectedBuf->buffer(), expectedBuf->length()), - retxIter->second->data.getHead()->getRange()); - ASSERT_EQ(stream->currentWriteOffset, bufMetaStartingOffset); - - // Send BufMeta in 3 chunks: - handleStreamBufMetaWritten( - *conn, - *stream, - bufMetaStartingOffset, - 200, - false, - 1 /* PacketNum */, - PacketNumberSpace::AppData); - ASSERT_EQ(800, stream->writeBufMeta.length); - ASSERT_TRUE(stream->writeBufMeta.eof); - ASSERT_EQ(bufMetaStartingOffset + 200, stream->writeBufMeta.offset); - auto retxBufMetaIter = - stream->retransmissionBufMetas.find(bufMetaStartingOffset); - ASSERT_NE(stream->retransmissionBufMetas.end(), retxBufMetaIter); - ASSERT_EQ(bufMetaStartingOffset, retxBufMetaIter->second.offset); - ASSERT_EQ(200, retxBufMetaIter->second.length); - ASSERT_FALSE(retxBufMetaIter->second.eof); - conn->streamManager->updateWritableStreams(*stream); - EXPECT_FALSE(conn->streamManager->hasLoss()); - EXPECT_FALSE(conn->streamManager->writableDSRStreams().empty()); - - handleStreamBufMetaWritten( - *conn, - *stream, - bufMetaStartingOffset + 200, - 400, - false, - 2 /* PacketNum */, - PacketNumberSpace::AppData); - ASSERT_EQ(400, stream->writeBufMeta.length); - ASSERT_TRUE(stream->writeBufMeta.eof); - ASSERT_EQ(bufMetaStartingOffset + 600, stream->writeBufMeta.offset); - retxBufMetaIter = - stream->retransmissionBufMetas.find(bufMetaStartingOffset + 200); - ASSERT_NE(stream->retransmissionBufMetas.end(), retxBufMetaIter); - ASSERT_EQ(bufMetaStartingOffset + 200, retxBufMetaIter->second.offset); - ASSERT_EQ(400, retxBufMetaIter->second.length); - ASSERT_FALSE(retxBufMetaIter->second.eof); - conn->streamManager->updateWritableStreams(*stream); - EXPECT_FALSE(conn->streamManager->hasLoss()); - EXPECT_FALSE(conn->streamManager->writableDSRStreams().empty()); - - handleStreamBufMetaWritten( - *conn, - *stream, - bufMetaStartingOffset + 600, - 400, - true, - 3 /* PacketNum */, - PacketNumberSpace::AppData); - ASSERT_EQ(0, stream->writeBufMeta.length); - ASSERT_TRUE(stream->writeBufMeta.eof); - ASSERT_EQ(bufMetaStartingOffset + 1000 + 1, stream->writeBufMeta.offset); - retxBufMetaIter = - stream->retransmissionBufMetas.find(bufMetaStartingOffset + 600); - ASSERT_NE(stream->retransmissionBufMetas.end(), retxBufMetaIter); - ASSERT_EQ(bufMetaStartingOffset + 600, retxBufMetaIter->second.offset); - ASSERT_EQ(400, retxBufMetaIter->second.length); - ASSERT_TRUE(retxBufMetaIter->second.eof); - conn->streamManager->updateWritableStreams(*stream); - EXPECT_FALSE(conn->streamManager->hasLoss()); - EXPECT_TRUE(conn->streamManager->writableDSRStreams().empty()); - - // Lose the 1st dsr packet: - RegularQuicWritePacket packet1(PacketHeader(ShortHeader( - ProtectionType::KeyPhaseZero, conn->serverConnectionId.value(), 1))); - WriteStreamFrame frame1(stream->id, bufMetaStartingOffset, 200, false); - frame1.fromBufMeta = true; - packet1.frames.push_back(frame1); - ASSERT_FALSE( - markPacketLoss(*conn, conn->currentPathId, packet1, false /* processed */) - .hasError()); - EXPECT_EQ(1, stream->lossBufMetas.size()); - const auto& lostBufMeta1 = stream->lossBufMetas.front(); - EXPECT_EQ(bufMetaStartingOffset, lostBufMeta1.offset); - EXPECT_EQ(200, lostBufMeta1.length); - EXPECT_FALSE(lostBufMeta1.eof); - EXPECT_EQ(2, stream->retransmissionBufMetas.size()); - EXPECT_TRUE(conn->streamManager->hasLoss()); - ASSERT_EQ(stream->streamLossCount, 1); - EXPECT_FALSE(stream->hasWritableBufMeta()); - EXPECT_FALSE(conn->streamManager->writableDSRStreams().contains(stream->id)); - EXPECT_TRUE(writeQueueContains(*conn, stream->id)); - - // Lose the 3rd dsr packet: - RegularQuicWritePacket packet3(PacketHeader(ShortHeader( - ProtectionType::KeyPhaseZero, conn->serverConnectionId.value(), 3))); - WriteStreamFrame frame3(stream->id, bufMetaStartingOffset + 600, 400, true); - frame3.fromBufMeta = true; - packet3.frames.push_back(frame3); - ASSERT_FALSE( - markPacketLoss(*conn, conn->currentPathId, packet3, false /* processed */) - .hasError()); - EXPECT_EQ(2, stream->lossBufMetas.size()); - const auto& lostBufMeta2 = stream->lossBufMetas.back(); - EXPECT_EQ(bufMetaStartingOffset + 600, lostBufMeta2.offset); - EXPECT_EQ(400, lostBufMeta2.length); - EXPECT_TRUE(lostBufMeta2.eof); - EXPECT_EQ(1, stream->retransmissionBufMetas.size()); - ASSERT_EQ(stream->streamLossCount, 2); - EXPECT_TRUE(conn->streamManager->hasLoss()); - EXPECT_FALSE(stream->hasWritableBufMeta()); - EXPECT_FALSE(conn->streamManager->writableDSRStreams().contains(stream->id)); - EXPECT_TRUE(writeQueueContains(*conn, stream->id)); - - // Lose the 3rd dsr packet, it should be merged together with the first - // element in the lossBufMetas: - RegularQuicWritePacket packet2(PacketHeader(ShortHeader( - ProtectionType::KeyPhaseZero, conn->serverConnectionId.value(), 2))); - WriteStreamFrame frame2(stream->id, bufMetaStartingOffset + 200, 400, false); - frame2.fromBufMeta = true; - packet2.frames.push_back(frame2); - ASSERT_FALSE( - markPacketLoss(*conn, conn->currentPathId, packet2, false /* processed */) - .hasError()); - EXPECT_EQ(2, stream->lossBufMetas.size()); - const auto& lostBufMeta3 = stream->lossBufMetas.front(); - EXPECT_EQ(bufMetaStartingOffset, lostBufMeta3.offset); - EXPECT_EQ(600, lostBufMeta3.length); - EXPECT_FALSE(lostBufMeta3.eof); - EXPECT_EQ(0, stream->retransmissionBufMetas.size()); - ASSERT_EQ(stream->streamLossCount, 3); - EXPECT_TRUE(conn->streamManager->hasLoss()); - EXPECT_FALSE(stream->hasWritableBufMeta()); - EXPECT_FALSE(conn->streamManager->writableDSRStreams().contains(stream->id)); - EXPECT_TRUE(writeQueueContains(*conn, stream->id)); -} - -TEST_F(QuicLossFunctionsTest, TestReorderingThresholdDSRNormal) { - std::vector lostPacket; - auto conn = createConn(); - - auto mockCongestionController = std::make_unique(); - auto rawCongestionController = mockCongestionController.get(); - conn->congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, onPacketSent(_)) - .WillRepeatedly(Return()); - - auto testingLossMarkFunc = - [&lostPacket](auto& /*conn*/, auto /*pathId */, auto& packet, bool) - -> quic::Expected { - auto packetNum = packet.header.getPacketSequenceNum(); - lostPacket.push_back(packetNum); - return {}; - }; - for (int i = 0; i < 6; ++i) { - sendPacket( - *conn, - Clock::now(), - std::nullopt, - PacketType::OneRtt, - std::nullopt, - true); - } - // Add some DSR frames - for (auto& op : conn->outstandings.packets) { - // This matches the stream packet index to the one used by the packet. - op.packet.frames.emplace_back( - WriteStreamFrame{ - 0, - 10, - 100, - false, - true, - std::nullopt, - op.packet.header.getPacketSequenceNum()}); - op.isDSRPacket = true; - conn->outstandings.dsrCount++; - } - EXPECT_EQ(6, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - // Assume some packets are already acked - for (auto iter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 2; - iter < getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5; - iter++) { - conn->outstandings.packetCount[PacketNumberSpace::AppData]--; - } - auto firstAppDataOpIter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); - conn->outstandings.packets.erase( - firstAppDataOpIter + 2, firstAppDataOpIter + 5); - // Ack for packet 9 arrives - auto ack = AckEvent::Builder() - .setPacketNumberSpace(PacketNumberSpace::AppData) - .setLargestAckedPacket(9) - .setIsImplicitAck(false) - .setAckTime(Clock::now()) - .setAdjustedAckTime(Clock::now()) - .setAckDelay(0us) - .build(); - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - detailsPerStream.recordFrameDelivered( - WriteStreamFrame{0, 10, 100, false, true, std::nullopt, 9}); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(9) - .setNonDsrPacketSequenceNumber(0) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata( - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) - ->metadata) - .build()); - auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 9; - auto lossEventResult = detectLossPackets( - *conn, - ackState, - testingLossMarkFunc, - TimePoint(90ms), - PacketNumberSpace::AppData, - &ack); - ASSERT_FALSE(lossEventResult.hasError()); - auto& lossEvent = lossEventResult.value(); - ASSERT_TRUE(lossEvent->largestLostPacketNum.has_value()); - EXPECT_EQ(2, lossEvent->largestLostPacketNum.value()); - EXPECT_EQ(TimePoint(90ms), lossEvent->lossTime); - // Packet 1,2 should be marked as loss - EXPECT_EQ(lostPacket.size(), 2); - EXPECT_EQ(lostPacket.front(), 1); - EXPECT_EQ(lostPacket.back(), 2); - - EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - - // Packet 6 should remain in packet as the delta is less than threshold - auto numDeclaredLost = std::count_if( - conn->outstandings.packets.begin(), - conn->outstandings.packets.end(), - [](auto& op) { return op.declaredLost; }); - EXPECT_EQ(conn->outstandings.packets.size(), 1 + numDeclaredLost); - auto first = getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); - auto packetNum = first->packet.header.getPacketSequenceNum(); - EXPECT_EQ(packetNum, 6); -} - -TEST_F(QuicLossFunctionsTest, TestReorderingThresholdDSRNormalOverflow) { - std::vector lostPacket; - auto conn = createConn(); - - auto mockCongestionController = std::make_unique(); - auto rawCongestionController = mockCongestionController.get(); - conn->congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, onPacketSent(_)) - .WillRepeatedly(Return()); - - auto testingLossMarkFunc = - [&lostPacket](auto& /*conn*/, auto /*pathId*/, auto& packet, bool) - -> quic::Expected { - auto packetNum = packet.header.getPacketSequenceNum(); - lostPacket.push_back(packetNum); - return {}; - }; - for (int i = 0; i < 6; ++i) { - sendPacket( - *conn, - Clock::now(), - std::nullopt, - PacketType::OneRtt, - std::nullopt, - true); - } - // Add some DSR frames - for (auto& op : conn->outstandings.packets) { - op.packet.frames.emplace_back(WriteStreamFrame{0, 10, 100, false, true}); - op.isDSRPacket = true; - conn->outstandings.dsrCount++; - } - EXPECT_EQ(6, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - // Assume some packets are already acked - for (auto iter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 2; - iter < getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5; - iter++) { - conn->outstandings.packetCount[PacketNumberSpace::AppData]--; - } - auto firstAppDataOpIter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); - conn->outstandings.packets.erase( - firstAppDataOpIter + 2, firstAppDataOpIter + 5); - // Ack for packet 9 arrives - auto ack = AckEvent::Builder() - .setPacketNumberSpace(PacketNumberSpace::AppData) - .setLargestAckedPacket(9) - .setIsImplicitAck(false) - .setAckTime(Clock::now()) - .setAdjustedAckTime(Clock::now()) - .setAckDelay(0us) - .build(); - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - detailsPerStream.recordFrameDelivered( - WriteStreamFrame{0, 10, 100, false, true}); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(0) - .setNonDsrPacketSequenceNumber(0) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata( - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) - ->metadata) - .build()); - - auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 9; - auto lossEventResult = detectLossPackets( - *conn, - ackState, - testingLossMarkFunc, - TimePoint(90ms), - PacketNumberSpace::AppData, - &ack); - EXPECT_FALSE(lossEventResult.hasError()); - auto& lossEvent = lossEventResult.value(); - EXPECT_FALSE(lossEvent.has_value()); - - auto numDeclaredLost = std::count_if( - conn->outstandings.packets.begin(), - conn->outstandings.packets.end(), - [](auto& op) { return op.declaredLost; }); - EXPECT_EQ(numDeclaredLost, 0); -} - -TEST_F(QuicLossFunctionsTest, TestReorderingThresholdDSRIgnoreReorder) { - std::vector lostPacket; - auto conn = createConn(); - - auto mockCongestionController = std::make_unique(); - auto rawCongestionController = mockCongestionController.get(); - conn->congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, onPacketSent(_)) - .WillRepeatedly(Return()); - - auto testingLossMarkFunc = - [&lostPacket](auto& /*conn*/, auto /*pathId*/, auto& packet, bool) - -> quic::Expected { - auto packetNum = packet.header.getPacketSequenceNum(); - lostPacket.push_back(packetNum); - return {}; - }; - for (int i = 0; i < 6; ++i) { - sendPacket( - *conn, - Clock::now(), - std::nullopt, - PacketType::OneRtt, - std::nullopt, - true); - } - // Add some DSR frames - for (auto& op : conn->outstandings.packets) { - op.packet.frames.emplace_back( - WriteStreamFrame{ - 0, - 10, - 100, - false, - true, - std::nullopt, - op.packet.header.getPacketSequenceNum()}); - op.isDSRPacket = true; - conn->outstandings.dsrCount++; - } - // Add another non-DSR after - sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); - EXPECT_EQ(7, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - // Assume some packets are already acked - for (auto iter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 2; - iter < getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5; - iter++) { - conn->outstandings.packetCount[PacketNumberSpace::AppData]--; - } - auto firstAppDataOpIter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); - conn->outstandings.packets.erase( - firstAppDataOpIter + 2, firstAppDataOpIter + 5); - // Ack for packet 20 arrives - auto ack = AckEvent::Builder() - .setPacketNumberSpace(PacketNumberSpace::AppData) - .setLargestAckedPacket(20) - .setIsImplicitAck(false) - .setAckTime(Clock::now()) - .setAdjustedAckTime(Clock::now()) - .setAckDelay(0us) - .build(); - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - // Ack a different stream. - detailsPerStream.recordFrameDelivered( - WriteStreamFrame{4, 10, 100, false, true}); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(20) - .setNonDsrPacketSequenceNumber(0) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata( - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) - ->metadata) - .build()); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(19) - .setNonDsrPacketSequenceNumber(19 - 6) - .setDetailsPerStream(AckEvent::AckPacket::DetailsPerStream()) - .setOutstandingPacketMetadata( - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) - ->metadata) - .build()); - auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 20; - auto lossEventResult = detectLossPackets( - *conn, - ackState, - testingLossMarkFunc, - TimePoint(90ms), - PacketNumberSpace::AppData, - &ack); - EXPECT_FALSE(lossEventResult.hasError()); - auto& lossEvent = lossEventResult.value(); - ASSERT_TRUE(lossEvent.has_value()); - - EXPECT_EQ(3, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - - auto numDeclaredLost = std::count_if( - conn->outstandings.packets.begin(), - conn->outstandings.packets.end(), - [](auto& op) { return op.declaredLost; }); - // We should declare the non DSR packet lost. - EXPECT_EQ(1, numDeclaredLost); -} - -TEST_F(QuicLossFunctionsTest, TestReorderingThresholdNonDSRIgnoreReorder) { - std::vector lostPacket; - auto conn = createConn(); - - auto mockCongestionController = std::make_unique(); - auto rawCongestionController = mockCongestionController.get(); - conn->congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, onPacketSent(_)) - .WillRepeatedly(Return()); - - auto testingLossMarkFunc = - [&lostPacket](auto& /*conn*/, auto /*pathId*/, auto& packet, bool) - -> quic::Expected { - auto packetNum = packet.header.getPacketSequenceNum(); - lostPacket.push_back(packetNum); - return {}; - }; - for (int i = 0; i < 6; ++i) { - sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); - } - EXPECT_EQ(6, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - // Assume some packets are already acked - for (auto iter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 2; - iter < getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5; - iter++) { - conn->outstandings.packetCount[PacketNumberSpace::AppData]--; - } - auto firstAppDataOpIter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); - conn->outstandings.packets.erase( - firstAppDataOpIter + 2, firstAppDataOpIter + 5); - // Ack for packet 9 arrives - auto ack = AckEvent::Builder() - .setPacketNumberSpace(PacketNumberSpace::AppData) - .setLargestAckedPacket(9) - .setIsImplicitAck(false) - .setAckTime(Clock::now()) - .setAdjustedAckTime(Clock::now()) - .setAckDelay(0us) - .build(); - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - // Ack a different stream. - detailsPerStream.recordFrameDelivered( - WriteStreamFrame{4, 10, 100, false, true}); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(9) - .setNonDsrPacketSequenceNumber(9) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata( - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) - ->metadata) - .build()); - - auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 9; - auto lossEventResult = detectLossPackets( - *conn, - ackState, - testingLossMarkFunc, - TimePoint(90ms), - PacketNumberSpace::AppData, - &ack); - EXPECT_FALSE(lossEventResult.hasError()); - auto& lossEvent = lossEventResult.value(); - EXPECT_FALSE(lossEvent.has_value()); - - EXPECT_EQ(3, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - - auto numDeclaredLost = std::count_if( - conn->outstandings.packets.begin(), - conn->outstandings.packets.end(), - [](auto& op) { return op.declaredLost; }); - EXPECT_EQ(0, numDeclaredLost); - EXPECT_EQ(conn->outstandings.packets.size(), 3); -} - -TEST_F( - QuicLossFunctionsTest, - TestReorderingThresholdNonDSRIgnoreReorderOverflow) { - std::vector lostPacket; - auto conn = createConn(); - - auto mockCongestionController = std::make_unique(); - auto rawCongestionController = mockCongestionController.get(); - conn->congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, onPacketSent(_)) - .WillRepeatedly(Return()); - - auto testingLossMarkFunc = - [&lostPacket](auto& /*conn*/, auto /*pathId*/, auto& packet, bool) - -> quic::Expected { - auto packetNum = packet.header.getPacketSequenceNum(); - lostPacket.push_back(packetNum); - return {}; - }; - for (int i = 0; i < 6; ++i) { - sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); - } - EXPECT_EQ(6, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - // Assume some packets are already acked - for (auto iter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 2; - iter < getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5; - iter++) { - conn->outstandings.packetCount[PacketNumberSpace::AppData]--; - } - auto firstAppDataOpIter = - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); - conn->outstandings.packets.erase( - firstAppDataOpIter + 2, firstAppDataOpIter + 5); - // Ack for packet 0 arrives - auto ack = AckEvent::Builder() - .setPacketNumberSpace(PacketNumberSpace::AppData) - .setLargestAckedPacket(9) - .setIsImplicitAck(false) - .setAckTime(Clock::now()) - .setAdjustedAckTime(Clock::now()) - .setAckDelay(0us) - .build(); - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - detailsPerStream.recordFrameDelivered( - WriteStreamFrame{4, 10, 100, false, true}); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(9) - .setNonDsrPacketSequenceNumber(9) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata( - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) - ->metadata) - .build()); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(0) - .setNonDsrPacketSequenceNumber(0) - .setOutstandingPacketMetadata( - getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) - ->metadata) - .setDetailsPerStream(AckEvent::AckPacket::DetailsPerStream()) - .build()); - - auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 9; - auto lossEventResult = detectLossPackets( - *conn, - ackState, - testingLossMarkFunc, - TimePoint(90ms), - PacketNumberSpace::AppData, - &ack); - EXPECT_FALSE(lossEventResult.hasError()); - auto& lossEvent = lossEventResult.value(); - EXPECT_FALSE(lossEvent.has_value()); - - EXPECT_EQ(3, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - - auto numDeclaredLost = std::count_if( - conn->outstandings.packets.begin(), - conn->outstandings.packets.end(), - [](auto& op) { return op.declaredLost; }); - EXPECT_EQ(0, numDeclaredLost); - EXPECT_EQ(conn->outstandings.packets.size(), 3); -} - -TEST_F(QuicLossFunctionsTest, TestReorderingThresholdDSRIgnoreReorderBurst) { - std::vector lostPacket; - auto conn = createConn(); - - auto mockCongestionController = std::make_unique(); - auto rawCongestionController = mockCongestionController.get(); - conn->congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, onPacketSent(_)) - .WillRepeatedly(Return()); - - auto testingLossMarkFunc = - [&lostPacket](auto& /*conn*/, auto /*pathId*/, auto& packet, bool) - -> quic::Expected { - auto packetNum = packet.header.getPacketSequenceNum(); - lostPacket.push_back(packetNum); - return {}; - }; - for (int i = 0; i < 4; ++i) { - sendPacket( - *conn, - Clock::now(), - std::nullopt, - PacketType::OneRtt, - std::nullopt, - true); - } - // Add some DSR frames and build the ACK - auto ack = AckEvent::Builder() - .setPacketNumberSpace(PacketNumberSpace::AppData) - .setLargestAckedPacket(9) - .setIsImplicitAck(false) - .setAckTime(Clock::now()) - .setAdjustedAckTime(Clock::now()) - .setAckDelay(0us) - .build(); - for (auto& op : conn->outstandings.packets) { - WriteStreamFrame f{ - 0, - 10, - 100, - false, - true, - std::nullopt, - op.packet.header.getPacketSequenceNum()}; - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - if (op.packet.header.getPacketSequenceNum() != 4) { - detailsPerStream.recordFrameDelivered(f); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(op.packet.header.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber(0) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata(op.metadata) - .build()); - } - op.packet.frames.emplace_back(f); - op.isDSRPacket = true; - conn->outstandings.dsrCount++; - } - // Add another non-DSR burst and ACK all of them - for (int i = 0; i < 4; ++i) { - sendPacket( - *conn, - Clock::now(), - std::nullopt, - PacketType::OneRtt, - std::nullopt, - false); - auto& op = *getLastOutstandingPacket(*conn, PacketNumberSpace::AppData); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(op.packet.header.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber( - op.nonDsrPacketSequenceNumber.value()) - .setDetailsPerStream({}) - .setOutstandingPacketMetadata(op.metadata) - .build()); - } - // Add one more DSR packet from the same stream, ACKed - sendPacket( - *conn, - Clock::now(), - std::nullopt, - PacketType::OneRtt, - std::nullopt, - true); - auto& op = *getLastOutstandingPacket(*conn, PacketNumberSpace::AppData); - WriteStreamFrame f{0, 10, 100, false, true, std::nullopt, 5}; - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - detailsPerStream.recordFrameDelivered(f); - op.packet.frames.emplace_back(f); - op.isDSRPacket = true; - conn->outstandings.dsrCount++; - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(op.packet.header.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber(0) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata(op.metadata) - .build()); - - ASSERT_EQ(9, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - // ACK everything that isn't packet 4. - auto itr = getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); - while (itr != conn->outstandings.packets.end()) { - if (itr->packet.header.getPacketSequenceNum() != 4) { - itr = conn->outstandings.packets.erase(itr); - conn->outstandings.packetCount[PacketNumberSpace::AppData]--; - } else { - itr++; - } - } - auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 10; - auto lossEventResult = detectLossPackets( - *conn, - ackState, - testingLossMarkFunc, - TimePoint(90ms), - PacketNumberSpace::AppData, - &ack); - EXPECT_FALSE(lossEventResult.hasError()); - auto& lossEvent = lossEventResult.value(); - EXPECT_FALSE(lossEvent.has_value()); - EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - auto numDeclaredLost = std::count_if( - conn->outstandings.packets.begin(), - conn->outstandings.packets.end(), - [](auto& op) { return op.declaredLost; }); - // The DSR packet before the burst shouldn't be lost. - EXPECT_EQ(0, numDeclaredLost); -} - -TEST_F(QuicLossFunctionsTest, TestReorderingThresholdNonDSRIgnoreReorderBurst) { - std::vector lostPacket; - auto conn = createConn(); - - auto mockCongestionController = std::make_unique(); - auto rawCongestionController = mockCongestionController.get(); - conn->congestionController = std::move(mockCongestionController); - EXPECT_CALL(*rawCongestionController, onPacketSent(_)) - .WillRepeatedly(Return()); - - auto testingLossMarkFunc = - [&lostPacket](auto& /*conn*/, auto /*pathId*/, auto& packet, bool) - -> quic::Expected { - auto packetNum = packet.header.getPacketSequenceNum(); - lostPacket.push_back(packetNum); - return {}; - }; - for (int i = 0; i < 4; ++i) { - sendPacket( - *conn, - Clock::now(), - std::nullopt, - PacketType::OneRtt, - std::nullopt, - false); - } - // Add some non-DSR frames and build the ACK - auto ack = AckEvent::Builder() - .setPacketNumberSpace(PacketNumberSpace::AppData) - .setLargestAckedPacket(9) - .setIsImplicitAck(false) - .setAckTime(Clock::now()) - .setAdjustedAckTime(Clock::now()) - .setAckDelay(0us) - .build(); - for (auto& op : conn->outstandings.packets) { - WriteStreamFrame f{0, 10, 100, false, false, std::nullopt, 0}; - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - if (op.packet.header.getPacketSequenceNum() != 4) { - detailsPerStream.recordFrameDelivered(f); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(op.packet.header.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber( - op.nonDsrPacketSequenceNumber.value()) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata(op.metadata) - .build()); - } - op.packet.frames.emplace_back(f); - } - // Add a DSR burst and ACK all of them - for (int i = 0; i < 4; ++i) { - sendPacket( - *conn, - Clock::now(), - std::nullopt, - PacketType::OneRtt, - std::nullopt, - true); - auto& op = *getLastOutstandingPacket(*conn, PacketNumberSpace::AppData); - WriteStreamFrame f{ - 4, 10, 100, false, true, std::nullopt, conn->outstandings.dsrCount++}; - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - detailsPerStream.recordFrameDelivered(f); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(op.packet.header.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber(0) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata(op.metadata) - .build()); - op.packet.frames.emplace_back(f); - op.isDSRPacket = true; - } - // Add one more non-DSR packet from the same stream, ACKed - sendPacket(*conn, Clock::now(), std::nullopt, PacketType::OneRtt); - auto& op = *getLastOutstandingPacket(*conn, PacketNumberSpace::AppData); - WriteStreamFrame f{0, 10, 100, false, false, std::nullopt, 0}; - AckEvent::AckPacket::DetailsPerStream detailsPerStream; - detailsPerStream.recordFrameDelivered(f); - op.packet.frames.emplace_back(f); - ack.ackedPackets.emplace_back( - CongestionController::AckEvent::AckPacket::Builder() - .setPacketNum(op.packet.header.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber(op.nonDsrPacketSequenceNumber.value()) - .setDetailsPerStream(std::move(detailsPerStream)) - .setOutstandingPacketMetadata(op.metadata) - .build()); - - ASSERT_EQ(9, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - // ACK everything that isn't packet 4. - auto itr = getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData); - while (itr != conn->outstandings.packets.end()) { - if (itr->packet.header.getPacketSequenceNum() != 4) { - itr = conn->outstandings.packets.erase(itr); - conn->outstandings.packetCount[PacketNumberSpace::AppData]--; - } else { - itr++; - } - } - auto& ackState = getAckState(*conn, PacketNumberSpace::AppData); - ackState.largestAckedByPeer = - ackState.largestNonDsrSequenceNumberAckedByPeer = 10; - auto lossEventResult = detectLossPackets( - *conn, - ackState, - testingLossMarkFunc, - TimePoint(90ms), - PacketNumberSpace::AppData, - &ack); - EXPECT_FALSE(lossEventResult.hasError()); - auto& lossEvent = lossEventResult.value(); - EXPECT_FALSE(lossEvent.has_value()); - EXPECT_EQ(1, conn->outstandings.packetCount[PacketNumberSpace::AppData]); - auto numDeclaredLost = std::count_if( - conn->outstandings.packets.begin(), - conn->outstandings.packets.end(), - [](auto& op) { return op.declaredLost; }); - // The non-DSR packet before the burst shouldn't be lost. - EXPECT_EQ(0, numDeclaredLost); -} - -INSTANTIATE_TEST_SUITE_P( - QuicLossFunctionsTests, - QuicLossFunctionsTest, - Values( - PacketNumberSpace::Initial, - PacketNumberSpace::Handshake, - PacketNumberSpace::AppData)); - TEST_F(QuicLossFunctionsTest, TestMarkPacketLossRetransmissionDisabled) { folly::EventBase evb; auto qEvb = std::make_shared(&evb); diff --git a/quic/samples/echo/LogQuicStats.h b/quic/samples/echo/LogQuicStats.h index dce7e9bad..ef18985dc 100644 --- a/quic/samples/echo/LogQuicStats.h +++ b/quic/samples/echo/LogQuicStats.h @@ -44,10 +44,6 @@ class LogQuicStats : public quic::QuicTransportStatsCallback { VLOG(2) << prefix_ << __func__; } - void onDSRPacketSent(size_t pktSize) override { - VLOG(2) << prefix_ << __func__ << " size=" << pktSize; - } - void onPacketRetransmission() override { VLOG(2) << prefix_ << __func__; } diff --git a/quic/server/BUCK b/quic/server/BUCK index 54082ce7b..7a28b6601 100644 --- a/quic/server/BUCK +++ b/quic/server/BUCK @@ -70,7 +70,6 @@ mvfst_cpp_library( "//quic/common:socket_util", "//quic/congestion_control:bbr", "//quic/congestion_control:copa", - "//quic/dsr/frontend:write_functions", "//quic/fizz/handshake:fizz_handshake", "//quic/fizz/server/handshake:fizz_server_handshake", "//quic/priority:http_priority_queue", diff --git a/quic/server/CMakeLists.txt b/quic/server/CMakeLists.txt index df59f00b7..25f08371c 100644 --- a/quic/server/CMakeLists.txt +++ b/quic/server/CMakeLists.txt @@ -34,7 +34,6 @@ add_dependencies( mvfst_codec mvfst_codec_types mvfst_folly_utils - mvfst_dsr_frontend mvfst_fizz_handshake mvfst_qlogger mvfst_state_ack_handler @@ -81,7 +80,6 @@ add_dependencies( mvfst_codec mvfst_codec_types mvfst_folly_utils - mvfst_dsr_frontend mvfst_fizz_handshake mvfst_qlogger mvfst_server_state @@ -122,7 +120,6 @@ add_dependencies( mvfst_codec mvfst_codec_types mvfst_folly_utils - mvfst_dsr_frontend mvfst_fizz_handshake mvfst_qlogger mvfst_state_ack_handler @@ -137,7 +134,6 @@ target_link_libraries( mvfst_codec mvfst_codec_types mvfst_folly_utils - mvfst_dsr_frontend mvfst_fizz_handshake mvfst_qlogger mvfst_state_ack_handler @@ -154,7 +150,6 @@ target_link_libraries( mvfst_codec mvfst_codec_types mvfst_folly_utils - mvfst_dsr_frontend mvfst_fizz_handshake mvfst_qlogger mvfst_server_state @@ -175,7 +170,6 @@ target_link_libraries( mvfst_codec mvfst_codec_types mvfst_folly_utils - mvfst_dsr_frontend mvfst_fizz_handshake mvfst_qlogger mvfst_server_state diff --git a/quic/server/QuicServerTransport.cpp b/quic/server/QuicServerTransport.cpp index 4753dff95..10ec8c685 100644 --- a/quic/server/QuicServerTransport.cpp +++ b/quic/server/QuicServerTransport.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -342,24 +341,6 @@ quic::Expected QuicServerTransport::writeData() { } return result.value(); }; - auto dsrPath = - [&](auto limit) -> quic::Expected { - auto bytesBefore = conn_->lossState.totalBytesSent; - // The DSR path can't write probes. - // This is packetsWritte, probesWritten, bytesWritten. - auto dsrResult = writePacketizationRequest( - *serverConn_, - destConnId, - limit, - *conn_->oneRttWriteCipher, - writeLoopBeginTime); - if (dsrResult.hasError()) { - return quic::make_unexpected(dsrResult.error()); - } - auto result = WriteQuicDataResult{ - dsrResult.value(), 0, conn_->lossState.totalBytesSent - bytesBefore}; - return result; - }; auto pathValidationWrites = [&](auto limit) -> quic::Expected { auto result = writePathValidationDataForAlternatePaths( @@ -377,30 +358,16 @@ quic::Expected QuicServerTransport::writeData() { } return result.value(); }; - // We need a while loop because both paths write streams from the same - // queue, which can result in empty writes. + // We need a while loop because we might get empty writes. while (packetLimit) { auto totalSentBefore = conn_->lossState.totalBytesSent; - // Give the non-DSR path a chance first for things like ACKs and flow - // control. auto written = nonDsrPath(packetLimit); if (written.hasError()) { return quic::make_unexpected(written.error()); } - // For both paths we only consider full packets against the packet - // limit. While this is slightly more aggressive than the intended - // packet limit it also helps ensure that small packets don't cause - // us to underutilize the link when mixing between DSR and non-DSR. packetLimit -= written->bytesWritten / conn_->udpSendPacketLen; - if (packetLimit && congestionControlWritableBytes(*serverConn_)) { - auto dsrWritten = dsrPath(packetLimit); - if (dsrWritten.hasError()) { - return quic::make_unexpected(dsrWritten.error()); - } - packetLimit -= dsrWritten->bytesWritten / conn_->udpSendPacketLen; - } if (totalSentBefore == conn_->lossState.totalBytesSent) { - // We haven't written anything with either path, so we're done. + // We haven't written anything, so we're done. break; } } @@ -1351,173 +1318,6 @@ QuicConnectionStats QuicServerTransport::getConnectionsStats() const { return connStats; } -QuicSocket::WriteResult QuicServerTransport::writeBufMeta( - StreamId id, - const BufferMeta& data, - bool eof, - ByteEventCallback* cb) { - if (isReceivingStream(conn_->nodeType, id)) { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - if (closeState_ != CloseState::OPEN) { - return quic::make_unexpected(LocalErrorCode::CONNECTION_CLOSED); - } - [[maybe_unused]] auto self = sharedGuard(); - try { - // Check whether stream exists before calling getStream to avoid - // creating a peer stream if it does not exist yet. - if (!conn_->streamManager->streamExists(id)) { - return quic::make_unexpected(LocalErrorCode::STREAM_NOT_EXISTS); - } - auto stream = - CHECK_NOTNULL(conn_->streamManager->getStream(id).value_or(nullptr)); - if (!stream->writable()) { - return quic::make_unexpected(LocalErrorCode::STREAM_CLOSED); - } - if (!stream->dsrSender) { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - if (stream->currentWriteOffset == 0 && stream->pendingWrites.empty()) { - // If nothing has been written ever, meta writing isn't allowed. - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - // Register DeliveryCallback for the data + eof offset. - if (cb) { - auto dataLength = data.length + (eof ? 1 : 0); - if (dataLength) { - auto currentLargestWriteOffset = getLargestWriteOffsetSeen(*stream); - auto deliveryResult = registerDeliveryCallback( - id, currentLargestWriteOffset + dataLength - 1, cb); - if (!deliveryResult.has_value()) { - VLOG(4) << "Failed to register delivery callback: " - << toString(deliveryResult.error()); - exceptionCloseWhat_ = "Failed to register delivery callback"; - closeImpl(QuicError( - deliveryResult.error(), - std::string("registerDeliveryCallback() error"))); - return quic::make_unexpected(LocalErrorCode::TRANSPORT_ERROR); - } - } - } - bool wasAppLimitedOrIdle = false; - if (conn_->congestionController) { - wasAppLimitedOrIdle = conn_->congestionController->isAppLimited(); - wasAppLimitedOrIdle |= conn_->streamManager->isAppIdle(); - } - auto writeResult = writeBufMetaToQuicStream(*stream, data, eof); - if (!writeResult.has_value()) { - VLOG(4) << __func__ << " streamId=" << id << " " - << writeResult.error().message << " " << *this; - exceptionCloseWhat_ = writeResult.error().message; - closeImpl(QuicError( - QuicErrorCode(*writeResult.error().code.asTransportErrorCode()), - std::string("writeChain() error"))); - return quic::make_unexpected(LocalErrorCode::TRANSPORT_ERROR); - } - // If we were previously app limited restart pacing with the current rate. - if (wasAppLimitedOrIdle && conn_->pacer) { - conn_->pacer->reset(); - } - updateWriteLooper(true); - } catch (const QuicTransportException& ex) { - VLOG(4) << __func__ << " streamId=" << id << " " << ex.what() << " " - << *this; - exceptionCloseWhat_ = ex.what(); - closeImpl(QuicError( - QuicErrorCode(ex.errorCode()), std::string("writeChain() error"))); - return quic::make_unexpected(LocalErrorCode::TRANSPORT_ERROR); - } catch (const QuicInternalException& ex) { - VLOG(4) << __func__ << " streamId=" << id << " " << ex.what() << " " - << *this; - exceptionCloseWhat_ = ex.what(); - closeImpl(QuicError( - QuicErrorCode(ex.errorCode()), std::string("writeChain() error"))); - return quic::make_unexpected(ex.errorCode()); - } catch (const std::exception& ex) { - VLOG(4) << __func__ << " streamId=" << id << " " << ex.what() << " " - << *this; - exceptionCloseWhat_ = ex.what(); - closeImpl(QuicError( - QuicErrorCode(TransportErrorCode::INTERNAL_ERROR), - std::string("writeChain() error"))); - return quic::make_unexpected(LocalErrorCode::INTERNAL_ERROR); - } - return {}; -} - -QuicSocket::WriteResult QuicServerTransport::setDSRPacketizationRequestSender( - StreamId id, - std::unique_ptr sender) { - if (closeState_ != CloseState::OPEN) { - return quic::make_unexpected(LocalErrorCode::CONNECTION_CLOSED); - } - if (isReceivingStream(conn_->nodeType, id)) { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - [[maybe_unused]] auto self = sharedGuard(); - try { - // Check whether stream exists before calling getStream to avoid - // creating a peer stream if it does not exist yet. - if (!conn_->streamManager->streamExists(id)) { - return quic::make_unexpected(LocalErrorCode::STREAM_NOT_EXISTS); - } - auto stream = - CHECK_NOTNULL(conn_->streamManager->getStream(id).value_or(nullptr)); - // Only allow resetting it back to nullptr once set. - if (stream->dsrSender && sender != nullptr) { - return quic::make_unexpected(LocalErrorCode::INVALID_OPERATION); - } - if (stream->dsrSender != nullptr) { - // If any of these aren't true then we are abandoning stream data. - CHECK_EQ(stream->writeBufMeta.length, 0) << stream; - CHECK_EQ(stream->lossBufMetas.size(), 0) << stream; - CHECK_EQ(stream->retransmissionBufMetas.size(), 0) << stream; - stream->dsrSender->release(); - stream->dsrSender = nullptr; - return {}; - } - if (!stream->writable()) { - return quic::make_unexpected(LocalErrorCode::STREAM_CLOSED); - } - stream->dsrSender = std::move(sender); - // Default to disabling opportunistic ACKing for DSR since it causes extra - // writes and spurious losses. - conn_->transportSettings.opportunisticAcking = false; - // Also turn on the default of 5 nexts per stream which has empirically - // shown good results. - if (conn_->transportSettings.priorityQueueWritesPerStream == 1) { - conn_->transportSettings.priorityQueueWritesPerStream = 5; - conn_->streamManager->setWriteQueueMaxNextsPerStream(5); - } - - // Fow now, no appLimited or appIdle update here since we are not writing - // either BufferMetas yet. The first BufferMeta write will update it. - } catch (const QuicTransportException& ex) { - VLOG(4) << __func__ << " streamId=" << id << " " << ex.what() << " " - << *this; - exceptionCloseWhat_ = ex.what(); - closeImpl(QuicError( - QuicErrorCode(ex.errorCode()), std::string("writeChain() error"))); - return quic::make_unexpected(LocalErrorCode::TRANSPORT_ERROR); - } catch (const QuicInternalException& ex) { - VLOG(4) << __func__ << " streamId=" << id << " " << ex.what() << " " - << *this; - exceptionCloseWhat_ = ex.what(); - closeImpl(QuicError( - QuicErrorCode(ex.errorCode()), std::string("writeChain() error"))); - return quic::make_unexpected(ex.errorCode()); - } catch (const std::exception& ex) { - VLOG(4) << __func__ << " streamId=" << id << " " << ex.what() << " " - << *this; - exceptionCloseWhat_ = ex.what(); - closeImpl(QuicError( - QuicErrorCode(TransportErrorCode::INTERNAL_ERROR), - std::string("writeChain() error"))); - return quic::make_unexpected(LocalErrorCode::INTERNAL_ERROR); - } - return {}; -} - CipherInfo QuicServerTransport::getOneRttCipherInfo() const { return { *conn_->oneRttWriteCipher->getKey(), diff --git a/quic/server/QuicServerTransport.h b/quic/server/QuicServerTransport.h index ce39490f7..050f91016 100644 --- a/quic/server/QuicServerTransport.h +++ b/quic/server/QuicServerTransport.h @@ -159,16 +159,6 @@ class QuicServerTransport std::shared_ptr sharedGuard() override; QuicConnectionStats getConnectionsStats() const override; - WriteResult writeBufMeta( - StreamId /* id */, - const BufferMeta& /* data */, - bool /* eof */, - ByteEventCallback* cb = nullptr) override; - - WriteResult setDSRPacketizationRequestSender( - StreamId /* id */, - std::unique_ptr /* sender */) override; - const fizz::server::FizzServerContext& getCtx() { return *ctx_; } diff --git a/quic/server/test/BUCK b/quic/server/test/BUCK index 13fa7ae3e..335696ac4 100644 --- a/quic/server/test/BUCK +++ b/quic/server/test/BUCK @@ -86,8 +86,6 @@ fb_dirsync_cpp_unittest( "//quic:constants", "//quic/codec:pktbuilder", "//quic/common:transport_knobs", - "//quic/dsr:types", - "//quic/dsr/test:mocks", "//quic/fizz/handshake:fizz_handshake", "//quic/logging:file_qlogger", "//quic/priority:http_priority_queue", @@ -107,7 +105,6 @@ fb_dirsync_cpp_unittest( ":quic_server_transport_test_util", "//quic:constants", "//quic/codec:pktbuilder", - "//quic/dsr:types", "//quic/logging:file_qlogger", "//quic/priority:http_priority_queue", "//quic/state/test:mocks", diff --git a/quic/server/test/QuicServerTransportMigrationTest.cpp b/quic/server/test/QuicServerTransportMigrationTest.cpp index b033809ee..ee64ce23a 100644 --- a/quic/server/test/QuicServerTransportMigrationTest.cpp +++ b/quic/server/test/QuicServerTransportMigrationTest.cpp @@ -10,8 +10,6 @@ #include #include -#include - #include #include diff --git a/quic/server/test/QuicServerTransportTest.cpp b/quic/server/test/QuicServerTransportTest.cpp index a231a487f..022a8c260 100644 --- a/quic/server/test/QuicServerTransportTest.cpp +++ b/quic/server/test/QuicServerTransportTest.cpp @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include #include @@ -2176,235 +2174,6 @@ TEST_F(QuicServerTransportTest, RecvNewConnectionIdExceptionInvalidDuplicate) { EXPECT_THROW(deliverData(packetToBuf(packet)), std::runtime_error); } -TEST_F(QuicServerTransportTest, WriteBufMetaWithoutRealData) { - auto streamId = server->createBidirectionalStream().value(); - size_t bufferLength = 2000; - BufferMeta meta(bufferLength); - auto result = server->writeBufMeta(streamId, meta, true); - EXPECT_TRUE(result.hasError()); -} - -TEST_F(QuicServerTransportTest, ResetDSRStream) { - auto& conn = server->getConnectionState(); - server->getNonConstConn().transportSettings.writeConnectionDataPacketsLimit = - 1; - auto streamId = server->createBidirectionalStream().value(); - BufferMeta meta(conn.udpSendPacketLen * 5); - auto buf = buildRandomInputData(200); - auto dsrSender = std::make_unique(); - EXPECT_CALL(*dsrSender, release()).Times(1); - auto serverSetDSRSender1 = - server->setDSRPacketizationRequestSender(streamId, std::move(dsrSender)); - EXPECT_TRUE(server->writeChain(streamId, std::move(buf), false).has_value()); - auto streamResult = conn.streamManager->getStream(streamId); - ASSERT_FALSE(streamResult.hasError()); - auto stream = streamResult.value(); - EXPECT_TRUE(server->writeBufMeta(streamId, meta, false).has_value()); - loopForWrites(); - ASSERT_NE(stream, nullptr); - stream->writeBufMeta.split(conn.udpSendPacketLen - 200); - - auto serverResetStream2 = - server->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN); - loopForWrites(); - auto packet = getLastOutstandingPacket( - server->getConnectionState(), PacketNumberSpace::AppData) - ->packet; - EXPECT_GE(packet.frames.size(), 1); - - bool foundReset = false; - for (auto& frame : packet.frames) { - auto rstStream = frame.asRstStreamFrame(); - if (!rstStream) { - continue; - } - EXPECT_EQ(streamId, rstStream->streamId); - EXPECT_GT(rstStream->finalSize, 200); - EXPECT_EQ(GenericApplicationErrorCode::UNKNOWN, rstStream->errorCode); - foundReset = true; - } - EXPECT_TRUE(foundReset); -} - -TEST_F(QuicServerTransportTest, SetDSRSenderAndWriteBufMetaIntoStream) { - auto streamId = server->createBidirectionalStream().value(); - size_t bufferLength = 2000; - BufferMeta meta(bufferLength); - auto buf = buildRandomInputData(20); - auto dsrSender = std::make_unique(); - auto serverSetDSRSender2 = - server->setDSRPacketizationRequestSender(streamId, std::move(dsrSender)); - // Some amount of real data needs to be written first: - auto serverWriteChain12 = server->writeChain(streamId, std::move(buf), false); - auto serverWriteBufMeta1 = server->writeBufMeta(streamId, meta, true); - auto& stream = - *server->getConnectionState().streamManager->findStream(streamId); - EXPECT_GE(stream.writeBufMeta.offset, 20); - EXPECT_EQ(stream.writeBufMeta.length, bufferLength); - EXPECT_TRUE(stream.writeBufMeta.eof); - EXPECT_EQ( - *stream.finalWriteOffset, - stream.writeBufMeta.offset + stream.writeBufMeta.length); -} - -TEST_F(QuicServerTransportTest, InvokeTxCallbacksSingleByteDSR) { - StrictMock firstByteTxCb; - StrictMock dsrByteTxCb; - StrictMock lastByteTxCb; - StrictMock pastlastByteTxCb; - auto stream = server->createBidirectionalStream().value(); - auto dsrSender = std::make_unique(); - auto serverSetDSRSender3 = - server->setDSRPacketizationRequestSender(stream, std::move(dsrSender)); - - auto buf = buildRandomInputData(1); - auto serverWriteChain13 = - server->writeChain(stream, buf->clone(), false /* eof */); - auto serverWriteBufMeta2 = server->writeBufMeta(stream, BufferMeta(1), false); - EXPECT_CALL(firstByteTxCb, onByteEventRegistered(getTxMatcher(stream, 0))) - .Times(1); - EXPECT_CALL(dsrByteTxCb, onByteEventRegistered(getTxMatcher(stream, 1))) - .Times(1); - EXPECT_CALL(lastByteTxCb, onByteEventRegistered(getTxMatcher(stream, 1))) - .Times(1); - EXPECT_CALL(pastlastByteTxCb, onByteEventRegistered(getTxMatcher(stream, 2))) - .Times(1); - auto serverRegisterTxCallback1 = - server->registerTxCallback(stream, 0, &firstByteTxCb); - auto serverRegisterTxCallback2 = - server->registerTxCallback(stream, 1, &dsrByteTxCb); - auto serverRegisterTxCallback3 = - server->registerTxCallback(stream, 1, &lastByteTxCb); - auto serverRegisterTxCallback4 = - server->registerTxCallback(stream, 2, &pastlastByteTxCb); - Mock::VerifyAndClearExpectations(&firstByteTxCb); - Mock::VerifyAndClearExpectations(&dsrByteTxCb); - Mock::VerifyAndClearExpectations(&lastByteTxCb); - Mock::VerifyAndClearExpectations(&pastlastByteTxCb); - - // first and last byte TX callbacks should be triggered immediately - EXPECT_CALL(firstByteTxCb, onByteEvent(getTxMatcher(stream, 0))).Times(1); - EXPECT_CALL(dsrByteTxCb, onByteEvent(getTxMatcher(stream, 1))).Times(1); - EXPECT_CALL(lastByteTxCb, onByteEvent(getTxMatcher(stream, 1))).Times(1); - server->getConnectionState().oneRttWriteCipher = test::createNoOpAead(); - auto temp = test::createNoOpHeaderCipher().value(); - temp->setDefaultKey(); - server->getConnectionState().oneRttWriteHeaderCipher = std::move(temp); - CHECK(server->getConnectionState().oneRttWriteCipher->getKey().has_value()); - CHECK(server->getConnectionState().oneRttWriteHeaderCipher); - loopForWrites(); - Mock::VerifyAndClearExpectations(&firstByteTxCb); - Mock::VerifyAndClearExpectations(&lastByteTxCb); - Mock::VerifyAndClearExpectations(&pastlastByteTxCb); - - // try to set the first and last byte offsets again - // callbacks should be triggered immediately - EXPECT_CALL(firstByteTxCb, onByteEventRegistered(getTxMatcher(stream, 0))) - .Times(1); - EXPECT_CALL(dsrByteTxCb, onByteEventRegistered(getTxMatcher(stream, 1))) - .Times(1); - EXPECT_CALL(lastByteTxCb, onByteEventRegistered(getTxMatcher(stream, 1))) - .Times(1); - auto serverRegisterTxCallback5 = - server->registerTxCallback(stream, 0, &firstByteTxCb); - auto serverRegisterTxCallback6 = - server->registerTxCallback(stream, 1, &dsrByteTxCb); - auto serverRegisterTxCallback7 = - server->registerTxCallback(stream, 1, &lastByteTxCb); - Mock::VerifyAndClearExpectations(&firstByteTxCb); - Mock::VerifyAndClearExpectations(&dsrByteTxCb); - Mock::VerifyAndClearExpectations(&lastByteTxCb); - EXPECT_CALL(firstByteTxCb, onByteEvent(getTxMatcher(stream, 0))).Times(1); - EXPECT_CALL(dsrByteTxCb, onByteEvent(getTxMatcher(stream, 1))).Times(1); - EXPECT_CALL(lastByteTxCb, onByteEvent(getTxMatcher(stream, 1))).Times(1); - loopForWrites(); // have to loop since processed async - Mock::VerifyAndClearExpectations(&firstByteTxCb); - Mock::VerifyAndClearExpectations(&dsrByteTxCb); - Mock::VerifyAndClearExpectations(&lastByteTxCb); - - // Even if we register pastlastByte again, it shouldn't trigger - // onByteEventRegistered because this is a duplicate registration. - EXPECT_CALL(pastlastByteTxCb, onByteEventRegistered(getTxMatcher(stream, 2))) - .Times(0); - auto ret = server->registerTxCallback(stream, 2, &pastlastByteTxCb); - EXPECT_EQ(LocalErrorCode::INVALID_OPERATION, ret.error()); - Mock::VerifyAndClearExpectations(&pastlastByteTxCb); - - // pastlastByteTxCb::onByteEvent will never get called - // cancel gets called instead - // Even though we attempted to register the ByteEvent twice, it resulted in - // an error. So, onByteEventCanceled should be called only once. - EXPECT_CALL(pastlastByteTxCb, onByteEventCanceled(getTxMatcher(stream, 2))) - .Times(1); - server->close(std::nullopt); - Mock::VerifyAndClearExpectations(&pastlastByteTxCb); -} - -TEST_F(QuicServerTransportTest, InvokeDeliveryCallbacksSingleByteWithDSR) { - // register all possible ways to get a DeliveryCb - // - // applications built atop QUIC may capture both first and last byte timings, - // which in this test are the same byte - StrictMock writeChainDeliveryCb; - StrictMock writeBufMetaDeliveryCb; - StrictMock firstByteDeliveryCb; - StrictMock lastByteDeliveryCb; - StrictMock unsentByteDeliveryCb; - auto stream = server->createBidirectionalStream().value(); - auto dsrSender = std::make_unique(); - auto serverSetDSRSender4 = - server->setDSRPacketizationRequestSender(stream, std::move(dsrSender)); - - auto buf = buildRandomInputData(1); - auto serverWriteChain14 = server->writeChain( - stream, buf->clone(), false /* eof */, &writeChainDeliveryCb); - auto serverWriteBufMeta3 = server->writeBufMeta( - stream, BufferMeta(1), false, &writeBufMetaDeliveryCb); - auto serverRegisterDelivery1 = - server->registerDeliveryCallback(stream, 0, &firstByteDeliveryCb); - auto serverRegisterDelivery2 = - server->registerDeliveryCallback(stream, 1, &lastByteDeliveryCb); - auto serverRegisterDelivery3 = - server->registerDeliveryCallback(stream, 2, &unsentByteDeliveryCb); - - // writeChain, first, last byte callbacks triggered after delivery - auto& conn = server->getConnectionState(); - folly::SocketAddress lAddr, rAddr; - conn.streamManager->addDeliverable(stream); - conn.lossState.srtt = 100us; - NetworkData networkData; - auto streamState = conn.streamManager->getStream(stream); - ASSERT_FALSE(streamState.hasError()); - streamState.value()->ackedIntervals.insert(0, 1); - EXPECT_CALL(writeChainDeliveryCb, onDeliveryAck(stream, 0, 100us)).Times(1); - EXPECT_CALL(writeBufMetaDeliveryCb, onDeliveryAck(stream, 1, 100us)).Times(1); - EXPECT_CALL(firstByteDeliveryCb, onDeliveryAck(stream, 0, 100us)).Times(1); - EXPECT_CALL(lastByteDeliveryCb, onDeliveryAck(stream, 1, 100us)).Times(1); - server->onNetworkData(lAddr, std::move(networkData), rAddr); - Mock::VerifyAndClearExpectations(&writeChainDeliveryCb); - Mock::VerifyAndClearExpectations(&writeBufMetaDeliveryCb); - Mock::VerifyAndClearExpectations(&firstByteDeliveryCb); - Mock::VerifyAndClearExpectations(&lastByteDeliveryCb); - - // try to set both offsets again - // callbacks should be triggered immediately - EXPECT_CALL(firstByteDeliveryCb, onDeliveryAck(stream, 0, _)).Times(1); - EXPECT_CALL(lastByteDeliveryCb, onDeliveryAck(stream, 1, _)).Times(1); - auto serverRegisterDelivery4 = - server->registerDeliveryCallback(stream, 0, &firstByteDeliveryCb); - auto serverRegisterDelivery5 = - server->registerDeliveryCallback(stream, 1, &lastByteDeliveryCb); - loopForWrites(); - Mock::VerifyAndClearExpectations(&firstByteDeliveryCb); - Mock::VerifyAndClearExpectations(&lastByteDeliveryCb); - - // unsentByteDeliveryCb::onByteEvent will never get called - // cancel gets called instead - EXPECT_CALL(unsentByteDeliveryCb, onCanceled(stream, 2)).Times(1); - server->close(std::nullopt); - Mock::VerifyAndClearExpectations(&unsentByteDeliveryCb); -} - class QuicUnencryptedServerTransportTest : public QuicServerTransportTest { public: void setupConnection() override {} @@ -4696,52 +4465,6 @@ TEST_F(QuicServerTransportTest, TestStreamBufKnobHandlers) { kMaxExcessCwndPctForImminentStreams); } -TEST_F(QuicServerTransportTest, WriteDSR) { - EXPECT_EQ(server->getConn().dsrPacketCount, 0); - // Make sure we are post-handshake - ASSERT_NE(nullptr, server->getConn().oneRttWriteCipher); - // Rinse anything pending - auto serverWriteData1 = server->writeData(); - loopForWrites(); - server->getNonConstConn().outstandings.reset(); - getFakeHandshakeLayer()->setCipherSuite( - fizz::CipherSuite::TLS_AES_128_GCM_SHA256); - auto streamId = server->createBidirectionalStream().value(); - // Large-ish non-DSR data but not a full packet's worth. - auto buf = folly::IOBuf::create(1100); - buf->append(1100); - auto serverWriteChain17 = server->writeChain(streamId, std::move(buf), false); - auto mockDSRSender = std::make_unique(); - auto rawDSRSender = mockDSRSender.get(); - auto serverSetDSRSender5 = server->setDSRPacketizationRequestSender( - streamId, std::move(mockDSRSender)); - // Explicitly control how many packets we expect. - server->getNonConstConn().transportSettings.writeConnectionDataPacketsLimit = - 6; - // Ensure we have plenty of data. - BufferMeta bufMeta(server->getConn().udpSendPacketLen * 50); - auto serverWriteBufMeta4 = server->writeBufMeta(streamId, bufMeta, true); - auto serverWriteData2 = server->writeData(); - int numDsr = 0; - int numNonDsr = 0; - for (auto& p : server->getConn().outstandings.packets) { - if (p.isDSRPacket) { - numDsr++; - } else { - numNonDsr++; - } - } - EXPECT_EQ(server->getConn().outstandings.packets.size(), 7); - // Since there's only a small non-DSR packet, we should have 6 DSR and 1 - // non-DSR. - EXPECT_EQ(numDsr, 6); - EXPECT_EQ(numNonDsr, 1); - EXPECT_CALL(*rawDSRSender, release()).Times(1); - auto serverResetStream3 = - server->resetStream(streamId, GenericApplicationErrorCode::NO_ERROR); - EXPECT_EQ(server->getConn().dsrPacketCount, 6); -} - class QuicServerTransportCertTest : public QuicServerTransportTest { protected: class MockCert : public fizz::Cert { diff --git a/quic/somerge_defs.bzl b/quic/somerge_defs.bzl index 794aae036..fab001ee0 100644 --- a/quic/somerge_defs.bzl +++ b/quic/somerge_defs.bzl @@ -2,7 +2,7 @@ Generated by xplat/cross_plat_devx/somerge_maps/compute_merge_maps.py -@generated SignedSource<> +@generated SignedSource<<02c53d1127e98f19df005b36843cf886>> """ # Entry Points: @@ -150,8 +150,6 @@ QUIC_NATIVE_LIBRARY_MERGE_MAP = [ "fbsource//xplat/quic/congestion_control:packet_processorAndroid$", "fbsource//xplat/quic/congestion_control:throttling_signal_provider$", "fbsource//xplat/quic/congestion_control:throttling_signal_providerAndroid$", - "fbsource//xplat/quic/dsr:dsr_packetization_request_sender$", - "fbsource//xplat/quic/dsr:dsr_packetization_request_senderAndroid$", "fbsource//xplat/quic/fizz/client/handshake:fizz_client_handshake$", "fbsource//xplat/quic/fizz/client/handshake:fizz_client_handshakeAndroid$", "fbsource//xplat/quic/fizz/client/handshake:psk_cache$", diff --git a/quic/state/AckEvent.cpp b/quic/state/AckEvent.cpp index cfb34c66f..3a1972bac 100644 --- a/quic/state/AckEvent.cpp +++ b/quic/state/AckEvent.cpp @@ -17,14 +17,10 @@ void AckEvent::AckPacket::DetailsPerStream::recordFrameDelivered( if (!frame.len) { // may be FIN only return; } - auto [it, inserted] = emplace( + emplace( std::piecewise_construct, std::make_tuple(frame.streamId), std::make_tuple()); - auto& outstandingPacketStreamDetails = it->second; - if (frame.fromBufMeta) { - outstandingPacketStreamDetails.streamPacketIdx = frame.streamPacketIdx; - } } void AckEvent::AckPacket::DetailsPerStream::recordFrameAlreadyDelivered( @@ -36,18 +32,15 @@ void AckEvent::AckPacket::DetailsPerStream::recordFrameAlreadyDelivered( std::piecewise_construct, std::make_tuple(frame.streamId), std::make_tuple()); + (void)inserted; // Unused after DSR removal auto& outstandingPacketStreamDetails = it->second; outstandingPacketStreamDetails.dupAckedStreamIntervals.insert( frame.offset, frame.offset + frame.len - 1); - if (frame.fromBufMeta) { - outstandingPacketStreamDetails.streamPacketIdx = frame.streamPacketIdx; - } } AckEvent::AckPacket::AckPacket( quic::PacketNum packetNumIn, - uint64_t nonDsrPacketSequenceNumberIn, const OutstandingPacketMetadata& outstandingPacketMetadataIn, // NOLINT const DetailsPerStream& detailsPerStreamIn, // NOLINT Optional @@ -55,7 +48,6 @@ AckEvent::AckPacket::AckPacket( bool isAppLimitedIn, OptionalMicros&& receiveRelativeTimeStampUsec) : packetNum(packetNumIn), - nonDsrPacketSequenceNumber(nonDsrPacketSequenceNumberIn), outstandingPacketMetadata(outstandingPacketMetadataIn), // NOLINT detailsPerStream(detailsPerStreamIn), // NOLINT lastAckedPacketInfo(std::move(lastAckedPacketInfoIn)), @@ -68,13 +60,6 @@ AckEvent::AckPacket::Builder&& AckEvent::AckPacket::Builder::setPacketNum( return std::move(*this); } -AckEvent::AckPacket::Builder&& -AckEvent::AckPacket::Builder::setNonDsrPacketSequenceNumber( - uint64_t nonDsrPacketSequenceNumberIn) { - nonDsrPacketSequenceNumber = nonDsrPacketSequenceNumberIn; - return std::move(*this); -} - AckEvent::AckPacket::Builder&& AckEvent::AckPacket::Builder::setOutstandingPacketMetadata( OutstandingPacketMetadata& outstandingPacketMetadataIn) { @@ -115,7 +100,6 @@ AckEvent::AckPacket AckEvent::AckPacket::Builder::build() && { CHECK(detailsPerStream.has_value()); return AckEvent::AckPacket( packetNum.value(), - nonDsrPacketSequenceNumber.value(), *outstandingPacketMetadata, detailsPerStream.value(), lastAckedPacketInfo ? Optional( @@ -132,7 +116,6 @@ void AckEvent::AckPacket::Builder::buildInto( CHECK(detailsPerStream.has_value()); ackedPacketsVec.emplace_back( packetNum.value(), - nonDsrPacketSequenceNumber.value(), *outstandingPacketMetadata, detailsPerStream.value(), lastAckedPacketInfo ? Optional( diff --git a/quic/state/AckEvent.h b/quic/state/AckEvent.h index a4e401f12..995ed9d0a 100644 --- a/quic/state/AckEvent.h +++ b/quic/state/AckEvent.h @@ -152,14 +152,11 @@ struct AckEvent { struct AckPacket { // Sequence number of previously outstanding (now acked) packet quic::PacketNum packetNum; - uint64_t nonDsrPacketSequenceNumber{0}; // Metadata of the previously outstanding (now acked) packet OutstandingPacketMetadata outstandingPacketMetadata; struct StreamDetails { - Optional streamPacketIdx; - // definition for DupAckedStreamIntervalSet // we expect this to be rare, any thus only allocate a single position template @@ -255,8 +252,6 @@ struct AckEvent { struct Builder { Builder&& setPacketNum(quic::PacketNum packetNumIn); - Builder&& setNonDsrPacketSequenceNumber( - uint64_t nonDsrPacketSequenceNumberIn); Builder&& setOutstandingPacketMetadata( OutstandingPacketMetadata& outstandingPacketMetadataIn); Builder&& setDetailsPerStream(DetailsPerStream&& detailsPerStreamIn); @@ -271,7 +266,6 @@ struct AckEvent { private: Optional packetNum; - Optional nonDsrPacketSequenceNumber; OutstandingPacketMetadata* outstandingPacketMetadata{nullptr}; Optional detailsPerStream; OutstandingPacketWrapper::LastAckedPacketInfo* lastAckedPacketInfo{ @@ -286,7 +280,6 @@ struct AckEvent { // into the back of a vector. explicit AckPacket( quic::PacketNum packetNumIn, - uint64_t nonDsrPacketSequenceNumberIn, const OutstandingPacketMetadata& outstandingPacketMetadataIn, // NOLINT const DetailsPerStream& detailsPerStreamIn, // NOLINT Optional diff --git a/quic/state/AckHandlers.cpp b/quic/state/AckHandlers.cpp index c48388256..8fc9dcad7 100644 --- a/quic/state/AckHandlers.cpp +++ b/quic/state/AckHandlers.cpp @@ -181,7 +181,6 @@ quic::Expected processAckFrame( ? make_optional(firstOutstandingPacket->getPacketSequenceNum()) : std::nullopt; - uint64_t dsrPacketsAcked = 0; Optional lastAckedPacketSentTime; Optional spuriousLossEvent; @@ -253,9 +252,6 @@ quic::Expected processAckFrame( CHECK(conn.outstandings.clonedPacketCount[currentPacketNumberSpace]); --conn.outstandings.clonedPacketCount[currentPacketNumberSpace]; } - if (ackedPacketIterator->isDSRPacket) { - ++dsrPacketsAcked; - } if (!ack.implicit && currentPacketNum == frame.largestAcked) { updateRttForLargestAckedPacket( @@ -389,8 +385,6 @@ quic::Expected processAckFrame( outstandingPacket->packet.header.getPacketSequenceNum()); CongestionController::AckEvent::AckPacket::Builder() .setPacketNum(outstandingPacket->packet.header.getPacketSequenceNum()) - .setNonDsrPacketSequenceNumber( - outstandingPacket->nonDsrPacketSequenceNumber.value_or(0)) .setOutstandingPacketMetadata(outstandingPacket->metadata) .setDetailsPerStream(std::move(detailsPerStream)) .setLastAckedPacketInfo( @@ -408,8 +402,6 @@ quic::Expected processAckFrame( if (lastAckedPacketSentTime) { conn.lossState.lastAckedPacketSentTime = *lastAckedPacketSentTime; } - CHECK_GE(conn.outstandings.dsrCount, dsrPacketsAcked); - conn.outstandings.dsrCount -= dsrPacketsAcked; CHECK_GE( conn.outstandings.packets.size(), conn.outstandings.declaredLostCount); auto updatedOustandingPacketsCount = conn.outstandings.numOutstanding(); diff --git a/quic/state/AckStates.h b/quic/state/AckStates.h index b4adc6c9b..39560c51a 100644 --- a/quic/state/AckStates.h +++ b/quic/state/AckStates.h @@ -28,15 +28,11 @@ struct AckState : WriteAckFrameState { Optional largestAckedByPeer; // Largest received packet number at the time we sent our last close message. Optional largestReceivedAtLastCloseSent; - // Packet sequence number for largest non-dsr packet acked by peer. - Optional largestNonDsrSequenceNumberAckedByPeer; // Next PacketNum we will send for packet in this packet number space PacketNum nextPacketNum{0}; // If set, then this packet number was recently skipped and should not be // acked by the peer. Optional skippedPacketNum; - // Incremented for each non-DSR packet. - uint64_t nonDsrPacketSequenceNumber{0}; uint64_t reorderThreshold{0}; Optional tolerance; Optional ackFrequencySequenceNumber; diff --git a/quic/state/BUCK b/quic/state/BUCK index 1e41da5dc..80c4d0873 100644 --- a/quic/state/BUCK +++ b/quic/state/BUCK @@ -139,7 +139,6 @@ mvfst_cpp_library( "//quic/congestion_control:congestion_controller", "//quic/congestion_control:packet_processor", "//quic/congestion_control:throttling_signal_provider", - "//quic/dsr:dsr_packetization_request_sender", "//quic/handshake:handshake", "//quic/logging:qlogger", "//quic/observer:socket_observer_types", diff --git a/quic/state/CMakeLists.txt b/quic/state/CMakeLists.txt index ee592f31d..15257bc11 100644 --- a/quic/state/CMakeLists.txt +++ b/quic/state/CMakeLists.txt @@ -36,7 +36,6 @@ add_dependencies( mvfst_codec mvfst_codec_types mvfst_folly_utils - mvfst_dsr_sender mvfst_handshake ) @@ -49,7 +48,6 @@ target_link_libraries( mvfst_codec mvfst_codec_types mvfst_folly_utils - mvfst_dsr_sender mvfst_handshake mvfst_http_priority_queue ) diff --git a/quic/state/OutstandingPacket.h b/quic/state/OutstandingPacket.h index 5f8789f79..625c0b36e 100644 --- a/quic/state/OutstandingPacket.h +++ b/quic/state/OutstandingPacket.h @@ -186,12 +186,6 @@ struct OutstandingPacket { // will be a std::nullopt if the packet isn't a clone and hasn't been cloned. Optional maybeClonedPacketIdentifier; - OptionalIntegral nonDsrPacketSequenceNumber; - - // Whether this is a DSR packet. A DSR packet's stream data isn't written - // by transport directly. - bool isDSRPacket : 1; - /** * Whether the packet is sent when congestion controller is in app-limited * state. @@ -232,7 +226,6 @@ struct OutstandingPacket { std::move(detailsPerStream), totalAppLimitedTimeUsecs)) { // TODO remove when C++20 everywhere. - isDSRPacket = false; isAppLimited = false; declaredLost = false; } diff --git a/quic/state/QuicStateFunctions.cpp b/quic/state/QuicStateFunctions.cpp index ac028b187..a25557397 100644 --- a/quic/state/QuicStateFunctions.cpp +++ b/quic/state/QuicStateFunctions.cpp @@ -253,13 +253,9 @@ PacketNum getNextPacketNum( void increaseNextPacketNum( QuicConnectionStateBase& conn, - PacketNumberSpace pnSpace, - bool dsrPacket) noexcept { + PacketNumberSpace pnSpace) noexcept { auto& ackState = getAckState(conn, pnSpace); ackState.nextPacketNum++; - if (!dsrPacket) { - ackState.nonDsrPacketSequenceNumber++; - } if (ackState.nextPacketNum == kMaxPacketNumber) { conn.pendingEvents.closeTransport = true; } diff --git a/quic/state/QuicStateFunctions.h b/quic/state/QuicStateFunctions.h index a1f6aa751..cb9433897 100644 --- a/quic/state/QuicStateFunctions.h +++ b/quic/state/QuicStateFunctions.h @@ -60,8 +60,7 @@ PacketNum getNextPacketNum( void increaseNextPacketNum( QuicConnectionStateBase& conn, - PacketNumberSpace pnSpace, - bool dsrPacket = false) noexcept; + PacketNumberSpace pnSpace) noexcept; /** * Update largestReceivedUdpPacketNum in ackState with packetNum. Return the diff --git a/quic/state/QuicStreamFunctions.cpp b/quic/state/QuicStreamFunctions.cpp index 51e7e7e41..ec4755cf9 100644 --- a/quic/state/QuicStreamFunctions.cpp +++ b/quic/state/QuicStreamFunctions.cpp @@ -26,17 +26,10 @@ void prependToBuf(quic::BufPtr& buf, quic::BufPtr toAppend) { namespace quic { quic::Expected writeDataToQuicStream(QuicStreamState& stream, BufPtr data, bool eof) { - auto neverWrittenBufMeta = (0 == stream.writeBufMeta.offset); uint64_t len = 0; if (data) { len = data->computeChainDataLength(); } - // Disallow writing any data or EOF when there's buf meta data already. - CHECK(neverWrittenBufMeta); - // Also disallow writing an EOF at the end of real data when there's going - // to be buf meta data in the future. - LOG_IF(FATAL, eof && stream.dsrSender) - << "Trying to write eof on normal data for DSR stream: " << &stream; if (len > 0) { // We call this before updating the writeBuffer because we only want to // write a blocked frame first time the stream becomes blocked @@ -56,38 +49,6 @@ writeDataToQuicStream(QuicStreamState& stream, BufPtr data, bool eof) { return {}; } -quic::Expected writeBufMetaToQuicStream( - QuicStreamState& stream, - const BufferMeta& data, - bool eof) { - if (data.length > 0) { - maybeWriteBlockAfterAPIWrite(stream); - } - auto realDataLength = - stream.currentWriteOffset + stream.pendingWrites.chainLength(); - CHECK_GT(realDataLength, 0) - << "Real data has to be written to a stream before any buffer meta is" - << "written to it."; - if (stream.writeBufMeta.offset == 0) { - CHECK(!stream.finalWriteOffset.has_value()) - << "Buffer meta cannot be appended to a stream after we have seen EOM " - << "in real data"; - stream.writeBufMeta.offset = realDataLength; - } - stream.writeBufMeta.length += data.length; - if (eof) { - stream.finalWriteOffset = - stream.writeBufMeta.offset + stream.writeBufMeta.length; - stream.writeBufMeta.eof = true; - } - auto result = updateFlowControlOnWriteToStream(stream, data.length); - if (!result.has_value()) { - return quic::make_unexpected(result.error()); - } - stream.conn.streamManager->updateWritableStreams(stream); - return {}; -} - void writeDataToQuicStream(QuicCryptoStream& stream, BufPtr data) { stream.pendingWrites.append(data); stream.writeBuffer.append(std::move(data)); @@ -472,9 +433,7 @@ bool allBytesTillFinAcked(const QuicStreamState& stream) { * 5. We have no bytes that are detected as lost. */ return stream.hasSentFIN() && stream.retransmissionBuffer.empty() && - stream.retransmissionBufMetas.empty() && stream.pendingWrites.empty() && - !stream.hasWritableBufMeta() && stream.lossBuffer.empty() && - stream.lossBufMetas.empty(); + stream.pendingWrites.empty() && stream.lossBuffer.empty(); } void appendPendingStreamReset( @@ -482,19 +441,6 @@ void appendPendingStreamReset( const QuicStreamState& stream, ApplicationErrorCode errorCode, Optional reliableSize) { - /* - * When BufMetas are written to the transport, but before they are written to - * the network, writeBufMeta.offset would be assigned a value > - * currentWriteOffset. For this reason, we can't simply use - * min(max(currentWriteOffset, writeBufMeta.offset), finalWriteOffset) as the - * final offset. We have to check if any BufMetas have been written to the - * network. If we simply use min(max(currentWriteOffset, writeBufMeta.offset), - * we risk using a value > peer's flow control limit. - */ - bool writeBufWritten = stream.writeBufMeta.offset && - (stream.currentWriteOffset + stream.pendingWrites.chainLength() != - stream.writeBufMeta.offset); - /* * The spec mandates that with multiple RESET_STREAM_AT or RESET_STREAM * frames, we must use the same value of finalSize. Although we don't store @@ -512,8 +458,7 @@ void appendPendingStreamReset( * RESET_STREAM_AT frames by virtue of the fact that it's the maxiumum of the * current write offset and the new reliable size. */ - uint64_t finalSize = - writeBufWritten ? stream.writeBufMeta.offset : stream.currentWriteOffset; + uint64_t finalSize = stream.currentWriteOffset; if (reliableSize) { // It's possible that we've queued up data at the socket, but haven't yet // written it out to the wire, so stream.currentWriteOffset could be @@ -532,20 +477,16 @@ void appendPendingStreamReset( uint64_t getLargestWriteOffsetSeen(const QuicStreamState& stream) { return stream.finalWriteOffset.value_or( - std::max( - stream.currentWriteOffset + stream.pendingWrites.chainLength(), - stream.writeBufMeta.offset + stream.writeBufMeta.length)); + stream.currentWriteOffset + stream.pendingWrites.chainLength()); } Optional getLargestWriteOffsetTxed(const QuicStreamState& stream) { // currentWriteOffset is really nextWriteOffset // when 0, it indicates nothing has been written yet - if (stream.currentWriteOffset == 0 && stream.writeBufMeta.offset == 0) { + if (stream.currentWriteOffset == 0) { return std::nullopt; } - uint64_t currentWriteOffset = - std::max(stream.currentWriteOffset, stream.writeBufMeta.offset); - return currentWriteOffset - 1; + return stream.currentWriteOffset - 1; } Optional getLargestDeliverableOffset(const QuicStreamState& stream) { diff --git a/quic/state/QuicStreamFunctions.h b/quic/state/QuicStreamFunctions.h index 460d61410..a852f7cdc 100644 --- a/quic/state/QuicStreamFunctions.h +++ b/quic/state/QuicStreamFunctions.h @@ -21,17 +21,6 @@ namespace quic { [[nodiscard]] quic::Expected writeDataToQuicStream(QuicStreamState& stream, BufPtr data, bool eof); -/** - * Adds data represented in the form of BufferMeta to the end of the Buffer - * Meta queue of the stream. - * - * TODO: move to dsr directory. - */ -[[nodiscard]] quic::Expected writeBufMetaToQuicStream( - QuicStreamState& stream, - const BufferMeta& data, - bool eof); - /** * Adds data to the end of the write buffer of the QUIC crypto stream. This * data will be written onto the socket. diff --git a/quic/state/QuicStreamManager.cpp b/quic/state/QuicStreamManager.cpp index 17c89b8e2..3ccb38801 100644 --- a/quic/state/QuicStreamManager.cpp +++ b/quic/state/QuicStreamManager.cpp @@ -890,7 +890,6 @@ void QuicStreamManager::updateWritableStreams( // Check for terminal write errors first if (stream.streamWriteError.has_value() && !stream.reliableSizeToPeer) { CHECK(stream.lossBuffer.empty()); - CHECK(stream.lossBufMetas.empty()); removeWritable(stream); return; } @@ -904,32 +903,21 @@ void QuicStreamManager::updateWritableStreams( return; } - // Update writable/loss sets based on data/meta presence + // Update writable/loss sets based on data presence if (stream.hasWritableData()) { writableStreams_.emplace(stream.id); } else { writableStreams_.erase(stream.id); } - if (stream.hasWritableBufMeta()) { - writableDSRStreams_.emplace(stream.id); - } else { - writableDSRStreams_.erase(stream.id); - } if (!stream.lossBuffer.empty()) { lossStreams_.emplace(stream.id); } else { lossStreams_.erase(stream.id); } - if (!stream.lossBufMetas.empty()) { - lossDSRStreams_.emplace(stream.id); - } else { - lossDSRStreams_.erase(stream.id); - } // Update the actual scheduling queues (PriorityQueue or control set) connFlowControlOpen |= bool(oldWriteQueue_); - if (stream.hasSchedulableData(connFlowControlOpen) || - stream.hasSchedulableDsr(connFlowControlOpen)) { + if (stream.hasSchedulableData(connFlowControlOpen)) { if (stream.isControl) { controlWriteQueue_.emplace(stream.id); } else { diff --git a/quic/state/QuicStreamManager.h b/quic/state/QuicStreamManager.h index 874b54d7b..6f792f330 100644 --- a/quic/state/QuicStreamManager.h +++ b/quic/state/QuicStreamManager.h @@ -215,7 +215,6 @@ class QuicStreamManager { windowUpdates_ = std::move(other.windowUpdates_); flowControlUpdated_ = std::move(other.flowControlUpdated_); lossStreams_ = std::move(other.lossStreams_); - lossDSRStreams_ = std::move(other.lossDSRStreams_); readableStreams_ = std::move(other.readableStreams_); unidirectionalReadableStreams_ = std::move(other.unidirectionalReadableStreams_); @@ -224,7 +223,6 @@ class QuicStreamManager { writeQueue_ = std::move(other.writeQueue_); controlWriteQueue_ = std::move(other.controlWriteQueue_); writableStreams_ = std::move(other.writableStreams_); - writableDSRStreams_ = std::move(other.writableDSRStreams_); txStreams_ = std::move(other.txStreams_); deliverableStreams_ = std::move(other.deliverableStreams_); closedStreams_ = std::move(other.closedStreams_); @@ -426,20 +424,11 @@ class QuicStreamManager { } [[nodiscard]] bool hasLoss() const { - return !lossStreams_.empty() || !lossDSRStreams_.empty(); - } - - [[nodiscard]] bool hasNonDSRLoss() const { return !lossStreams_.empty(); } - [[nodiscard]] bool hasDSRLoss() const { - return !lossDSRStreams_.empty(); - } - void removeLoss(StreamId id) { lossStreams_.erase(id); - lossDSRStreams_.erase(id); } void addLoss(StreamId id) { @@ -458,10 +447,6 @@ class QuicStreamManager { bool connFlowControlOpen = true, const std::shared_ptr& qLogger = nullptr); - auto& writableDSRStreams() { - return writableDSRStreams_; - } - auto& controlWriteQueue() { return controlWriteQueue_; } @@ -479,14 +464,6 @@ class QuicStreamManager { !writeQueue_->empty() || !controlWriteQueue_.empty(); } - [[nodiscard]] bool hasDSRWritable() const { - return !writableDSRStreams_.empty(); - } - - bool hasNonDSRWritable() const { - return !writableStreams_.empty() || !controlWriteQueue_.empty(); - } - void removeWritable(const QuicStreamState& stream) { if (stream.isControl) { controlWriteQueue_.erase(stream.id); @@ -499,14 +476,11 @@ class QuicStreamManager { } } writableStreams_.erase(stream.id); - writableDSRStreams_.erase(stream.id); lossStreams_.erase(stream.id); - lossDSRStreams_.erase(stream.id); } void clearWritable() { writableStreams_.clear(); - writableDSRStreams_.clear(); if (oldWriteQueue_) { oldWriteQueue()->clear(); } @@ -920,7 +894,6 @@ class QuicStreamManager { // Streams that have bytes in loss buffer UnorderedSet lossStreams_; - UnorderedSet lossDSRStreams_; UnorderedSet readableStreams_; UnorderedSet unidirectionalReadableStreams_; UnorderedSet peekableStreams_; @@ -929,7 +902,6 @@ class QuicStreamManager { std::unique_ptr oldWriteQueue_; std::set controlWriteQueue_; UnorderedSet writableStreams_; - UnorderedSet writableDSRStreams_; UnorderedSet txStreams_; UnorderedSet deliverableStreams_; UnorderedSet closedStreams_; diff --git a/quic/state/QuicTransportStatsCallback.h b/quic/state/QuicTransportStatsCallback.h index 4aa7cef0b..9a4dc322f 100644 --- a/quic/state/QuicTransportStatsCallback.h +++ b/quic/state/QuicTransportStatsCallback.h @@ -69,8 +69,6 @@ class QuicTransportStatsCallback { } } - virtual void onDSRPacketSent(size_t pktSize) = 0; - virtual void onPacketRetransmission() = 0; virtual void onPacketLoss() = 0; diff --git a/quic/state/StateData.h b/quic/state/StateData.h index 38c4967b2..42d900663 100644 --- a/quic/state/StateData.h +++ b/quic/state/StateData.h @@ -63,10 +63,6 @@ struct OutstandingsInfo { // Number of packets currently declared lost. uint64_t declaredLostCount{0}; - // Number of outstanding inflight DSR packet. That is, when a DSR packet is - // declared lost, this counter will be decreased. - uint64_t dsrCount{0}; - // We just use this to get the correct number of outstanding packets. We // subtract the number of packets declared lost and scheduled for destruction // from the number of packets in the outstanding packets list. @@ -92,7 +88,6 @@ struct OutstandingsInfo { clonedPacketCount = {}; declaredLostCount = 0; scheduledForDestructionCount = 0; - dsrCount = 0; } }; @@ -672,9 +667,6 @@ struct QuicConnectionStateBase : public folly::DelayedDestruction { // in the Observers, to construct Write Blocks uint64_t writeCount{0}; - // Number of DSR packets sent by this connection. - uint64_t dsrPacketCount{0}; - // Whether we successfully used 0-RTT keys in this connection. bool usedZeroRtt{false}; diff --git a/quic/state/StreamData.h b/quic/state/StreamData.h index 261df4bcb..d06ea5e1a 100644 --- a/quic/state/StreamData.h +++ b/quic/state/StreamData.h @@ -13,77 +13,11 @@ #include #include #include -#include #include #include namespace quic { -/** - * A buffer representation without the actual data. This is part of the public - * facing interface. - * - * This is experimental. - */ -struct BufferMeta { - size_t length; - - explicit BufferMeta(size_t lengthIn) : length(lengthIn) {} -}; - -/** - * A write buffer representation without the actual data. This is used for - * write buffer management in a stream. - * - * This is experimental. - */ -struct WriteBufferMeta { - size_t length{0}; - size_t offset{0}; - bool eof{false}; - - WriteBufferMeta() = default; - - struct Builder { - Builder& setLength(size_t lengthIn) { - length_ = lengthIn; - return *this; - } - - Builder& setOffset(size_t offsetIn) { - offset_ = offsetIn; - return *this; - } - - Builder& setEOF(bool val) { - eof_ = val; - return *this; - } - - WriteBufferMeta build() { - return WriteBufferMeta(length_, offset_, eof_); - } - - private: - size_t length_{0}; - size_t offset_{0}; - bool eof_{false}; - }; - - WriteBufferMeta split(size_t splitLen) { - CHECK_GE(length, splitLen); - auto splitEof = splitLen == length && eof; - WriteBufferMeta splitOf(splitLen, offset, splitEof); - offset += splitLen; - length -= splitLen; - return splitOf; - } - - private: - explicit WriteBufferMeta(size_t lengthIn, size_t offsetIn, bool eofIn) - : length(lengthIn), offset(offsetIn), eof(eofIn) {} -}; - struct StreamBuffer { BufQueue data; uint64_t offset; @@ -156,11 +90,8 @@ struct QuicStreamLike { // Current offset of the start bytes in the pending writes chain. // This changes when we pop stuff off the pendingWrites chain. - // In a non-DSR stream, when we are finished writing out all the bytes until - // FIN, this will be one greater than finalWriteOffset. - // When DSR is used, this still points to the starting bytes in the write - // buffer. Its value won't change with WriteBufferMetas are appended and sent - // for a stream. + // When we are finished writing out all the bytes until FIN, this will be + // one greater than finalWriteOffset. uint64_t currentWriteOffset{0}; // the minimum offset requires retransmit @@ -439,10 +370,6 @@ struct QuicStreamState : public QuicStreamLike { totalHolbTime = other.totalHolbTime; holbCount = other.holbCount; priority = other.priority; - dsrSender = std::move(other.dsrSender); - writeBufMeta = other.writeBufMeta; - retransmissionBufMetas = std::move(other.retransmissionBufMetas); - lossBufMetas = std::move(other.lossBufMetas); streamLossCount = other.streamLossCount; } @@ -503,9 +430,7 @@ struct QuicStreamState : public QuicStreamLike { // Uninitialized = default PriorityQueue::Priority priority; - // This monotonically increases by 1 this stream is written to packets. Note - // that this is only used for DSR and facilitates loss detection. - uint64_t streamPacketIdx{0}; + uint64_t streamLossCount{0}; // Returns true if both send and receive state machines are in a terminal // state @@ -528,7 +453,7 @@ struct QuicStreamState : public QuicStreamLike { return recvState == StreamRecvState::Open; } - // If the stream has writable data that's not backed by DSR. That is, in a + // If the stream has writable data. That is, in a // regular stream write, it will be able to write something. So it either // needs to have data in the pendingWrites chain, or it has EOF to send. bool hasWritableData(bool connFlowControlOpen = true) const { @@ -538,62 +463,29 @@ struct QuicStreamState : public QuicStreamLike { flowControlState.peerAdvertisedMaxOffset - currentWriteOffset > 0; } if (finalWriteOffset) { - // We can only write a FIN with a non-DSR stream frame if there's no - // DSR data. - return writeBufMeta.offset == 0 && - currentWriteOffset <= *finalWriteOffset; + return currentWriteOffset <= *finalWriteOffset; } return false; } - // Whether this stream has non-DSR data in the write buffer or loss buffer. + // Whether this stream has data in the write buffer or loss buffer. [[nodiscard]] bool hasSchedulableData(bool connFlowControlOpen = true) const { return hasWritableData(connFlowControlOpen) || !lossBuffer.empty(); } - [[nodiscard]] bool hasSchedulableDsr(bool connFlowControlOpen = true) const { - return hasWritableBufMeta(connFlowControlOpen) || !lossBufMetas.empty(); - } - - [[nodiscard]] bool hasWritableBufMeta(bool connFlowControlOpen = true) const { - if (writeBufMeta.offset == 0) { - return false; - } - if (writeBufMeta.length > 0) { - CHECK_GE(flowControlState.peerAdvertisedMaxOffset, writeBufMeta.offset); - return connFlowControlOpen && - flowControlState.peerAdvertisedMaxOffset - writeBufMeta.offset > 0; - } - if (finalWriteOffset) { - return writeBufMeta.offset <= *finalWriteOffset; - } - return false; - } - [[nodiscard]] bool hasSentFIN() const { if (!finalWriteOffset) { return false; } - return currentWriteOffset > *finalWriteOffset || - writeBufMeta.offset > *finalWriteOffset; + return currentWriteOffset > *finalWriteOffset; } [[nodiscard]] bool hasLoss() const { - return !lossBuffer.empty() || !lossBufMetas.empty(); + return !lossBuffer.empty(); } [[nodiscard]] uint64_t nextOffsetToWrite() const { - // The stream has never had WriteBufferMetas. Then currentWriteOffset - // always points to the next offset we send. This of course relies on the - // current contract of DSR: Real data always comes first. This code (and a - // lot other code) breaks when that contract is breached. - if (writeBufMeta.offset == 0) { - return currentWriteOffset; - } - if (!pendingWrites.empty()) { - return currentWriteOffset; - } - return writeBufMeta.offset; + return currentWriteOffset; } bool hasReadableData() const { @@ -606,54 +498,6 @@ struct QuicStreamState : public QuicStreamLike { return readBuffer.size() > 0; } - void removeFromWriteBufMetaStartingAtOffset(uint64_t startingOffset) { - if (startingOffset <= writeBufMeta.offset) { - writeBufMeta.length = 0; - return; - } - - if (startingOffset > writeBufMeta.offset && - startingOffset <= writeBufMeta.offset + writeBufMeta.length) { - writeBufMeta.length = uint32_t(startingOffset - writeBufMeta.offset); - } - } - - void removeFromRetransmissionBufMetasStartingAtOffset( - uint64_t startingOffset) { - UnorderedSet offsetsToRemove; - - for (auto& [offset, buf] : retransmissionBufMetas) { - if (offset >= startingOffset) { - offsetsToRemove.insert(offset); - } else if (offset + buf.length >= startingOffset) { - buf.length = size_t(startingOffset - offset); - } - } - - for (auto offset : offsetsToRemove) { - retransmissionBufMetas.erase(offset); - } - } - - void removeFromLossBufMetasStartingAtOffset(uint64_t startingOffset) { - if (lossBufMetas.empty()) { - // Nothing to do. - return; - } - - while (!lossBufMetas.empty()) { - auto& lastElement = lossBufMetas.back(); - if (lastElement.offset >= startingOffset) { - lossBufMetas.pop_back(); - } else if (lastElement.offset + lastElement.length >= startingOffset) { - lastElement.length = uint32_t(startingOffset - lastElement.offset); - return; - } else { - return; - } - } - } - void removeFromReadBufferStartingAtOffset(uint64_t startingOffset) { while (!readBuffer.empty()) { auto& lastElement = readBuffer.back(); @@ -670,45 +514,5 @@ struct QuicStreamState : public QuicStreamLike { } } } - - std::unique_ptr dsrSender; - - // BufferMeta that has been written to the QUIC layer. - // When offset is 0, nothing has been written to it. On first write, its - // starting offset will be currentWriteOffset + pendingWrites.chainLength(). - WriteBufferMeta writeBufMeta; - - // A map to store sent WriteBufferMetas for potential retransmission. - UnorderedMap retransmissionBufMetas; - - // WriteBufferMetas that's already marked lost. They will be retransmitted. - CircularDeque lossBufMetas; - - uint64_t streamLossCount{0}; - - /** - * Insert a new WriteBufferMeta into lossBufMetas. If the new WriteBufferMeta - * can be append to an existing WriteBufferMeta, it will be appended. Note - * it won't be prepended to an existing WriteBufferMeta. And it will also not - * merge 3 WriteBufferMetas together if the new one happens to fill up a hole - * between 2 existing WriteBufferMetas. - */ - void insertIntoLossBufMeta(WriteBufferMeta bufMeta) { - auto lossItr = std::upper_bound( - lossBufMetas.begin(), - lossBufMetas.end(), - bufMeta.offset, - [](auto offset, const auto& wBufMeta) { - return offset < wBufMeta.offset; - }); - if (!lossBufMetas.empty() && lossItr != lossBufMetas.begin() && - std::prev(lossItr)->offset + std::prev(lossItr)->length == - bufMeta.offset) { - std::prev(lossItr)->length += bufMeta.length; - std::prev(lossItr)->eof = bufMeta.eof; - } else { - lossBufMetas.insert(lossItr, bufMeta); - } - } }; } // namespace quic diff --git a/quic/state/stream/StreamSendHandlers.cpp b/quic/state/stream/StreamSendHandlers.cpp index b7f334c0c..fc41fb6b2 100644 --- a/quic/state/stream/StreamSendHandlers.cpp +++ b/quic/state/stream/StreamSendHandlers.cpp @@ -134,50 +134,26 @@ quic::Expected sendAckSMHandler( switch (stream.sendState) { case StreamSendState::Open: case StreamSendState::ResetSent: { - if (!ackedFrame.fromBufMeta) { - // Clean up the acked buffers from the retransmissionBuffer. - auto ackedBuffer = stream.retransmissionBuffer.find(ackedFrame.offset); - if (ackedBuffer != stream.retransmissionBuffer.end()) { - CHECK_EQ(ackedFrame.offset, ackedBuffer->second->offset); - CHECK_EQ(ackedFrame.len, ackedBuffer->second->data.chainLength()); - CHECK_EQ(ackedFrame.fin, ackedBuffer->second->eof); - VLOG(10) << "Open: acked stream data stream=" << stream.id - << " offset=" << ackedBuffer->second->offset - << " len=" << ackedBuffer->second->data.chainLength() - << " eof=" << ackedBuffer->second->eof << " " << stream.conn; - auto updateResult = stream.updateAckedIntervals( - ackedBuffer->second->offset, - ackedBuffer->second->data.chainLength(), - ackedBuffer->second->eof); - if (!updateResult.has_value()) { - return quic::make_unexpected(QuicError( - TransportErrorCode::INTERNAL_ERROR, - "Failed to update acked intervals")); - } - stream.retransmissionBuffer.erase(ackedBuffer); - } - } else { - auto ackedBuffer = - stream.retransmissionBufMetas.find(ackedFrame.offset); - if (ackedBuffer != stream.retransmissionBufMetas.end()) { - CHECK_EQ(ackedFrame.offset, ackedBuffer->second.offset); - CHECK_EQ(ackedFrame.len, ackedBuffer->second.length); - CHECK_EQ(ackedFrame.fin, ackedBuffer->second.eof); - VLOG(10) << "Open: acked stream data bufmeta=" << stream.id - << " offset=" << ackedBuffer->second.offset - << " len=" << ackedBuffer->second.length - << " eof=" << ackedBuffer->second.eof << " " << stream.conn; - auto updateResult = stream.updateAckedIntervals( - ackedBuffer->second.offset, - ackedBuffer->second.length, - ackedBuffer->second.eof); - if (!updateResult.has_value()) { - return quic::make_unexpected(QuicError( - TransportErrorCode::INTERNAL_ERROR, - "Failed to update acked intervals")); - } - stream.retransmissionBufMetas.erase(ackedBuffer); + // Clean up the acked buffers from the retransmissionBuffer. + auto ackedBuffer = stream.retransmissionBuffer.find(ackedFrame.offset); + if (ackedBuffer != stream.retransmissionBuffer.end()) { + CHECK_EQ(ackedFrame.offset, ackedBuffer->second->offset); + CHECK_EQ(ackedFrame.len, ackedBuffer->second->data.chainLength()); + CHECK_EQ(ackedFrame.fin, ackedBuffer->second->eof); + VLOG(10) << "Open: acked stream data stream=" << stream.id + << " offset=" << ackedBuffer->second->offset + << " len=" << ackedBuffer->second->data.chainLength() + << " eof=" << ackedBuffer->second->eof << " " << stream.conn; + auto updateResult = stream.updateAckedIntervals( + ackedBuffer->second->offset, + ackedBuffer->second->data.chainLength(), + ackedBuffer->second->eof); + if (!updateResult.has_value()) { + return quic::make_unexpected(QuicError( + TransportErrorCode::INTERNAL_ERROR, + "Failed to update acked intervals")); } + stream.retransmissionBuffer.erase(ackedBuffer); } // This stream may be able to invoke some deliveryCallbacks: diff --git a/quic/state/stream/StreamStateFunctions.cpp b/quic/state/stream/StreamStateFunctions.cpp index fcdd5cccb..7db31c492 100644 --- a/quic/state/stream/StreamStateFunctions.cpp +++ b/quic/state/stream/StreamStateFunctions.cpp @@ -25,9 +25,6 @@ quic::Expected resetQuicStream( stream.removeFromWriteBufStartingAtOffset(*reliableSize); stream.removeFromPendingWritesStartingAtOffset(*reliableSize); stream.removeFromLossBufStartingAtOffset(*reliableSize); - stream.removeFromRetransmissionBufMetasStartingAtOffset(*reliableSize); - stream.removeFromWriteBufMetaStartingAtOffset(*reliableSize); - stream.removeFromLossBufMetasStartingAtOffset(*reliableSize); stream.streamWriteError = error; } else { stream.reliableSizeToPeer = std::nullopt; @@ -36,13 +33,6 @@ quic::Expected resetQuicStream( ChainedByteRangeHead(std::move(stream.pendingWrites)); // Will be destructed stream.lossBuffer.clear(); stream.streamWriteError = error; - stream.writeBufMeta.length = 0; - stream.retransmissionBufMetas.clear(); - stream.lossBufMetas.clear(); - if (stream.dsrSender) { - stream.dsrSender->release(); - stream.dsrSender.reset(); - } } stream.conn.streamManager->updateReadableStreams(stream); stream.conn.streamManager->updateWritableStreams(stream); diff --git a/quic/state/stream/test/BUCK b/quic/state/stream/test/BUCK index b2372996e..7d7813053 100644 --- a/quic/state/stream/test/BUCK +++ b/quic/state/stream/test/BUCK @@ -26,8 +26,6 @@ mvfst_cpp_test( ], deps = [ "//quic/common/test:test_utils", - "//quic/dsr:types", - "//quic/dsr/test:mocks", "//quic/fizz/server/handshake:fizz_server_handshake", "//quic/logging:file_qlogger", "//quic/server/state:server", diff --git a/quic/state/stream/test/StreamStateFunctionsTest.cpp b/quic/state/stream/test/StreamStateFunctionsTest.cpp index de0b5731b..7e380469f 100644 --- a/quic/state/stream/test/StreamStateFunctionsTest.cpp +++ b/quic/state/stream/test/StreamStateFunctionsTest.cpp @@ -9,8 +9,6 @@ #include #include -#include -#include #include #include #include @@ -260,39 +258,6 @@ TEST_F(StreamStateFunctionsTests, SendReset) { EXPECT_TRUE(stream.writeBuffer.empty()); } -TEST_F(StreamStateFunctionsTests, SendResetDSRStream) { - QuicServerConnectionState conn( - FizzServerQuicHandshakeContext::Builder().build()); - conn.flowControlState.peerAdvertisedMaxOffset = 5000; - StreamId id = 1; - QuicStreamState stream(id, conn); - auto initialConnWindow = getSendConnFlowControlBytesAPI(conn); - ASSERT_FALSE( - writeDataToQuicStream(stream, folly::IOBuf::copyBuffer("aloha"), false) - .hasError()); - auto mockDSRSender = std::make_unique(); - EXPECT_CALL(*mockDSRSender, release()).Times(1); - stream.flowControlState.peerAdvertisedMaxOffset = - std::numeric_limits::max(); - stream.dsrSender = std::move(mockDSRSender); - BufferMeta bufMeta(2000); - ASSERT_FALSE(writeBufMetaToQuicStream(stream, bufMeta, true).hasError()); - EXPECT_EQ(conn.flowControlState.sumCurStreamBufferLen, 5 + 2000); - EXPECT_EQ(getSendConnFlowControlBytesAPI(conn), initialConnWindow - 5 - 2000); - ASSERT_FALSE(appendDataToReadBuffer( - stream, StreamBuffer(folly::IOBuf::copyBuffer("hi"), 0)) - .hasError()); - EXPECT_FALSE(stream.writeBuffer.empty()); - EXPECT_FALSE(stream.readBuffer.empty()); - ASSERT_FALSE( - resetQuicStream(stream, GenericApplicationErrorCode::UNKNOWN).hasError()); - EXPECT_EQ(getSendConnFlowControlBytesAPI(conn), initialConnWindow); - EXPECT_TRUE(stream.streamWriteError.has_value()); - EXPECT_TRUE(stream.writeBuffer.empty()); - EXPECT_EQ(0, stream.writeBufMeta.length); - EXPECT_TRUE(stream.lossBufMetas.empty()); -} - TEST_F(StreamStateFunctionsTests, ResetNoFlowControlGenerated) { QuicServerConnectionState conn( FizzServerQuicHandshakeContext::Builder().build()); diff --git a/quic/state/stream/test/StreamStateMachineTest.cpp b/quic/state/stream/test/StreamStateMachineTest.cpp index b1343c590..f220a76fd 100644 --- a/quic/state/stream/test/StreamStateMachineTest.cpp +++ b/quic/state/stream/test/StreamStateMachineTest.cpp @@ -1112,79 +1112,4 @@ TEST_F(QuicUnidirectionalStreamTest, ResetSentInvalidRstStream) { EXPECT_NE(result.error().code.asTransportErrorCode(), nullptr); } -TEST_F(QuicOpenStateTest, DSRStreamAcked) { - auto conn = createConn(); - conn->clientConnectionId = getTestConnectionId(0); - conn->serverConnectionId = getTestConnectionId(1); - auto stream = conn->streamManager->createNextBidirectionalStream().value(); - ASSERT_FALSE(writeDataToQuicStream( - *stream, - folly::IOBuf::copyBuffer("Big ship stucks in small water"), - false) - .hasError()); - ASSERT_FALSE( - writeBufMetaToQuicStream(*stream, BufferMeta(1000), true).hasError()); - auto bufMetaStartingOffset = stream->writeBufMeta.offset; - handleStreamBufMetaWritten( - *conn, - *stream, - bufMetaStartingOffset, - 300, - false, - 1, - PacketNumberSpace::AppData); - ASSERT_NE( - stream->retransmissionBufMetas.end(), - stream->retransmissionBufMetas.find(bufMetaStartingOffset)); - WriteStreamFrame frame(stream->id, bufMetaStartingOffset, 300, false); - frame.fromBufMeta = true; - auto result = sendAckSMHandler(*stream, frame); - ASSERT_FALSE(result.hasError()); - EXPECT_TRUE(stream->retransmissionBufMetas.empty()); - EXPECT_EQ(stream->sendState, StreamSendState::Open); -} - -TEST_F(QuicOpenStateTest, DSRFullStreamAcked) { - auto conn = createConn(); - conn->clientConnectionId = getTestConnectionId(0); - conn->serverConnectionId = getTestConnectionId(1); - auto stream = conn->streamManager->createNextBidirectionalStream().value(); - auto buf = folly::IOBuf::copyBuffer("Big ship stucks in small water"); - size_t len = buf->computeChainDataLength(); - ASSERT_FALSE( - writeDataToQuicStream(*stream, std::move(buf), false).hasError()); - ASSERT_FALSE(handleStreamWritten( - *conn, *stream, 0, len, false, 1, PacketNumberSpace::AppData) - .hasError()); - ASSERT_EQ(stream->retransmissionBuffer.size(), 1); - ASSERT_FALSE( - writeBufMetaToQuicStream(*stream, BufferMeta(1000), true).hasError()); - auto bufMetaStartingOffset = stream->writeBufMeta.offset; - handleStreamBufMetaWritten( - *conn, - *stream, - bufMetaStartingOffset, - 1000, - true, - 1, - PacketNumberSpace::AppData); - ASSERT_EQ(stream->pendingWrites.chainLength(), 0); - ASSERT_NE( - stream->retransmissionBufMetas.end(), - stream->retransmissionBufMetas.find(bufMetaStartingOffset)); - WriteStreamFrame frame(stream->id, bufMetaStartingOffset, 1000, true); - frame.fromBufMeta = true; - auto result = sendAckSMHandler(*stream, frame); - ASSERT_FALSE(result.hasError()); - frame.offset = 0; - frame.len = len; - frame.fin = false; - frame.fromBufMeta = false; - result = sendAckSMHandler(*stream, frame); - ASSERT_FALSE(result.hasError()); - EXPECT_TRUE(stream->retransmissionBuffer.empty()); - EXPECT_TRUE(stream->retransmissionBufMetas.empty()); - EXPECT_EQ(stream->sendState, StreamSendState::Closed); -} - } // namespace quic::test diff --git a/quic/state/test/AckHandlersTest.cpp b/quic/state/test/AckHandlersTest.cpp index 10cf9bfae..aa0e89323 100644 --- a/quic/state/test/AckHandlersTest.cpp +++ b/quic/state/test/AckHandlersTest.cpp @@ -81,8 +81,6 @@ auto emplacePackets( 0, OutstandingPacketMetadata::DetailsPerStream()); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } } @@ -199,8 +197,6 @@ TEST_P(AckHandlersTest, TestAckMultipleSequentialBlocks) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } ReadAckFrame ackFrame; ackFrame.largestAcked = 101; @@ -280,8 +276,6 @@ TEST_P(AckHandlersTest, TestAckWithECN) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; // To enable accounting of sent marked packets conn.ecnState = ECNState::ValidatedL4S; @@ -364,8 +358,6 @@ TEST_P(AckHandlersTest, TestSpuriousLossFullRemoval) { 0, OutstandingPacketMetadata::DetailsPerStream()); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; // setting a very low reordering threshold to force loss by reorder conn.lossState.reorderingThreshold = 1; @@ -379,10 +371,8 @@ TEST_P(AckHandlersTest, TestSpuriousLossFullRemoval) { // Update the ackState // Both largestAckedByPeer (packet num) and - // largestNonDsrSequenceNumberAckedByPeer (sequence num) need to be updated to // exercise loss by reorder path auto& ackState = getAckState(conn, GetParam().pnSpace); - ackState.largestNonDsrSequenceNumberAckedByPeer = 4; ackState.largestAckedByPeer = 4; ASSERT_FALSE( detectLossPackets( @@ -456,8 +446,6 @@ TEST_P(AckHandlersTest, TestSpuriousLossSplitMiddleRemoval) { 0, OutstandingPacketMetadata::DetailsPerStream()); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; // setting a very low reordering threshold to force loss by reorder conn.lossState.reorderingThreshold = 1; @@ -471,10 +459,8 @@ TEST_P(AckHandlersTest, TestSpuriousLossSplitMiddleRemoval) { // Update the ackState // Both largestAckedByPeer (packet num) and - // largestNonDsrSequenceNumberAckedByPeer (sequence num) need to be updated to // exercise loss by reorder path auto& ackState = getAckState(conn, GetParam().pnSpace); - ackState.largestNonDsrSequenceNumberAckedByPeer = 4; ackState.largestAckedByPeer = 4; ASSERT_FALSE( detectLossPackets( @@ -554,8 +540,6 @@ TEST_P(AckHandlersTest, TestSpuriousLossTrimFrontRemoval) { 0, OutstandingPacketMetadata::DetailsPerStream()); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; // setting a very low reordering threshold to force loss by reorder conn.lossState.reorderingThreshold = 1; @@ -569,10 +553,8 @@ TEST_P(AckHandlersTest, TestSpuriousLossTrimFrontRemoval) { // Update the ackState // Both largestAckedByPeer (packet num) and - // largestNonDsrSequenceNumberAckedByPeer (sequence num) need to be updated to // exercise loss by reorder path auto& ackState = getAckState(conn, GetParam().pnSpace); - ackState.largestNonDsrSequenceNumberAckedByPeer = 4; ackState.largestAckedByPeer = 4; ASSERT_FALSE( detectLossPackets( @@ -648,8 +630,6 @@ TEST_P(AckHandlersTest, TestSpuriousLossSplitFrontRemoval) { 0, OutstandingPacketMetadata::DetailsPerStream()); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; // setting a very low reordering threshold to force loss by reorder conn.lossState.reorderingThreshold = 1; @@ -663,10 +643,8 @@ TEST_P(AckHandlersTest, TestSpuriousLossSplitFrontRemoval) { // Update the ackState // Both largestAckedByPeer (packet num) and - // largestNonDsrSequenceNumberAckedByPeer (sequence num) need to be updated to // exercise loss by reorder path auto& ackState = getAckState(conn, GetParam().pnSpace); - ackState.largestNonDsrSequenceNumberAckedByPeer = 4; ackState.largestAckedByPeer = 4; ASSERT_FALSE( detectLossPackets( @@ -741,8 +719,6 @@ TEST_P(AckHandlersTest, TestPacketDestructionAcks) { OutstandingPacketMetadata::DetailsPerStream(), 0us, packetDestroyFn); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } EXPECT_EQ(conn.outstandings.packets.size(), 3); @@ -825,16 +801,12 @@ TEST_P(AckHandlersTest, TestPacketDestructionSpuriousLoss) { OutstandingPacketMetadata::DetailsPerStream(), 0us, packetDestroyFn); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } EXPECT_EQ(conn.outstandings.packets.size(), 3); // Update the ackState // Both largestAckedByPeer (packet num) and - // largestNonDsrSequenceNumberAckedByPeer (sequence num) need to be updated to // exercise loss by reorder path auto& ackState = getAckState(conn, GetParam().pnSpace); - ackState.largestNonDsrSequenceNumberAckedByPeer = 3; ackState.largestAckedByPeer = 3; ASSERT_FALSE(detectLossPackets( conn, @@ -896,8 +868,6 @@ TEST_P(AckHandlersTest, TestPacketDestructionSpuriousLoss) { OutstandingPacketMetadata::DetailsPerStream(), 0us, packetDestroyFn); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } // Send ACK for #4, which should clear # 1 as well. @@ -978,8 +948,6 @@ TEST_P(AckHandlersTest, TestPacketDestructionBigDeque) { OutstandingPacketMetadata::DetailsPerStream(), 0us, packetDestroyFn); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } EXPECT_EQ(conn.outstandings.packets.size(), 1000); @@ -1097,8 +1065,6 @@ TEST_P(AckHandlersTest, TestAckMultipleSequentialBlocksLoss) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } ReadAckFrame ackFrame; ackFrame.largestAcked = 101; @@ -1269,8 +1235,6 @@ TEST_P(AckHandlersTest, TestAckBlocksWithGaps) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } ReadAckFrame ackFrame; @@ -1395,8 +1359,6 @@ TEST_P(AckHandlersTest, TestNonSequentialPacketNumbers) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } for (PacketNum packetNum = 20; packetNum < 40; packetNum += 3) { @@ -1417,8 +1379,6 @@ TEST_P(AckHandlersTest, TestNonSequentialPacketNumbers) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } ReadAckFrame ackFrame; @@ -1520,8 +1480,6 @@ TEST_P(AckHandlersTest, AckVisitorForAckTest) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; auto secondPacket = createNewPacket(101 /* packetNum */, GetParam().pnSpace); WriteAckFrame secondAckFrame; @@ -1542,8 +1500,6 @@ TEST_P(AckHandlersTest, AckVisitorForAckTest) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; ReadAckFrame firstReceivedAck; firstReceivedAck.largestAcked = 100; @@ -1633,8 +1589,6 @@ TEST_P(AckHandlersTest, NoNewAckedPacket) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; ReadAckFrame ackFrame; ackFrame.largestAcked = 5; @@ -1703,8 +1657,6 @@ TEST_P(AckHandlersTest, AckPacketNumDoesNotExist) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; PacketNum packetNum2 = 10; auto regularPacket2 = createNewPacket(packetNum2, GetParam().pnSpace); @@ -1720,8 +1672,6 @@ TEST_P(AckHandlersTest, AckPacketNumDoesNotExist) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; // Ack a packet one higher than the packet so that we don't trigger // reordering threshold. @@ -1769,8 +1719,6 @@ TEST_P(AckHandlersTest, TestHandshakeCounterUpdate) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } ReadAckFrame ackFrame; @@ -1985,8 +1933,6 @@ TEST_P(AckHandlersTest, NoSkipAckVisitor) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; ReadAckFrame ackFrame; ackFrame.largestAcked = 0; @@ -2125,8 +2071,6 @@ TEST_P(AckHandlersTest, MultiplePacketProcessors) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; } ReadAckFrame ackFrame; @@ -2356,8 +2300,6 @@ TEST_P(AckHandlersTest, UpdateMaxAckDelay) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; ReadAckFrame ackFrame; // ackDelay has no effect on mrtt @@ -2494,8 +2436,6 @@ TEST_P(AckHandlersTest, UpdatePendingAckStates) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; conn.lossState.totalBytesSent += 111; conn.lossState.totalBodyBytesSent += 100; @@ -2569,8 +2509,6 @@ TEST_P(AckHandlersTest, AckEventCreation) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = (packetNum % 2); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -2699,8 +2637,6 @@ TEST_P(AckHandlersTest, AckEventCreationSingleWrite) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = (packetNum % 2); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -2830,8 +2766,6 @@ TEST_P(AckHandlersTest, AckEventCreationNoCongestionController) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = (packetNum % 2); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -3592,8 +3526,6 @@ TEST_P(AckHandlersTest, AckEventCreationInvalidAckDelay) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = (packetNum % 2); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -3700,8 +3632,6 @@ TEST_P(AckHandlersTest, AckEventCreationRttMinusAckDelayIsZero) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = (packetNum % 2); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -3815,8 +3745,6 @@ TEST_P(AckHandlersTest, AckEventCreationReorderingLargestPacketAcked) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = (packetNum % 2); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -4059,8 +3987,6 @@ TEST_P(AckHandlersTest, AckEventCreationNoMatchingPacketDueToLoss) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = false; conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -4208,8 +4134,6 @@ TEST_P(AckHandlersTest, ImplictAckEventCreation) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = (packetNum % 2); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -4314,8 +4238,6 @@ TEST_P(AckHandlersTest, ObserverRttSample) { OutstandingPacketMetadata::DetailsPerStream()); sentPacket.isAppLimited = false; conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; packetNum++; } @@ -4443,10 +4365,8 @@ TEST_P(AckHandlersTest, ObserverSpuriousLostEventReorderThreshold) { .Times(1); // Update the ackState // Both largestAckedByPeer (packet num) and - // largestNonDsrSequenceNumberAckedByPeer (sequence num) need to be updated to // exercise loss by reorder path auto& ackState = getAckState(conn, GetParam().pnSpace); - ackState.largestNonDsrSequenceNumberAckedByPeer = 4; ackState.largestAckedByPeer = 4; ASSERT_FALSE(detectLossPackets( conn, @@ -4545,10 +4465,8 @@ TEST_P(AckHandlersTest, ObserverSpuriousLostEventTimeout) { // Update the ackState // Both largestAckedByPeer (packet num) and - // largestNonDsrSequenceNumberAckedByPeer (sequence num) need to be updated to // exercise loss by reorder path auto& ackState = getAckState(conn, GetParam().pnSpace); - ackState.largestNonDsrSequenceNumberAckedByPeer = 10; ackState.largestAckedByPeer = 10; ASSERT_FALSE(detectLossPackets( conn, @@ -4620,8 +4538,6 @@ TEST_P(AckHandlersTest, SubMicrosecondRTT) { LossState(), 0, OutstandingPacketMetadata::DetailsPerStream()); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, GetParam().pnSpace).nonDsrPacketSequenceNumber++; ReadAckFrame ackFrame; auto ackReceiveTime = packetSendTime + 400ns; @@ -4785,8 +4701,7 @@ class AckEventForAppDataTest : public Test { packet.packet, timepoint, getEncodedSize(packet), - getEncodedBodySize(packet), - false /* isDSRPacket */) + getEncodedBodySize(packet)) .hasError()); } @@ -7886,8 +7801,6 @@ TEST_P(AckHandlersTest, InflightBytesDecrementOnAckIncludesLostBytes) { OutstandingPacketMetadata::DetailsPerStream()); conn.outstandings.packets.emplace_back(std::move(sentPacket)); - conn.outstandings.packets.back().nonDsrPacketSequenceNumber = - getAckState(conn, pnSpace).nonDsrPacketSequenceNumber++; inflightAtSend += kPktSize; } diff --git a/quic/state/test/MockQuicStats.h b/quic/state/test/MockQuicStats.h index 2a474b1e6..a4d0ec429 100644 --- a/quic/state/test/MockQuicStats.h +++ b/quic/state/test/MockQuicStats.h @@ -22,7 +22,6 @@ class MockQuicStats : public QuicTransportStatsCallback { MOCK_METHOD(void, onOutOfOrderPacketReceived, ()); MOCK_METHOD(void, onPacketProcessed, ()); MOCK_METHOD(void, onPacketSent, ()); - MOCK_METHOD(void, onDSRPacketSent, (size_t)); MOCK_METHOD(void, onPacketRetransmission, ()); MOCK_METHOD(void, onPacketLoss, ()); MOCK_METHOD(void, onPacketSpuriousLoss, ()); diff --git a/quic/state/test/QuicStreamFunctionsTest.cpp b/quic/state/test/QuicStreamFunctionsTest.cpp index f476294c6..de28cd846 100644 --- a/quic/state/test/QuicStreamFunctionsTest.cpp +++ b/quic/state/test/QuicStreamFunctionsTest.cpp @@ -2224,14 +2224,6 @@ TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAcked) { EXPECT_TRUE(allBytesTillFinAcked(stream)); } -TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedDSR) { - StreamId id = 3; - QuicStreamState stream(id, conn); - stream.finalWriteOffset = 1; - stream.writeBufMeta.offset = 2; - EXPECT_TRUE(allBytesTillFinAcked(stream)); -} - TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedFinOnly) { StreamId id = 3; QuicStreamState stream(id, conn); @@ -2240,14 +2232,6 @@ TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedFinOnly) { EXPECT_TRUE(allBytesTillFinAcked(stream)); } -TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedFinOnlyDSR) { - StreamId id = 3; - QuicStreamState stream(id, conn); - stream.finalWriteOffset = 0; - stream.writeBufMeta.offset = 1; - EXPECT_TRUE(allBytesTillFinAcked(stream)); -} - TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedNewStream) { StreamId id = 3; QuicStreamState stream(id, conn); @@ -2264,19 +2248,6 @@ TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedStillLost) { EXPECT_FALSE(allBytesTillFinAcked(stream)); } -TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedStillLostDSR) { - StreamId id = 3; - QuicStreamState stream(id, conn); - stream.finalWriteOffset = 20; - stream.writeBufMeta.offset = 21; - WriteBufferMeta::Builder b; - b.setLength(10); - b.setOffset(10); - b.setEOF(false); - stream.lossBufMetas.emplace_back(b.build()); - EXPECT_FALSE(allBytesTillFinAcked(stream)); -} - TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedStillRetransmitting) { StreamId id = 3; QuicStreamState stream(id, conn); @@ -2290,20 +2261,6 @@ TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedStillRetransmitting) { EXPECT_FALSE(allBytesTillFinAcked(stream)); } -TEST_P( - QuicStreamFunctionsTestBase, - AllBytesTillFinAckedStillRetransmittingDSR) { - StreamId id = 3; - QuicStreamState stream(id, conn); - stream.finalWriteOffset = 12; - WriteBufferMeta::Builder b; - b.setLength(10); - b.setOffset(10); - b.setEOF(false); - stream.retransmissionBufMetas.emplace(0, b.build()); - EXPECT_FALSE(allBytesTillFinAcked(stream)); -} - TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedStillWriting) { StreamId id = 3; QuicStreamState stream(id, conn); @@ -2314,14 +2271,6 @@ TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedStillWriting) { EXPECT_FALSE(allBytesTillFinAcked(stream)); } -TEST_P(QuicStreamFunctionsTestBase, AllBytesTillFinAckedStillWritingDSR) { - StreamId id = 3; - QuicStreamState stream(id, conn); - stream.finalWriteOffset = 10; - stream.writeBufMeta.length = 10; - EXPECT_FALSE(allBytesTillFinAcked(stream)); -} - TEST_F(QuicServerStreamFunctionsTest, TestAppendPendingStreamResetAllData) { StreamId id = 3; QuicStreamState stream(id, conn); @@ -2411,30 +2360,12 @@ TEST_P(QuicStreamFunctionsTestBase, LargestWriteOffsetSeenNoFIN) { EXPECT_EQ(120, getLargestWriteOffsetSeen(stream)); } -TEST_P(QuicStreamFunctionsTestBase, LargestWriteOffsetSeenDSRNoFIN) { - QuicStreamState stream(3, conn); - stream.currentWriteOffset = 10; - stream.writeBufMeta.offset = 100; - stream.writeBufMeta.length = 20; - EXPECT_EQ(120, getLargestWriteOffsetSeen(stream)); -} - TEST_P(QuicStreamFunctionsTestBase, StreamLargestWriteOffsetTxedNothingTxed) { QuicStreamState stream(3, conn); stream.currentWriteOffset = 0; - stream.writeBufMeta.offset = 0; EXPECT_EQ(std::nullopt, getLargestWriteOffsetTxed(stream)); } -TEST_F( - QuicStreamFunctionsTest, - StreamLargestWriteOffsetTxedNothingTxedDSRTxed) { - QuicStreamState stream(3, conn); - stream.currentWriteOffset = 0; - stream.writeBufMeta.offset = 55; - EXPECT_EQ(54, getLargestWriteOffsetTxed(stream).value()); -} - TEST_P(QuicStreamFunctionsTestBase, StreamLargestWriteOffsetTxedOneByteTxed) { QuicStreamState stream(3, conn); stream.currentWriteOffset = 1; @@ -2442,16 +2373,6 @@ TEST_P(QuicStreamFunctionsTestBase, StreamLargestWriteOffsetTxedOneByteTxed) { EXPECT_EQ(0, getLargestWriteOffsetTxed(stream).value()); } -TEST_P( - QuicStreamFunctionsTestBase, - StreamLargestWriteOffsetTxedOneByteDSRTxed) { - QuicStreamState stream(3, conn); - stream.currentWriteOffset = 1; - stream.writeBufMeta.offset = 2; - ASSERT_TRUE(getLargestWriteOffsetTxed(stream).has_value()); - EXPECT_EQ(1, getLargestWriteOffsetTxed(stream).value()); -} - TEST_P( QuicStreamFunctionsTestBase, StreamLargestWriteOffsetTxedHundredBytesTxed) { @@ -2461,16 +2382,6 @@ TEST_P( EXPECT_EQ(99, getLargestWriteOffsetTxed(stream).value()); } -TEST_F( - QuicStreamFunctionsTest, - StreamLargestWriteOffsetTxedHundredBytesDSRTxed) { - QuicStreamState stream(3, conn); - stream.currentWriteOffset = 10; - stream.writeBufMeta.offset = 100; - ASSERT_TRUE(getLargestWriteOffsetTxed(stream).has_value()); - EXPECT_EQ(99, getLargestWriteOffsetTxed(stream).value()); -} - TEST_F( QuicStreamFunctionsTest, StreamLargestWriteOffsetTxedIgnoreFinalWriteOffset) { @@ -2483,19 +2394,6 @@ TEST_F( EXPECT_EQ(9, getLargestWriteOffsetTxed(stream).value()); } -TEST_F( - QuicStreamFunctionsTest, - StreamLargestWriteOffsetTxedDSRIgnoreFinalWriteOffset) { - // finalWriteOffset is set when writeChain is called with EoR, but we should - // always use currentWriteOffset to determine how many bytes have been TXed - QuicStreamState stream(3, conn); - stream.currentWriteOffset = 1; - stream.writeBufMeta.offset = 10; - stream.finalWriteOffset = 100; - ASSERT_TRUE(getLargestWriteOffsetTxed(stream).has_value()); - EXPECT_EQ(9, getLargestWriteOffsetTxed(stream).value()); -} - TEST_P(QuicStreamFunctionsTestBase, StreamNextOffsetToDeliverNothingAcked) { QuicStreamState stream(3, conn); stream.currentWriteOffset = 100; @@ -2533,31 +2431,6 @@ TEST_P(QuicStreamFunctionsTestBase, LossBufferHasData) { EXPECT_TRUE(conn.streamManager->hasLoss()); } -TEST_P(QuicStreamFunctionsTestBase, LossBufferMetaHasData) { - StreamId id = 4; - QuicStreamState stream(id, conn); - WriteBufferMeta::Builder b; - b.setLength(10); - b.setOffset(10); - b.setEOF(false); - stream.lossBufMetas.emplace_back(b.build()); - conn.streamManager->updateWritableStreams(stream); - EXPECT_TRUE(conn.streamManager->hasLoss()); -} - -TEST_P(QuicStreamFunctionsTestBase, LossBufferMetaStillHasData) { - StreamId id = 4; - QuicStreamState stream(id, conn); - conn.streamManager->addLoss(id); - WriteBufferMeta::Builder b; - b.setLength(10); - b.setOffset(10); - b.setEOF(false); - stream.lossBufMetas.emplace_back(b.build()); - conn.streamManager->updateWritableStreams(stream); - EXPECT_TRUE(conn.streamManager->hasLoss()); -} - TEST_P(QuicStreamFunctionsTestBase, LossBufferStillHasData) { StreamId id = 4; QuicStreamState stream(id, conn); diff --git a/quic/state/test/QuicStreamManagerTest.cpp b/quic/state/test/QuicStreamManagerTest.cpp index 277e62a61..e0171684b 100644 --- a/quic/state/test/QuicStreamManagerTest.cpp +++ b/quic/state/test/QuicStreamManagerTest.cpp @@ -728,31 +728,6 @@ TEST_P(QuicStreamManagerTest, TestUnidirectionalStreamsSeparateSetTwoStreams) { EXPECT_EQ(manager.readableUnidirectionalStreams().size(), 1); } -TEST_P(QuicStreamManagerTest, WriteBufferMeta) { - auto& manager = *conn.streamManager; - auto streamResult = manager.createNextUnidirectionalStream(); - ASSERT_TRUE(streamResult.has_value()); - auto* stream = streamResult.value(); - - // Add some real data into write buffer - ASSERT_FALSE( - writeDataToQuicStream(*stream, folly::IOBuf::copyBuffer("prefix"), false) - .hasError()); - // Artificially remove the stream from writable queue, so that any further - // writable query is about the DSR state. - manager.removeWritable(*stream); - - BufferMeta bufferMeta(200); - ASSERT_FALSE(writeBufMetaToQuicStream(*stream, bufferMeta, true).hasError()); - EXPECT_TRUE(stream->hasWritableBufMeta()); - EXPECT_TRUE(manager.hasWritable()); // Checks combined queues - - stream->sendState = StreamSendState::Closed; - stream->recvState = StreamRecvState::Closed; - ASSERT_FALSE(manager.removeClosedStream(stream->id).hasError()); - EXPECT_TRUE(manager.writableDSRStreams().empty()); -} - TEST_P(QuicStreamManagerTest, RemoveResetsUponClosure) { auto& manager = *conn.streamManager; auto streamResult = manager.createNextBidirectionalStream(); diff --git a/quic/state/test/StreamDataTest.cpp b/quic/state/test/StreamDataTest.cpp index d645c1e39..fd77effb5 100644 --- a/quic/state/test/StreamDataTest.cpp +++ b/quic/state/test/StreamDataTest.cpp @@ -282,269 +282,6 @@ TEST(StreamDataTest, PendingWritesRemovalNoChange) { EXPECT_EQ(state.pendingWrites.chainLength(), 8); } -TEST(StreamDataTest, LossBufferMetaRemovalAll) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [1, 2] [5, 12] [17, 19] - WriteBufferMeta wbm1 = WriteBufferMeta::Builder() - .setOffset(1) - .setLength(2) - .setEOF(false) - .build(); - WriteBufferMeta wbm2 = WriteBufferMeta::Builder() - .setOffset(5) - .setLength(8) - .setEOF(false) - .build(); - WriteBufferMeta wbm3 = WriteBufferMeta::Builder() - .setOffset(17) - .setLength(3) - .setEOF(false) - .build(); - state.insertIntoLossBufMeta(wbm1); - state.insertIntoLossBufMeta(wbm2); - state.insertIntoLossBufMeta(wbm3); - - state.removeFromLossBufMetasStartingAtOffset(1); - - EXPECT_EQ(state.lossBufMetas.size(), 0); -} - -TEST(StreamDataTest, LossBufferMetaRemovalExactMatch) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [1, 2] [5, 12] [17, 19] - WriteBufferMeta wbm1 = WriteBufferMeta::Builder() - .setOffset(1) - .setLength(2) - .setEOF(false) - .build(); - WriteBufferMeta wbm2 = WriteBufferMeta::Builder() - .setOffset(5) - .setLength(8) - .setEOF(false) - .build(); - WriteBufferMeta wbm3 = WriteBufferMeta::Builder() - .setOffset(17) - .setLength(3) - .setEOF(false) - .build(); - state.insertIntoLossBufMeta(wbm1); - state.insertIntoLossBufMeta(wbm2); - state.insertIntoLossBufMeta(wbm3); - - state.removeFromLossBufMetasStartingAtOffset(5); - EXPECT_EQ(state.lossBufMetas.size(), 1); - EXPECT_EQ(state.lossBufMetas[0].offset, 1); - EXPECT_EQ(state.lossBufMetas[0].length, 2); -} - -TEST(StreamDataTest, LossBufferMetaRemovalPartialMatch) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [1, 2] [5, 12] [17, 19] - WriteBufferMeta wbm1 = WriteBufferMeta::Builder() - .setOffset(1) - .setLength(2) - .setEOF(false) - .build(); - WriteBufferMeta wbm2 = WriteBufferMeta::Builder() - .setOffset(5) - .setLength(8) - .setEOF(false) - .build(); - WriteBufferMeta wbm3 = WriteBufferMeta::Builder() - .setOffset(17) - .setLength(3) - .setEOF(false) - .build(); - state.insertIntoLossBufMeta(wbm1); - state.insertIntoLossBufMeta(wbm2); - state.insertIntoLossBufMeta(wbm3); - - state.removeFromLossBufMetasStartingAtOffset(6); - EXPECT_EQ(state.lossBufMetas.size(), 2); - - EXPECT_EQ(state.lossBufMetas[0].offset, 1); - EXPECT_EQ(state.lossBufMetas[0].length, 2); - - EXPECT_EQ(state.lossBufMetas[1].offset, 5); - EXPECT_EQ(state.lossBufMetas[1].length, 1); -} - -TEST(StreamDataTest, LossBufferMetaRemovalNoMatch) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [1, 2] [5, 12] [17, 19] - WriteBufferMeta wbm1 = WriteBufferMeta::Builder() - .setOffset(1) - .setLength(2) - .setEOF(false) - .build(); - WriteBufferMeta wbm2 = WriteBufferMeta::Builder() - .setOffset(5) - .setLength(8) - .setEOF(false) - .build(); - WriteBufferMeta wbm3 = WriteBufferMeta::Builder() - .setOffset(17) - .setLength(3) - .setEOF(false) - .build(); - state.insertIntoLossBufMeta(wbm1); - state.insertIntoLossBufMeta(wbm2); - state.insertIntoLossBufMeta(wbm3); - - state.removeFromLossBufStartingAtOffset(21); - EXPECT_EQ(state.lossBufMetas.size(), 3); - - EXPECT_EQ(state.lossBufMetas[0].offset, 1); - EXPECT_EQ(state.lossBufMetas[0].length, 2); - - EXPECT_EQ(state.lossBufMetas[1].offset, 5); - EXPECT_EQ(state.lossBufMetas[1].length, 8); - - EXPECT_EQ(state.lossBufMetas[2].offset, 17); - EXPECT_EQ(state.lossBufMetas[2].length, 3); -} - -TEST(StreamDataTest, RetxBufferMetaRemovalAll) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [1, 2] [5, 12] [17, 19] - WriteBufferMeta wbm1 = WriteBufferMeta::Builder() - .setOffset(1) - .setLength(2) - .setEOF(false) - .build(); - WriteBufferMeta wbm2 = WriteBufferMeta::Builder() - .setOffset(5) - .setLength(8) - .setEOF(false) - .build(); - WriteBufferMeta wbm3 = WriteBufferMeta::Builder() - .setOffset(17) - .setLength(3) - .setEOF(false) - .build(); - state.retransmissionBufMetas.emplace(1, wbm1); - state.retransmissionBufMetas.emplace(5, wbm2); - state.retransmissionBufMetas.emplace(17, wbm3); - - state.removeFromRetransmissionBufMetasStartingAtOffset(1); - EXPECT_EQ(state.retransmissionBufMetas.size(), 0); -} - -TEST(StreamDataTest, RetxBufferMetaRemovalExactMatch) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [1, 2] [5, 12] [17, 19] - WriteBufferMeta wbm1 = WriteBufferMeta::Builder() - .setOffset(1) - .setLength(2) - .setEOF(false) - .build(); - WriteBufferMeta wbm2 = WriteBufferMeta::Builder() - .setOffset(5) - .setLength(8) - .setEOF(false) - .build(); - WriteBufferMeta wbm3 = WriteBufferMeta::Builder() - .setOffset(17) - .setLength(3) - .setEOF(false) - .build(); - state.retransmissionBufMetas.emplace(1, wbm1); - state.retransmissionBufMetas.emplace(5, wbm2); - state.retransmissionBufMetas.emplace(17, wbm3); - - state.removeFromRetransmissionBufMetasStartingAtOffset(17); - EXPECT_EQ(state.retransmissionBufMetas.size(), 2); - - EXPECT_EQ(state.retransmissionBufMetas[1].offset, 1); - EXPECT_EQ(state.retransmissionBufMetas[1].length, 2); - - EXPECT_EQ(state.retransmissionBufMetas[5].offset, 5); - EXPECT_EQ(state.retransmissionBufMetas[5].length, 8); -} - -TEST(StreamDataTest, RetxBufferMetaRemovalPartialMatch) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [1, 2] [5, 12] [17, 19] - WriteBufferMeta wbm1 = WriteBufferMeta::Builder() - .setOffset(1) - .setLength(2) - .setEOF(false) - .build(); - WriteBufferMeta wbm2 = WriteBufferMeta::Builder() - .setOffset(5) - .setLength(8) - .setEOF(false) - .build(); - WriteBufferMeta wbm3 = WriteBufferMeta::Builder() - .setOffset(17) - .setLength(3) - .setEOF(false) - .build(); - state.retransmissionBufMetas.emplace(1, wbm1); - state.retransmissionBufMetas.emplace(5, wbm2); - state.retransmissionBufMetas.emplace(17, wbm3); - - state.removeFromRetransmissionBufMetasStartingAtOffset(6); - EXPECT_EQ(state.retransmissionBufMetas.size(), 2); - - EXPECT_EQ(state.retransmissionBufMetas[1].offset, 1); - EXPECT_EQ(state.retransmissionBufMetas[1].length, 2); - - EXPECT_EQ(state.retransmissionBufMetas[5].offset, 5); - EXPECT_EQ(state.retransmissionBufMetas[5].length, 1); -} - -TEST(StreamDataTest, RetxBufferMetaRemovalNoMatch) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [1, 2] [5, 12] [17, 19] - WriteBufferMeta wbm1 = WriteBufferMeta::Builder() - .setOffset(1) - .setLength(2) - .setEOF(false) - .build(); - WriteBufferMeta wbm2 = WriteBufferMeta::Builder() - .setOffset(5) - .setLength(8) - .setEOF(false) - .build(); - WriteBufferMeta wbm3 = WriteBufferMeta::Builder() - .setOffset(17) - .setLength(3) - .setEOF(false) - .build(); - state.retransmissionBufMetas.emplace(1, wbm1); - state.retransmissionBufMetas.emplace(5, wbm2); - state.retransmissionBufMetas.emplace(17, wbm3); - - state.removeFromRetransmissionBufMetasStartingAtOffset(20); - EXPECT_EQ(state.retransmissionBufMetas.size(), 3); - - EXPECT_EQ(state.retransmissionBufMetas[1].offset, 1); - EXPECT_EQ(state.retransmissionBufMetas[1].length, 2); - - EXPECT_EQ(state.retransmissionBufMetas[5].offset, 5); - EXPECT_EQ(state.retransmissionBufMetas[5].length, 8); - - EXPECT_EQ(state.retransmissionBufMetas[17].offset, 17); - EXPECT_EQ(state.retransmissionBufMetas[17].length, 3); -} - TEST(StreamDataTest, ReadBufferRemovalAll) { QuicConnectionStateBase qcsb(QuicNodeType::Client); QuicStreamState state(0, qcsb); @@ -650,46 +387,6 @@ TEST(StreamDataTest, ReadBufferRemovalNoMatch) { EXPECT_EQ(state.readBuffer[2].data.chainLength(), 3); } -TEST(StreamDataTest, WriteBufferMetaRemovalAll) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - // [5, 16] - state.writeBufMeta.offset = 5; - state.writeBufMeta.length = 12; - - state.removeFromWriteBufMetaStartingAtOffset(1); - EXPECT_EQ(state.writeBufMeta.length, 0); -} - -TEST(StreamDataTest, WriteBufferMetaRemoval) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - state.writeBufferStartOffset = 5; - - // [5, 16] - state.writeBufMeta.offset = 5; - state.writeBufMeta.length = 12; - - state.removeFromWriteBufMetaStartingAtOffset(6); - EXPECT_EQ(state.writeBufMeta.length, 1); -} - -TEST(StreamDataTest, WriteBufferMetaRemovalNoChange) { - QuicConnectionStateBase qcsb(QuicNodeType::Client); - QuicStreamState state(0, qcsb); - - state.writeBufferStartOffset = 5; - - // [5, 16] - state.writeBufMeta.offset = 5; - state.writeBufMeta.length = 12; - - state.removeFromWriteBufMetaStartingAtOffset(17); - EXPECT_EQ(state.writeBufMeta.length, 12); -} - TEST(StreamDataTest, AllBytesAckedTillEmptyAck) { QuicConnectionStateBase qcsb(QuicNodeType::Client); QuicStreamState state(0, qcsb); diff --git a/quic/tools/tperf/BUCK b/quic/tools/tperf/BUCK index ddc7da134..45f2a7d21 100644 --- a/quic/tools/tperf/BUCK +++ b/quic/tools/tperf/BUCK @@ -35,7 +35,6 @@ mvfst_cpp_library( ], deps = [ ":pacing_observer", - ":tperf_dsr_sender", "//fizz/crypto:utils", "//folly/stats:histogram", "//quic/common/test:test_utils", @@ -68,27 +67,6 @@ mvfst_cpp_binary( ], ) -mvfst_cpp_library( - name = "tperf_dsr_sender", - srcs = [ - "TperfDSRSender.cpp", - ], - headers = [ - "TperfDSRSender.h", - ], - deps = [ - "//quic/dsr/backend/test:test_utils", - ], - exported_deps = [ - "//folly:network_address", - "//quic/common/udpsocket:quic_async_udp_socket", - "//quic/dsr:dsr_packetization_request_sender", - "//quic/dsr:types", - "//quic/dsr/backend:dsr_packetizer", - "//quic/server:server", - ], -) - mvfst_cpp_library( name = "pacing_observer", headers = [ diff --git a/quic/tools/tperf/CMakeLists.txt b/quic/tools/tperf/CMakeLists.txt index 0e2220f7d..80b44436e 100644 --- a/quic/tools/tperf/CMakeLists.txt +++ b/quic/tools/tperf/CMakeLists.txt @@ -10,7 +10,6 @@ endif() add_executable( tperf tperf.cpp - TperfDSRSender.cpp TperfClient.cpp TperfServer.cpp ) @@ -31,7 +30,6 @@ target_link_libraries( Folly::folly fizz::fizz mvfst_test_utils - mvfst_dsr_backend ${GFLAGS_LIBRARIES} ${LIBGMOCK_LIBRARIES} ) diff --git a/quic/tools/tperf/TperfDSRSender.cpp b/quic/tools/tperf/TperfDSRSender.cpp deleted file mode 100644 index c52989dff..000000000 --- a/quic/tools/tperf/TperfDSRSender.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -namespace quic { - -TperfDSRSender::TperfDSRSender(BufPtr sendBuf, QuicAsyncUDPSocket& sock) - : sock_(sock), buf_(std::move(sendBuf)) {} - -bool TperfDSRSender::addSendInstruction(const SendInstruction& instruction) { - instructions_.push_back(instruction); - return true; -} - -void TperfDSRSender::setCipherInfo(CipherInfo info) { - CipherBuilder builder; - cipherPair_ = builder.buildCiphers( - fizz::TrafficKey{ - .key = std::move(info.trafficKey.key), - .iv = std::move(info.trafficKey.iv)}, - info.cipherSuite, - std::move(info.packetProtectionKey)); -} - -bool TperfDSRSender::flush() { - auto& firstInstruction = instructions_.front(); - RequestGroup prs{ - .dcid = firstInstruction.dcid, - .scid = firstInstruction.scid, - .clientAddress = firstInstruction.clientAddress, - .cipherPair = &cipherPair_, - .requests = {}}; - prs.requests.reserve(instructions_.size()); - for (const auto& instruction : instructions_) { - prs.requests.push_back( - test::sendInstructionToPacketizationRequest(instruction)); - } - quic::UdpSocketPacketGroupWriter packetGroupWriter(sock_, prs.clientAddress); - auto written = packetGroupWriter.writePacketsGroup( - prs, [=, this](const PacketizationRequest& req) { - BufPtr buf; - uint64_t remainingLen = req.len; - do { - buf = buf_->clone(); - uint64_t appendLen = - std::min(remainingLen, buf->capacity()); - buf->append(appendLen); - remainingLen -= appendLen; - } while (buf->length() < req.len); - return buf; - }); - instructions_.clear(); - return written.packetsSent > 0; -} - -void TperfDSRSender::release() {} -} // namespace quic diff --git a/quic/tools/tperf/TperfDSRSender.h b/quic/tools/tperf/TperfDSRSender.h deleted file mode 100644 index 9e1774b46..000000000 --- a/quic/tools/tperf/TperfDSRSender.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include -#include - -#pragma once - -namespace quic { - -/** - * This is a implementtion of DSRPacketizationRequestSender that directly calls - * the backend writePacketsGroup API within itself. It's completely in-process - * with no RPC involved. It also shares the AsyncUDPSockets with the - * TperfServer' QuicServerTransports instead of creating one within itself. - * - * The bytes it sends out are random. - * - * The main purpose of this sender is to sanity test DSR APIs in QUIC transport. - */ -class TperfDSRSender : public DSRPacketizationRequestSender { - public: - TperfDSRSender(BufPtr sendBuf, QuicAsyncUDPSocket& sock); - - bool addSendInstruction(const SendInstruction&) override; - - bool flush() override; - - void release() override; - - void setCipherInfo(CipherInfo info); - - private: - std::vector instructions_; - QuicAsyncUDPSocket& sock_; - CipherPair cipherPair_; - BufPtr buf_; -}; - -} // namespace quic diff --git a/quic/tools/tperf/TperfServer.cpp b/quic/tools/tperf/TperfServer.cpp index 5fae2037b..27bf5066a 100644 --- a/quic/tools/tperf/TperfServer.cpp +++ b/quic/tools/tperf/TperfServer.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include namespace quic::tperf { @@ -29,7 +28,6 @@ class ServerStreamHandler : public quic::QuicSocket::ConnectionSetupCallback, uint32_t numStreams, uint64_t maxBytesPerStream, folly::AsyncUDPSocket& sock, - bool dsrEnabled, uint32_t burstDeadlineMs, uint64_t maxPacingRate, TPerfServer::DoneCallback* doneCallback) @@ -38,7 +36,6 @@ class ServerStreamHandler : public quic::QuicSocket::ConnectionSetupCallback, blockSize_(blockSize), numStreams_(numStreams), maxBytesPerStream_(maxBytesPerStream), - dsrEnabled_(dsrEnabled), burstDeadlineMs_(burstDeadlineMs), maxPacingRate_(maxPacingRate), doneCallback_(doneCallback) { @@ -189,11 +186,7 @@ class ServerStreamHandler : public quic::QuicSocket::ConnectionSetupCallback, eof = true; } } - if (dsrEnabled_ && (((id - 3) / 4) % 2) == 0) { - dsrSend(id, toSend, eof); - } else { - regularSend(id, toSend, eof); - } + regularSend(id, toSend, eof); if (!eof) { notifyDataForStream(id); } else { @@ -213,33 +206,6 @@ class ServerStreamHandler : public quic::QuicSocket::ConnectionSetupCallback, } private: - void dsrSend(quic::StreamId id, uint64_t toSend, bool eof) { - if (streamsHavingDSRSender_.find(id) == streamsHavingDSRSender_.end()) { - auto dsrSender = - std::make_unique(buf_->clone(), udpSock_); - auto serverTransport = dynamic_cast(sock_.get()); - dsrSender->setCipherInfo(serverTransport->getOneRttCipherInfo()); - auto res = - sock_->setDSRPacketizationRequestSender(id, std::move(dsrSender)); - if (res.hasError()) { - LOG(FATAL) << "Got error on write: " << quic::toString(res.error()); - } - // OK I don't know when to erase it... - streamsHavingDSRSender_.insert(id); - // Some real data has to be written before BufMeta is written, and we - // can only do it once: - res = sock_->writeChain(id, folly::IOBuf::copyBuffer("Lame"), false); - if (res.hasError()) { - LOG(FATAL) << "Got error on write: " << quic::toString(res.error()); - } - } - BufferMeta bufferMeta(toSend); - auto res = sock_->writeBufMeta(id, bufferMeta, eof, nullptr); - if (res.hasError()) { - LOG(FATAL) << "Got error on write: " << quic::toString(res.error()); - } - } - void regularSend(quic::StreamId id, uint64_t toSend, bool eof) { auto sendBuffer = buf_->clone(); sendBuffer->append(toSend); @@ -343,8 +309,6 @@ class ServerStreamHandler : public quic::QuicSocket::ConnectionSetupCallback, uint32_t numStreams_; uint64_t maxBytesPerStream_; std::unordered_map bytesPerStream_; - std::set streamsHavingDSRSender_; - bool dsrEnabled_; uint32_t burstDeadlineMs_; uint64_t maxPacingRate_; @@ -428,7 +392,6 @@ class TPerfServerTransportFactory : public quic::QuicServerTransportFactory { uint64_t blockSize, uint32_t numStreams, uint64_t maxBytesPerStream, - bool dsrEnabled, uint32_t burstDeadlineMs, uint64_t maxPacingRate, std::string qloggerPath, @@ -437,7 +400,6 @@ class TPerfServerTransportFactory : public quic::QuicServerTransportFactory { : blockSize_(blockSize), numStreams_(numStreams), maxBytesPerStream_(maxBytesPerStream), - dsrEnabled_(dsrEnabled), burstDeadlineMs_(burstDeadlineMs), maxPacingRate_(maxPacingRate), qloggerPath_(qloggerPath), @@ -458,7 +420,6 @@ class TPerfServerTransportFactory : public quic::QuicServerTransportFactory { numStreams_, maxBytesPerStream_, *sock, - dsrEnabled_, burstDeadlineMs_, maxPacingRate_, doneCallback_); @@ -504,7 +465,6 @@ class TPerfServerTransportFactory : public quic::QuicServerTransportFactory { uint64_t blockSize_; uint32_t numStreams_; uint64_t maxBytesPerStream_; - bool dsrEnabled_; uint32_t burstDeadlineMs_; uint64_t maxPacingRate_; std::string qloggerPath_; @@ -526,7 +486,6 @@ TPerfServer::TPerfServer( uint64_t maxBytesPerStream, uint32_t maxReceivePacketSize, bool useInplaceWrite, - bool dsrEnabled, bool overridePacketSize, double latencyFactor, bool useAckReceiveTimestamps, @@ -610,7 +569,6 @@ TPerfServer::TPerfServer( blockSize, numStreams, maxBytesPerStream, - dsrEnabled, burstDeadlineMs_, maxPacingRate_, qloggerPath, diff --git a/quic/tools/tperf/TperfServer.h b/quic/tools/tperf/TperfServer.h index 3db3070e2..6baf49222 100644 --- a/quic/tools/tperf/TperfServer.h +++ b/quic/tools/tperf/TperfServer.h @@ -140,7 +140,6 @@ class TPerfServer { uint64_t maxBytesPerStream, uint32_t maxReceivePacketSize, bool useInplaceWrite, - bool dsrEnabled, bool overridePacketSize, double latencyFactor, bool useAckReceiveTimestamps, diff --git a/quic/tools/tperf/tperf.cpp b/quic/tools/tperf/tperf.cpp index 2cbc20c07..8a1d055c3 100644 --- a/quic/tools/tperf/tperf.cpp +++ b/quic/tools/tperf/tperf.cpp @@ -75,7 +75,6 @@ DEFINE_string( transport_knob_params, "", "JSON-serialized dictionary of transport knob params"); -DEFINE_bool(dsr, false, "if you want to debug perf"); DEFINE_bool( use_ack_receive_timestamps, false, @@ -147,7 +146,6 @@ int main(int argc, char* argv[]) { FLAGS_bytes_per_stream, FLAGS_max_receive_packet_size, FLAGS_use_inplace_write, - FLAGS_dsr, FLAGS_override_packet_size, FLAGS_latency_factor, FLAGS_use_ack_receive_timestamps,