mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-08-08 09:42:06 +03:00
Send windowed stream limit updates
Summary: Implement sending stream limit updates in a windowed fashion, so that as a peer exhausts its streams we will grant it additional credit. This is implemented by having the stream manager check if an update is needed on removing streams, and the api layer potentially sending an update after it initiates the check for closed streams. This also makes some driveby changes to use `std::lower_bound` instead of `std::find` for the sorted collections in the stream manager. Reviewed By: yangchi Differential Revision: D16808229 fbshipit-source-id: f6e3460d43e4d165e362164be00c0cec27cf1e79
This commit is contained in:
committed by
Facebook Github Bot
parent
7fa7277089
commit
72e677df33
@@ -1979,6 +1979,7 @@ void QuicTransportBase::checkForClosedStream() {
|
|||||||
stream->totalHolbTime.count(),
|
stream->totalHolbTime.count(),
|
||||||
stream->holbCount);
|
stream->holbCount);
|
||||||
conn_->streamManager->removeClosedStream(*itr);
|
conn_->streamManager->removeClosedStream(*itr);
|
||||||
|
maybeSendStreamLimitUpdates(*conn_);
|
||||||
readCallbacks_.erase(*itr);
|
readCallbacks_.erase(*itr);
|
||||||
peekCallbacks_.erase(*itr);
|
peekCallbacks_.erase(*itr);
|
||||||
itr = conn_->streamManager->closedStreams().erase(itr);
|
itr = conn_->streamManager->closedStreams().erase(itr);
|
||||||
@@ -2288,7 +2289,14 @@ void QuicTransportBase::cancelDeliveryCallbacks(
|
|||||||
|
|
||||||
void QuicTransportBase::setTransportSettings(
|
void QuicTransportBase::setTransportSettings(
|
||||||
TransportSettings transportSettings) {
|
TransportSettings transportSettings) {
|
||||||
|
// If we've already encoded the transport parameters, silently return as
|
||||||
|
// setting the transport settings again would be buggy.
|
||||||
|
// TODO should we throw or return Expected here?
|
||||||
|
if (conn_->transportParametersEncoded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
conn_->transportSettings = std::move(transportSettings);
|
conn_->transportSettings = std::move(transportSettings);
|
||||||
|
conn_->streamManager->refreshTransportSettings(conn_->transportSettings);
|
||||||
setCongestionControl(transportSettings.defaultCongestionController);
|
setCongestionControl(transportSettings.defaultCongestionController);
|
||||||
if (conn_->transportSettings.pacingEnabled) {
|
if (conn_->transportSettings.pacingEnabled) {
|
||||||
conn_->pacer = std::make_unique<DefaultPacer>(
|
conn_->pacer = std::make_unique<DefaultPacer>(
|
||||||
|
@@ -1110,4 +1110,15 @@ WriteDataReason hasNonAckDataToWrite(const QuicConnectionStateBase& conn) {
|
|||||||
}
|
}
|
||||||
return WriteDataReason::NO_WRITE;
|
return WriteDataReason::NO_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void maybeSendStreamLimitUpdates(QuicConnectionStateBase& conn) {
|
||||||
|
auto update = conn.streamManager->remoteBidirectionalStreamLimitUpdate();
|
||||||
|
if (update) {
|
||||||
|
sendSimpleFrame(conn, (MaxStreamsFrame(*update, true)));
|
||||||
|
}
|
||||||
|
update = conn.streamManager->remoteUnidirectionalStreamLimitUpdate();
|
||||||
|
if (update) {
|
||||||
|
sendSimpleFrame(conn, (MaxStreamsFrame(*update, false)));
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace quic
|
} // namespace quic
|
||||||
|
@@ -234,4 +234,6 @@ uint64_t writeProbingDataToSocket(
|
|||||||
HeaderBuilder LongHeaderBuilder(LongHeader::Types packetType);
|
HeaderBuilder LongHeaderBuilder(LongHeader::Types packetType);
|
||||||
HeaderBuilder ShortHeaderBuilder();
|
HeaderBuilder ShortHeaderBuilder();
|
||||||
|
|
||||||
|
void maybeSendStreamLimitUpdates(QuicConnectionStateBase& conn);
|
||||||
|
|
||||||
} // namespace quic
|
} // namespace quic
|
||||||
|
@@ -392,7 +392,7 @@ TEST_F(QuicPacketSchedulerTest, WriteOnlyOutstandingPacketsTest) {
|
|||||||
bool present = false;
|
bool present = false;
|
||||||
/* the next four frames should not be written */
|
/* the next four frames should not be written */
|
||||||
present |= boost::get<ConnectionCloseFrame>(&frame) ? true : false;
|
present |= boost::get<ConnectionCloseFrame>(&frame) ? true : false;
|
||||||
present |= boost::get<MaxStreamsFrame>(&frame) ? true : false;
|
present |= boost::get<QuicSimpleFrame>(&frame) ? true : false;
|
||||||
present |= boost::get<PingFrame>(&frame) ? true : false;
|
present |= boost::get<PingFrame>(&frame) ? true : false;
|
||||||
present |= boost::get<WriteAckFrame>(&frame) ? true : false;
|
present |= boost::get<WriteAckFrame>(&frame) ? true : false;
|
||||||
ASSERT_FALSE(present);
|
ASSERT_FALSE(present);
|
||||||
|
@@ -430,17 +430,6 @@ void QuicClientTransport::processPacketData(
|
|||||||
*stream, streamWindowUpdate.maximumData, packetNum);
|
*stream, streamWindowUpdate.maximumData, packetNum);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](MaxStreamsFrame& maxStreamsFrame) {
|
|
||||||
VLOG(10) << "Client received max streams frame stream="
|
|
||||||
<< maxStreamsFrame.maxStreams << *this;
|
|
||||||
if (maxStreamsFrame.isForBidirectionalStream()) {
|
|
||||||
conn_->streamManager->setMaxLocalBidirectionalStreams(
|
|
||||||
maxStreamsFrame.maxStreams);
|
|
||||||
} else {
|
|
||||||
conn_->streamManager->setMaxLocalUnidirectionalStreams(
|
|
||||||
maxStreamsFrame.maxStreams);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[&](DataBlockedFrame&) {
|
[&](DataBlockedFrame&) {
|
||||||
VLOG(10) << "Client received blocked " << *this;
|
VLOG(10) << "Client received blocked " << *this;
|
||||||
pktHasRetransmittableData = true;
|
pktHasRetransmittableData = true;
|
||||||
@@ -874,6 +863,7 @@ void QuicClientTransport::startCryptoHandshake() {
|
|||||||
conn_->transportSettings.ackDelayExponent,
|
conn_->transportSettings.ackDelayExponent,
|
||||||
conn_->transportSettings.maxRecvPacketSize,
|
conn_->transportSettings.maxRecvPacketSize,
|
||||||
customTransportParameters_);
|
customTransportParameters_);
|
||||||
|
conn_->transportParametersEncoded = true;
|
||||||
auto handshakeLayer = clientConn_->clientHandshakeLayer;
|
auto handshakeLayer = clientConn_->clientHandshakeLayer;
|
||||||
handshakeLayer->connect(
|
handshakeLayer->connect(
|
||||||
ctx_,
|
ctx_,
|
||||||
|
@@ -74,7 +74,8 @@ struct QuicClientConnectionState : public QuicConnectionStateBase {
|
|||||||
// We shouldn't normally need to set this until we're starting the
|
// We shouldn't normally need to set this until we're starting the
|
||||||
// transport, however writing unit tests is much easier if we set this here.
|
// transport, however writing unit tests is much easier if we set this here.
|
||||||
updateFlowControlStateWithSettings(flowControlState, transportSettings);
|
updateFlowControlStateWithSettings(flowControlState, transportSettings);
|
||||||
streamManager = std::make_unique<QuicStreamManager>(*this, this->nodeType);
|
streamManager = std::make_unique<QuicStreamManager>(
|
||||||
|
*this, this->nodeType, transportSettings);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -502,6 +502,31 @@ TEST_P(QuicClientTransportIntegrationTest, NetworkTestConnected) {
|
|||||||
sendRequestAndResponseAndWait(*expected, data->clone(), streamId, &readCb);
|
sendRequestAndResponseAndWait(*expected, data->clone(), streamId, &readCb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(QuicClientTransportIntegrationTest, SetTransportSettingsAfterStart) {
|
||||||
|
expectTransportCallbacks();
|
||||||
|
auto qLogger = std::make_shared<FileQLogger>();
|
||||||
|
client->getNonConstConn().qLogger = qLogger;
|
||||||
|
TransportSettings settings;
|
||||||
|
settings.connectUDP = true;
|
||||||
|
client->setTransportSettings(settings);
|
||||||
|
client->start(&clientConnCallback);
|
||||||
|
|
||||||
|
EXPECT_CALL(clientConnCallback, onTransportReady()).WillOnce(Invoke([&] {
|
||||||
|
CHECK(client->getConn().oneRttWriteCipher);
|
||||||
|
eventbase_.terminateLoopSoon();
|
||||||
|
}));
|
||||||
|
eventbase_.loopForever();
|
||||||
|
|
||||||
|
auto streamId = client->createBidirectionalStream().value();
|
||||||
|
auto data = IOBuf::copyBuffer("hello");
|
||||||
|
auto expected = std::shared_ptr<IOBuf>(IOBuf::copyBuffer("echo "));
|
||||||
|
expected->prependChain(data->clone());
|
||||||
|
sendRequestAndResponseAndWait(*expected, data->clone(), streamId, &readCb);
|
||||||
|
settings.connectUDP = false;
|
||||||
|
client->setTransportSettings(settings);
|
||||||
|
EXPECT_TRUE(client->getTransportSettings().connectUDP);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(QuicClientTransportIntegrationTest, TestZeroRttSuccess) {
|
TEST_P(QuicClientTransportIntegrationTest, TestZeroRttSuccess) {
|
||||||
auto cachedPsk = setupZeroRttOnClientCtx(*clientCtx, hostname, getVersion());
|
auto cachedPsk = setupZeroRttOnClientCtx(*clientCtx, hostname, getVersion());
|
||||||
pskCache_->putPsk(hostname, cachedPsk);
|
pskCache_->putPsk(hostname, cachedPsk);
|
||||||
|
@@ -434,6 +434,23 @@ size_t writeSimpleFrame(
|
|||||||
}
|
}
|
||||||
// no space left in packet
|
// no space left in packet
|
||||||
return size_t(0);
|
return size_t(0);
|
||||||
|
},
|
||||||
|
[&](MaxStreamsFrame& maxStreamsFrame) {
|
||||||
|
auto frameType = maxStreamsFrame.isForBidirectionalStream()
|
||||||
|
? FrameType::MAX_STREAMS_BIDI
|
||||||
|
: FrameType::MAX_STREAMS_UNI;
|
||||||
|
QuicInteger intFrameType(static_cast<FrameTypeType>(frameType));
|
||||||
|
QuicInteger streamCount(maxStreamsFrame.maxStreams);
|
||||||
|
auto maxStreamsFrameSize =
|
||||||
|
intFrameType.getSize() + streamCount.getSize();
|
||||||
|
if (packetSpaceCheck(spaceLeft, maxStreamsFrameSize)) {
|
||||||
|
builder.write(intFrameType);
|
||||||
|
builder.write(streamCount);
|
||||||
|
builder.appendFrame(maxStreamsFrame);
|
||||||
|
return maxStreamsFrameSize;
|
||||||
|
}
|
||||||
|
// no space left in packet
|
||||||
|
return size_t(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,23 +537,6 @@ size_t writeFrame(QuicWriteFrame&& frame, PacketBuilderInterface& builder) {
|
|||||||
// no space left in packet
|
// no space left in packet
|
||||||
return size_t(0);
|
return size_t(0);
|
||||||
},
|
},
|
||||||
[&](MaxStreamsFrame& maxStreamsFrame) {
|
|
||||||
auto frameType = maxStreamsFrame.isForBidirectionalStream()
|
|
||||||
? FrameType::MAX_STREAMS_BIDI
|
|
||||||
: FrameType::MAX_STREAMS_UNI;
|
|
||||||
QuicInteger intFrameType(static_cast<FrameTypeType>(frameType));
|
|
||||||
QuicInteger streamCount(maxStreamsFrame.maxStreams);
|
|
||||||
auto maxStreamsFrameSize =
|
|
||||||
intFrameType.getSize() + streamCount.getSize();
|
|
||||||
if (packetSpaceCheck(spaceLeft, maxStreamsFrameSize)) {
|
|
||||||
builder.write(intFrameType);
|
|
||||||
builder.write(streamCount);
|
|
||||||
builder.appendFrame(std::move(maxStreamsFrame));
|
|
||||||
return maxStreamsFrameSize;
|
|
||||||
}
|
|
||||||
// no space left in packet
|
|
||||||
return size_t(0);
|
|
||||||
},
|
|
||||||
[&](DataBlockedFrame& blockedFrame) {
|
[&](DataBlockedFrame& blockedFrame) {
|
||||||
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::DATA_BLOCKED));
|
QuicInteger intFrameType(static_cast<uint8_t>(FrameType::DATA_BLOCKED));
|
||||||
QuicInteger dataLimit(blockedFrame.dataLimit);
|
QuicInteger dataLimit(blockedFrame.dataLimit);
|
||||||
|
@@ -564,7 +564,8 @@ using QuicSimpleFrame = boost::variant<
|
|||||||
ExpiredStreamDataFrame,
|
ExpiredStreamDataFrame,
|
||||||
PathChallengeFrame,
|
PathChallengeFrame,
|
||||||
PathResponseFrame,
|
PathResponseFrame,
|
||||||
NewConnectionIdFrame>;
|
NewConnectionIdFrame,
|
||||||
|
MaxStreamsFrame>;
|
||||||
|
|
||||||
// Types of frames that can be read.
|
// Types of frames that can be read.
|
||||||
using QuicFrame = boost::variant<
|
using QuicFrame = boost::variant<
|
||||||
@@ -574,7 +575,6 @@ using QuicFrame = boost::variant<
|
|||||||
ApplicationCloseFrame,
|
ApplicationCloseFrame,
|
||||||
MaxDataFrame,
|
MaxDataFrame,
|
||||||
MaxStreamDataFrame,
|
MaxStreamDataFrame,
|
||||||
MaxStreamsFrame,
|
|
||||||
PingFrame,
|
PingFrame,
|
||||||
DataBlockedFrame,
|
DataBlockedFrame,
|
||||||
StreamDataBlockedFrame,
|
StreamDataBlockedFrame,
|
||||||
@@ -594,11 +594,10 @@ using QuicWriteFrame = boost::variant<
|
|||||||
ApplicationCloseFrame,
|
ApplicationCloseFrame,
|
||||||
MaxDataFrame,
|
MaxDataFrame,
|
||||||
MaxStreamDataFrame,
|
MaxStreamDataFrame,
|
||||||
MaxStreamsFrame,
|
|
||||||
StreamsBlockedFrame,
|
|
||||||
PingFrame,
|
PingFrame,
|
||||||
DataBlockedFrame,
|
DataBlockedFrame,
|
||||||
StreamDataBlockedFrame,
|
StreamDataBlockedFrame,
|
||||||
|
StreamsBlockedFrame,
|
||||||
WriteAckFrame,
|
WriteAckFrame,
|
||||||
WriteStreamFrame,
|
WriteStreamFrame,
|
||||||
WriteCryptoFrame,
|
WriteCryptoFrame,
|
||||||
|
@@ -130,7 +130,8 @@ TEST_F(QuicPacketRebuilderTest, RebuildPacket) {
|
|||||||
EXPECT_EQ("The sun is in the sky.", closeFrame.reasonPhrase);
|
EXPECT_EQ("The sun is in the sky.", closeFrame.reasonPhrase);
|
||||||
EXPECT_EQ(FrameType::ACK, closeFrame.closingFrameType);
|
EXPECT_EQ(FrameType::ACK, closeFrame.closingFrameType);
|
||||||
},
|
},
|
||||||
[](const MaxStreamsFrame& maxStreamFrame) {
|
[](const QuicSimpleFrame& simpleFrame) {
|
||||||
|
auto maxStreamFrame = boost::get<MaxStreamsFrame>(simpleFrame);
|
||||||
EXPECT_EQ(4321, maxStreamFrame.maxStreams);
|
EXPECT_EQ(4321, maxStreamFrame.maxStreams);
|
||||||
},
|
},
|
||||||
[](const PingFrame& ping) { EXPECT_EQ(PingFrame(), ping); },
|
[](const PingFrame& ping) { EXPECT_EQ(PingFrame(), ping); },
|
||||||
|
@@ -968,13 +968,14 @@ TEST_F(QuicWriteCodecTest, WriteMaxStreamId) {
|
|||||||
auto streamCountSize = i < 64 ? 1 : 2;
|
auto streamCountSize = i < 64 ? 1 : 2;
|
||||||
// 1 byte for the type and up to 2 bytes for the stream count.
|
// 1 byte for the type and up to 2 bytes for the stream count.
|
||||||
EXPECT_EQ(1 + streamCountSize, bytesWritten);
|
EXPECT_EQ(1 + streamCountSize, bytesWritten);
|
||||||
auto resultMaxStreamIdFrame =
|
auto resultMaxStreamIdFrame = boost::get<MaxStreamsFrame>(
|
||||||
boost::get<MaxStreamsFrame>(regularPacket.frames[0]);
|
boost::get<QuicSimpleFrame>(regularPacket.frames[0]));
|
||||||
EXPECT_EQ(i, resultMaxStreamIdFrame.maxStreams);
|
EXPECT_EQ(i, resultMaxStreamIdFrame.maxStreams);
|
||||||
|
|
||||||
auto wireBuf = std::move(builtOut.second);
|
auto wireBuf = std::move(builtOut.second);
|
||||||
folly::io::Cursor cursor(wireBuf.get());
|
folly::io::Cursor cursor(wireBuf.get());
|
||||||
auto wireStreamsFrame = boost::get<MaxStreamsFrame>(parseQuicFrame(cursor));
|
auto wireStreamsFrame = boost::get<MaxStreamsFrame>(
|
||||||
|
boost::get<QuicSimpleFrame>(parseQuicFrame(cursor)));
|
||||||
EXPECT_EQ(i, wireStreamsFrame.maxStreams);
|
EXPECT_EQ(i, wireStreamsFrame.maxStreams);
|
||||||
EXPECT_TRUE(cursor.isAtEnd());
|
EXPECT_TRUE(cursor.isAtEnd());
|
||||||
}
|
}
|
||||||
@@ -994,13 +995,14 @@ TEST_F(QuicWriteCodecTest, WriteUniMaxStreamId) {
|
|||||||
auto streamCountSize = i < 64 ? 1 : 2;
|
auto streamCountSize = i < 64 ? 1 : 2;
|
||||||
// 1 byte for the type and up to 2 bytes for the stream count.
|
// 1 byte for the type and up to 2 bytes for the stream count.
|
||||||
EXPECT_EQ(1 + streamCountSize, bytesWritten);
|
EXPECT_EQ(1 + streamCountSize, bytesWritten);
|
||||||
auto resultMaxStreamIdFrame =
|
auto resultMaxStreamIdFrame = boost::get<MaxStreamsFrame>(
|
||||||
boost::get<MaxStreamsFrame>(regularPacket.frames[0]);
|
boost::get<QuicSimpleFrame>(regularPacket.frames[0]));
|
||||||
EXPECT_EQ(i, resultMaxStreamIdFrame.maxStreams);
|
EXPECT_EQ(i, resultMaxStreamIdFrame.maxStreams);
|
||||||
|
|
||||||
auto wireBuf = std::move(builtOut.second);
|
auto wireBuf = std::move(builtOut.second);
|
||||||
folly::io::Cursor cursor(wireBuf.get());
|
folly::io::Cursor cursor(wireBuf.get());
|
||||||
auto wireStreamsFrame = boost::get<MaxStreamsFrame>(parseQuicFrame(cursor));
|
auto wireStreamsFrame = boost::get<MaxStreamsFrame>(
|
||||||
|
boost::get<QuicSimpleFrame>(parseQuicFrame(cursor)));
|
||||||
EXPECT_EQ(i, wireStreamsFrame.maxStreams);
|
EXPECT_EQ(i, wireStreamsFrame.maxStreams);
|
||||||
EXPECT_TRUE(cursor.isAtEnd());
|
EXPECT_TRUE(cursor.isAtEnd());
|
||||||
}
|
}
|
||||||
@@ -1268,12 +1270,13 @@ TEST_F(QuicWriteCodecTest, WriteStreamIdNeeded) {
|
|||||||
auto builtOut = std::move(pktBuilder).buildPacket();
|
auto builtOut = std::move(pktBuilder).buildPacket();
|
||||||
auto regularPacket = builtOut.first;
|
auto regularPacket = builtOut.first;
|
||||||
EXPECT_EQ(bytesWritten, 3);
|
EXPECT_EQ(bytesWritten, 3);
|
||||||
EXPECT_NO_THROW(boost::get<MaxStreamsFrame>(regularPacket.frames[0]));
|
EXPECT_NO_THROW(boost::get<MaxStreamsFrame>(
|
||||||
|
boost::get<QuicSimpleFrame>(regularPacket.frames[0])));
|
||||||
|
|
||||||
auto wireBuf = std::move(builtOut.second);
|
auto wireBuf = std::move(builtOut.second);
|
||||||
folly::io::Cursor cursor(wireBuf.get());
|
folly::io::Cursor cursor(wireBuf.get());
|
||||||
auto writeStreamIdBlocked =
|
auto writeStreamIdBlocked = boost::get<MaxStreamsFrame>(
|
||||||
boost::get<MaxStreamsFrame>(parseQuicFrame(cursor));
|
boost::get<QuicSimpleFrame>(parseQuicFrame(cursor)));
|
||||||
EXPECT_EQ(writeStreamIdBlocked.maxStreams, blockedStreamId);
|
EXPECT_EQ(writeStreamIdBlocked.maxStreams, blockedStreamId);
|
||||||
EXPECT_TRUE(cursor.isAtEnd());
|
EXPECT_TRUE(cursor.isAtEnd());
|
||||||
}
|
}
|
||||||
|
@@ -24,8 +24,8 @@ class QuicFlowControlTest : public Test {
|
|||||||
public:
|
public:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
transportInfoCb_ = std::make_unique<MockQuicStats>();
|
transportInfoCb_ = std::make_unique<MockQuicStats>();
|
||||||
conn_.streamManager =
|
conn_.streamManager = std::make_unique<QuicStreamManager>(
|
||||||
std::make_unique<QuicStreamManager>(conn_, conn_.nodeType);
|
conn_, conn_.nodeType, conn_.transportSettings);
|
||||||
conn_.infoCallback = transportInfoCb_.get();
|
conn_.infoCallback = transportInfoCb_.get();
|
||||||
}
|
}
|
||||||
std::unique_ptr<MockQuicStats> transportInfoCb_;
|
std::unique_ptr<MockQuicStats> transportInfoCb_;
|
||||||
|
@@ -494,6 +494,7 @@ void onServerReadDataFromOpen(
|
|||||||
conn.transportSettings.maxRecvPacketSize,
|
conn.transportSettings.maxRecvPacketSize,
|
||||||
conn.transportSettings.partialReliabilityEnabled,
|
conn.transportSettings.partialReliabilityEnabled,
|
||||||
token));
|
token));
|
||||||
|
conn.transportParametersEncoded = true;
|
||||||
QuicFizzFactory fizzFactory;
|
QuicFizzFactory fizzFactory;
|
||||||
FizzCryptoFactory cryptoFactory(&fizzFactory);
|
FizzCryptoFactory cryptoFactory(&fizzFactory);
|
||||||
conn.readCodec = std::make_unique<QuicReadCodec>(QuicNodeType::Server);
|
conn.readCodec = std::make_unique<QuicReadCodec>(QuicNodeType::Server);
|
||||||
@@ -870,18 +871,6 @@ void onServerReadDataFromOpen(
|
|||||||
*stream, streamWindowUpdate.maximumData, packetNum);
|
*stream, streamWindowUpdate.maximumData, packetNum);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](MaxStreamsFrame& maxStreamsFrame) {
|
|
||||||
VLOG(10) << "Server received max streams frame stream="
|
|
||||||
<< maxStreamsFrame.maxStreams << " " << conn;
|
|
||||||
isNonProbingPacket = true;
|
|
||||||
if (maxStreamsFrame.isForBidirectionalStream()) {
|
|
||||||
conn.streamManager->setMaxLocalBidirectionalStreams(
|
|
||||||
maxStreamsFrame.maxStreams);
|
|
||||||
} else {
|
|
||||||
conn.streamManager->setMaxLocalUnidirectionalStreams(
|
|
||||||
maxStreamsFrame.maxStreams);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[&](DataBlockedFrame&) {
|
[&](DataBlockedFrame&) {
|
||||||
VLOG(10) << "Server received blocked " << conn;
|
VLOG(10) << "Server received blocked " << conn;
|
||||||
pktHasRetransmittableData = true;
|
pktHasRetransmittableData = true;
|
||||||
|
@@ -132,7 +132,8 @@ struct QuicServerConnectionState : public QuicConnectionStateBase {
|
|||||||
pendingZeroRttData =
|
pendingZeroRttData =
|
||||||
std::make_unique<std::vector<ServerEvents::ReadData>>();
|
std::make_unique<std::vector<ServerEvents::ReadData>>();
|
||||||
pendingOneRttData = std::make_unique<std::vector<ServerEvents::ReadData>>();
|
pendingOneRttData = std::make_unique<std::vector<ServerEvents::ReadData>>();
|
||||||
streamManager = std::make_unique<QuicStreamManager>(*this, this->nodeType);
|
streamManager = std::make_unique<QuicStreamManager>(
|
||||||
|
*this, this->nodeType, transportSettings);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -109,8 +109,8 @@ void QuicStreamManager::setMaxLocalBidirectionalStreams(
|
|||||||
"Attempt to set maxStreams beyond the max allowed.",
|
"Attempt to set maxStreams beyond the max allowed.",
|
||||||
TransportErrorCode::STREAM_LIMIT_ERROR);
|
TransportErrorCode::STREAM_LIMIT_ERROR);
|
||||||
}
|
}
|
||||||
StreamId maxStreamId =
|
StreamId maxStreamId = maxStreams * detail::kStreamIncrement +
|
||||||
maxStreams * detail::kStreamIncrement + initialBidirectionalStreamId_;
|
initialLocalBidirectionalStreamId_;
|
||||||
if (force || maxStreamId > maxLocalBidirectionalStreamId_) {
|
if (force || maxStreamId > maxLocalBidirectionalStreamId_) {
|
||||||
maxLocalBidirectionalStreamId_ = maxStreamId;
|
maxLocalBidirectionalStreamId_ = maxStreamId;
|
||||||
}
|
}
|
||||||
@@ -124,21 +124,68 @@ void QuicStreamManager::setMaxLocalUnidirectionalStreams(
|
|||||||
"Attempt to set maxStreams beyond the max allowed.",
|
"Attempt to set maxStreams beyond the max allowed.",
|
||||||
TransportErrorCode::STREAM_LIMIT_ERROR);
|
TransportErrorCode::STREAM_LIMIT_ERROR);
|
||||||
}
|
}
|
||||||
StreamId maxStreamId =
|
StreamId maxStreamId = maxStreams * detail::kStreamIncrement +
|
||||||
maxStreams * detail::kStreamIncrement + initialUnidirectionalStreamId_;
|
initialLocalUnidirectionalStreamId_;
|
||||||
if (force || maxStreamId > maxLocalUnidirectionalStreamId_) {
|
if (force || maxStreamId > maxLocalUnidirectionalStreamId_) {
|
||||||
maxLocalUnidirectionalStreamId_ = maxStreamId;
|
maxLocalUnidirectionalStreamId_ = maxStreamId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QuicStreamManager::setMaxRemoteBidirectionalStreams(uint64_t maxStreams) {
|
||||||
|
setMaxRemoteBidirectionalStreamsInternal(maxStreams, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuicStreamManager::setMaxRemoteUnidirectionalStreams(uint64_t maxStreams) {
|
||||||
|
setMaxRemoteUnidirectionalStreamsInternal(maxStreams, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuicStreamManager::setMaxRemoteBidirectionalStreamsInternal(
|
||||||
|
uint64_t maxStreams,
|
||||||
|
bool force) {
|
||||||
|
if (maxStreams > kMaxMaxStreams) {
|
||||||
|
throw QuicTransportException(
|
||||||
|
"Attempt to set maxStreams beyond the max allowed.",
|
||||||
|
TransportErrorCode::STREAM_LIMIT_ERROR);
|
||||||
|
}
|
||||||
|
StreamId maxStreamId = maxStreams * detail::kStreamIncrement +
|
||||||
|
initialRemoteBidirectionalStreamId_;
|
||||||
|
if (force || maxStreamId > maxRemoteBidirectionalStreamId_) {
|
||||||
|
maxRemoteBidirectionalStreamId_ = maxStreamId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuicStreamManager::setMaxRemoteUnidirectionalStreamsInternal(
|
||||||
|
uint64_t maxStreams,
|
||||||
|
bool force) {
|
||||||
|
if (maxStreams > kMaxMaxStreams) {
|
||||||
|
throw QuicTransportException(
|
||||||
|
"Attempt to set maxStreams beyond the max allowed.",
|
||||||
|
TransportErrorCode::STREAM_LIMIT_ERROR);
|
||||||
|
}
|
||||||
|
StreamId maxStreamId = maxStreams * detail::kStreamIncrement +
|
||||||
|
initialRemoteUnidirectionalStreamId_;
|
||||||
|
if (force || maxStreamId > maxRemoteUnidirectionalStreamId_) {
|
||||||
|
maxRemoteUnidirectionalStreamId_ = maxStreamId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuicStreamManager::refreshTransportSettings(
|
||||||
|
const TransportSettings& settings) {
|
||||||
|
transportSettings_ = &settings;
|
||||||
|
setMaxRemoteBidirectionalStreamsInternal(
|
||||||
|
transportSettings_->advertisedInitialMaxStreamsBidi, true);
|
||||||
|
setMaxRemoteUnidirectionalStreamsInternal(
|
||||||
|
transportSettings_->advertisedInitialMaxStreamsUni, true);
|
||||||
|
}
|
||||||
|
|
||||||
// We create local streams lazily. If a local stream was created
|
// We create local streams lazily. If a local stream was created
|
||||||
// but not allocated yet, this will allocate a stream.
|
// but not allocated yet, this will allocate a stream.
|
||||||
// This will return nullptr if a stream is closed or un-opened.
|
// This will return nullptr if a stream is closed or un-opened.
|
||||||
QuicStreamState* FOLLY_NULLABLE
|
QuicStreamState* FOLLY_NULLABLE
|
||||||
QuicStreamManager::getOrCreateOpenedLocalStream(StreamId streamId) {
|
QuicStreamManager::getOrCreateOpenedLocalStream(StreamId streamId) {
|
||||||
auto streamIdx =
|
auto streamIdx = std::lower_bound(
|
||||||
std::find(openLocalStreams_.begin(), openLocalStreams_.end(), streamId);
|
openLocalStreams_.begin(), openLocalStreams_.end(), streamId);
|
||||||
if (streamIdx != openLocalStreams_.end()) {
|
if (streamIdx != openLocalStreams_.end() && *streamIdx == streamId) {
|
||||||
// Open a lazily created stream.
|
// Open a lazily created stream.
|
||||||
auto it = streams_.emplace(
|
auto it = streams_.emplace(
|
||||||
std::piecewise_construct,
|
std::piecewise_construct,
|
||||||
@@ -217,9 +264,12 @@ QuicStreamManager::getOrCreatePeerStream(StreamId streamId) {
|
|||||||
if (peerStream != streams_.end()) {
|
if (peerStream != streams_.end()) {
|
||||||
return &peerStream->second;
|
return &peerStream->second;
|
||||||
}
|
}
|
||||||
auto streamIdx =
|
auto& openPeerStreams = isUnidirectionalStream(streamId)
|
||||||
std::find(openPeerStreams_.begin(), openPeerStreams_.end(), streamId);
|
? openUnidirectionalPeerStreams_
|
||||||
if (streamIdx != openPeerStreams_.end()) {
|
: openBidirectionalPeerStreams_;
|
||||||
|
auto streamIdx = std::lower_bound(
|
||||||
|
openPeerStreams.begin(), openPeerStreams.end(), streamId);
|
||||||
|
if (streamIdx != openPeerStreams.end() && *streamIdx == streamId) {
|
||||||
// Stream was already open, create the state for it lazily.
|
// Stream was already open, create the state for it lazily.
|
||||||
auto it = streams_.emplace(
|
auto it = streams_.emplace(
|
||||||
std::piecewise_construct,
|
std::piecewise_construct,
|
||||||
@@ -229,7 +279,7 @@ QuicStreamManager::getOrCreatePeerStream(StreamId streamId) {
|
|||||||
return &it.first->second;
|
return &it.first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto previousPeerStreams = openPeerStreams_;
|
auto previousPeerStreams = folly::copy(openPeerStreams);
|
||||||
auto& nextAcceptableStreamId = isUnidirectionalStream(streamId)
|
auto& nextAcceptableStreamId = isUnidirectionalStream(streamId)
|
||||||
? nextAcceptablePeerUnidirectionalStreamId_
|
? nextAcceptablePeerUnidirectionalStreamId_
|
||||||
: nextAcceptablePeerBidirectionalStreamId_;
|
: nextAcceptablePeerBidirectionalStreamId_;
|
||||||
@@ -237,7 +287,7 @@ QuicStreamManager::getOrCreatePeerStream(StreamId streamId) {
|
|||||||
? maxRemoteUnidirectionalStreamId_
|
? maxRemoteUnidirectionalStreamId_
|
||||||
: maxRemoteBidirectionalStreamId_;
|
: maxRemoteBidirectionalStreamId_;
|
||||||
auto openedResult = openStreamIfNotClosed(
|
auto openedResult = openStreamIfNotClosed(
|
||||||
streamId, openPeerStreams_, nextAcceptableStreamId, maxStreamId);
|
streamId, openPeerStreams, nextAcceptableStreamId, maxStreamId);
|
||||||
if (openedResult == LocalErrorCode::CREATING_EXISTING_STREAM) {
|
if (openedResult == LocalErrorCode::CREATING_EXISTING_STREAM) {
|
||||||
// Stream could be closed here.
|
// Stream could be closed here.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -248,8 +298,8 @@ QuicStreamManager::getOrCreatePeerStream(StreamId streamId) {
|
|||||||
|
|
||||||
// Copy over the new streams.
|
// Copy over the new streams.
|
||||||
std::set_difference(
|
std::set_difference(
|
||||||
openPeerStreams_.begin(),
|
openPeerStreams.begin(),
|
||||||
openPeerStreams_.end(),
|
openPeerStreams.end(),
|
||||||
std::make_move_iterator(previousPeerStreams.begin()),
|
std::make_move_iterator(previousPeerStreams.begin()),
|
||||||
std::make_move_iterator(previousPeerStreams.end()),
|
std::make_move_iterator(previousPeerStreams.end()),
|
||||||
std::back_inserter(newPeerStreams_));
|
std::back_inserter(newPeerStreams_));
|
||||||
@@ -331,14 +381,49 @@ void QuicStreamManager::removeClosedStream(StreamId streamId) {
|
|||||||
}
|
}
|
||||||
streams_.erase(it);
|
streams_.erase(it);
|
||||||
QUIC_STATS(conn_.infoCallback, onQuicStreamClosed);
|
QUIC_STATS(conn_.infoCallback, onQuicStreamClosed);
|
||||||
auto streamItr =
|
if (isRemoteStream(nodeType_, streamId)) {
|
||||||
std::find(openPeerStreams_.begin(), openPeerStreams_.end(), streamId);
|
auto& openPeerStreams = isUnidirectionalStream(streamId)
|
||||||
if (streamItr != openPeerStreams_.end()) {
|
? openUnidirectionalPeerStreams_
|
||||||
openPeerStreams_.erase(streamItr);
|
: openBidirectionalPeerStreams_;
|
||||||
|
auto streamItr = std::lower_bound(
|
||||||
|
openPeerStreams.begin(), openPeerStreams.end(), streamId);
|
||||||
|
if (streamItr != openPeerStreams.end() && *streamItr == streamId) {
|
||||||
|
openPeerStreams.erase(streamItr);
|
||||||
|
// Check if we should send a stream limit update. We need to send an
|
||||||
|
// update every time we've closed a number of streams >= the set windowing
|
||||||
|
// fraction.
|
||||||
|
uint64_t initialStreamLimit = isUnidirectionalStream(streamId)
|
||||||
|
? transportSettings_->advertisedInitialMaxStreamsUni
|
||||||
|
: transportSettings_->advertisedInitialMaxStreamsBidi;
|
||||||
|
uint64_t streamWindow =
|
||||||
|
initialStreamLimit / streamLimitWindowingFraction_;
|
||||||
|
uint64_t openableRemoteStreams = isUnidirectionalStream(streamId)
|
||||||
|
? openableRemoteUnidirectionalStreams()
|
||||||
|
: openableRemoteBidirectionalStreams();
|
||||||
|
// The "credit" here is how much available stream space we have based on
|
||||||
|
// what the initial stream limit was set to.
|
||||||
|
uint64_t streamCredit =
|
||||||
|
initialStreamLimit - openableRemoteStreams - openPeerStreams.size();
|
||||||
|
if (streamCredit >= streamWindow) {
|
||||||
|
if (isUnidirectionalStream(streamId)) {
|
||||||
|
uint64_t maxStreams = (maxRemoteUnidirectionalStreamId_ -
|
||||||
|
initialRemoteUnidirectionalStreamId_) /
|
||||||
|
detail::kStreamIncrement;
|
||||||
|
setMaxRemoteUnidirectionalStreams(maxStreams + streamCredit);
|
||||||
|
remoteUnidirectionalStreamLimitUpdate_ = maxStreams + streamCredit;
|
||||||
|
} else {
|
||||||
|
uint64_t maxStreams = (maxRemoteBidirectionalStreamId_ -
|
||||||
|
initialRemoteBidirectionalStreamId_) /
|
||||||
|
detail::kStreamIncrement;
|
||||||
|
setMaxRemoteBidirectionalStreams(maxStreams + streamCredit);
|
||||||
|
remoteBidirectionalStreamLimitUpdate_ = maxStreams + streamCredit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
streamItr =
|
auto streamItr = std::lower_bound(
|
||||||
std::find(openLocalStreams_.begin(), openLocalStreams_.end(), streamId);
|
openLocalStreams_.begin(), openLocalStreams_.end(), streamId);
|
||||||
if (streamItr != openLocalStreams_.end()) {
|
if (streamItr != openLocalStreams_.end() && *streamItr == streamId) {
|
||||||
openLocalStreams_.erase(streamItr);
|
openLocalStreams_.erase(streamItr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include <quic/QuicConstants.h>
|
#include <quic/QuicConstants.h>
|
||||||
#include <quic/codec/Types.h>
|
#include <quic/codec/Types.h>
|
||||||
#include <quic/state/StreamData.h>
|
#include <quic/state/StreamData.h>
|
||||||
|
#include <quic/state/TransportSettings.h>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
@@ -28,8 +29,11 @@ class QuicStreamManager {
|
|||||||
public:
|
public:
|
||||||
explicit QuicStreamManager(
|
explicit QuicStreamManager(
|
||||||
QuicConnectionStateBase& conn,
|
QuicConnectionStateBase& conn,
|
||||||
QuicNodeType nodeType)
|
QuicNodeType nodeType,
|
||||||
: conn_(conn), nodeType_(nodeType) {
|
const TransportSettings& transportSettings)
|
||||||
|
: conn_(conn),
|
||||||
|
nodeType_(nodeType),
|
||||||
|
transportSettings_(&transportSettings) {
|
||||||
if (nodeType == QuicNodeType::Server) {
|
if (nodeType == QuicNodeType::Server) {
|
||||||
nextAcceptablePeerBidirectionalStreamId_ = 0x00;
|
nextAcceptablePeerBidirectionalStreamId_ = 0x00;
|
||||||
nextAcceptablePeerUnidirectionalStreamId_ = 0x02;
|
nextAcceptablePeerUnidirectionalStreamId_ = 0x02;
|
||||||
@@ -37,8 +41,10 @@ class QuicStreamManager {
|
|||||||
nextAcceptableLocalUnidirectionalStreamId_ = 0x03;
|
nextAcceptableLocalUnidirectionalStreamId_ = 0x03;
|
||||||
nextBidirectionalStreamId_ = 0x01;
|
nextBidirectionalStreamId_ = 0x01;
|
||||||
nextUnidirectionalStreamId_ = 0x03;
|
nextUnidirectionalStreamId_ = 0x03;
|
||||||
initialBidirectionalStreamId_ = 0x01;
|
initialLocalBidirectionalStreamId_ = 0x01;
|
||||||
initialUnidirectionalStreamId_ = 0x03;
|
initialLocalUnidirectionalStreamId_ = 0x03;
|
||||||
|
initialRemoteBidirectionalStreamId_ = 0x00;
|
||||||
|
initialRemoteUnidirectionalStreamId_ = 0x02;
|
||||||
} else {
|
} else {
|
||||||
nextAcceptablePeerBidirectionalStreamId_ = 0x01;
|
nextAcceptablePeerBidirectionalStreamId_ = 0x01;
|
||||||
nextAcceptablePeerUnidirectionalStreamId_ = 0x03;
|
nextAcceptablePeerUnidirectionalStreamId_ = 0x03;
|
||||||
@@ -46,9 +52,12 @@ class QuicStreamManager {
|
|||||||
nextAcceptableLocalUnidirectionalStreamId_ = 0x02;
|
nextAcceptableLocalUnidirectionalStreamId_ = 0x02;
|
||||||
nextBidirectionalStreamId_ = 0x00;
|
nextBidirectionalStreamId_ = 0x00;
|
||||||
nextUnidirectionalStreamId_ = 0x02;
|
nextUnidirectionalStreamId_ = 0x02;
|
||||||
initialBidirectionalStreamId_ = 0x00;
|
initialLocalBidirectionalStreamId_ = 0x00;
|
||||||
initialUnidirectionalStreamId_ = 0x02;
|
initialLocalUnidirectionalStreamId_ = 0x02;
|
||||||
|
initialRemoteBidirectionalStreamId_ = 0x01;
|
||||||
|
initialRemoteUnidirectionalStreamId_ = 0x03;
|
||||||
}
|
}
|
||||||
|
refreshTransportSettings(transportSettings);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Create the state for a stream if it does not exist and return it. Note this
|
* Create the state for a stream if it does not exist and return it. Note this
|
||||||
@@ -117,7 +126,13 @@ class QuicStreamManager {
|
|||||||
*/
|
*/
|
||||||
bool streamExists(StreamId streamId) {
|
bool streamExists(StreamId streamId) {
|
||||||
return std::binary_search(
|
return std::binary_search(
|
||||||
openPeerStreams_.begin(), openPeerStreams_.end(), streamId) ||
|
openBidirectionalPeerStreams_.begin(),
|
||||||
|
openBidirectionalPeerStreams_.end(),
|
||||||
|
streamId) ||
|
||||||
|
std::binary_search(
|
||||||
|
openUnidirectionalPeerStreams_.begin(),
|
||||||
|
openUnidirectionalPeerStreams_.end(),
|
||||||
|
streamId) ||
|
||||||
std::binary_search(
|
std::binary_search(
|
||||||
openLocalStreams_.begin(), openLocalStreams_.end(), streamId);
|
openLocalStreams_.begin(), openLocalStreams_.end(), streamId);
|
||||||
}
|
}
|
||||||
@@ -158,7 +173,8 @@ class QuicStreamManager {
|
|||||||
*/
|
*/
|
||||||
void clearOpenStreams() {
|
void clearOpenStreams() {
|
||||||
openLocalStreams_.clear();
|
openLocalStreams_.clear();
|
||||||
openPeerStreams_.clear();
|
openBidirectionalPeerStreams_.clear();
|
||||||
|
openUnidirectionalPeerStreams_.clear();
|
||||||
streams_.clear();
|
streams_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,6 +293,54 @@ class QuicStreamManager {
|
|||||||
uint64_t maxStreams,
|
uint64_t maxStreams,
|
||||||
bool force = false);
|
bool force = false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the max number of remote bidirectional streams. Can only be increased
|
||||||
|
* unless force is true.
|
||||||
|
*/
|
||||||
|
void setMaxRemoteBidirectionalStreams(uint64_t maxStreams);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the max number of remote unidirectional streams. Can only be increased
|
||||||
|
* unless force is true.
|
||||||
|
*/
|
||||||
|
void setMaxRemoteUnidirectionalStreams(uint64_t maxStreams);
|
||||||
|
|
||||||
|
void refreshTransportSettings(const TransportSettings& settings);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the "window-by" fraction for sending stream limit updates. E.g.
|
||||||
|
* setting the fraction to two when the initial stream limit was 100 will
|
||||||
|
* cause the stream manager to update the relevant stream limit update when
|
||||||
|
* 50 streams have been closed.
|
||||||
|
*/
|
||||||
|
void setStreamLimitWindowingFraction(uint64_t fraction) {
|
||||||
|
if (fraction > 0) {
|
||||||
|
streamLimitWindowingFraction_ = fraction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The next value that should be sent in a bidirectional max streams frame,
|
||||||
|
* if any. This is potentially updated every time a bidirectional stream is
|
||||||
|
* closed. Calling this function "consumes" the update.
|
||||||
|
*/
|
||||||
|
folly::Optional<uint64_t> remoteBidirectionalStreamLimitUpdate() {
|
||||||
|
auto ret = remoteBidirectionalStreamLimitUpdate_;
|
||||||
|
remoteBidirectionalStreamLimitUpdate_ = folly::none;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The next value that should be sent in a unidirectional max streams frame,
|
||||||
|
* if any. This is potentially updated every time a unidirectional stream is
|
||||||
|
* closed. Calling this function "consumes" the update.
|
||||||
|
*/
|
||||||
|
folly::Optional<uint64_t> remoteUnidirectionalStreamLimitUpdate() {
|
||||||
|
auto ret = remoteUnidirectionalStreamLimitUpdate_;
|
||||||
|
remoteUnidirectionalStreamLimitUpdate_ = folly::none;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a const reference to the underlying stream window updates
|
* Returns a const reference to the underlying stream window updates
|
||||||
* container.
|
* container.
|
||||||
@@ -488,10 +552,20 @@ class QuicStreamManager {
|
|||||||
|
|
||||||
// TODO figure out a better interface here.
|
// TODO figure out a better interface here.
|
||||||
/*
|
/*
|
||||||
* Returns a mutable reference to the underlying open peer streams container.
|
* Returns a mutable reference to the underlying open bidirectional peer
|
||||||
|
* streams container.
|
||||||
*/
|
*/
|
||||||
auto& openPeerStreams() {
|
auto& openBidirectionalPeerStreams() {
|
||||||
return openPeerStreams_;
|
return openBidirectionalPeerStreams_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO figure out a better interface here.
|
||||||
|
/*
|
||||||
|
* Returns a mutable reference to the underlying open peer unidirectional
|
||||||
|
* streams container.
|
||||||
|
*/
|
||||||
|
auto& openUnidirectionalPeerStreams() {
|
||||||
|
return openUnidirectionalPeerStreams_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO figure out a better interface here.
|
// TODO figure out a better interface here.
|
||||||
@@ -579,6 +653,13 @@ class QuicStreamManager {
|
|||||||
|
|
||||||
QuicStreamState* FOLLY_NULLABLE getOrCreatePeerStream(StreamId streamId);
|
QuicStreamState* FOLLY_NULLABLE getOrCreatePeerStream(StreamId streamId);
|
||||||
|
|
||||||
|
void setMaxRemoteBidirectionalStreamsInternal(
|
||||||
|
uint64_t maxStreams,
|
||||||
|
bool force);
|
||||||
|
void setMaxRemoteUnidirectionalStreamsInternal(
|
||||||
|
uint64_t maxStreams,
|
||||||
|
bool force);
|
||||||
|
|
||||||
QuicConnectionStateBase& conn_;
|
QuicConnectionStateBase& conn_;
|
||||||
QuicNodeType nodeType_;
|
QuicNodeType nodeType_;
|
||||||
|
|
||||||
@@ -608,18 +689,39 @@ class QuicStreamManager {
|
|||||||
|
|
||||||
StreamId maxLocalUnidirectionalStreamId_{0};
|
StreamId maxLocalUnidirectionalStreamId_{0};
|
||||||
|
|
||||||
StreamId maxRemoteBidirectionalStreamId_{kMaxStreamId};
|
StreamId maxRemoteBidirectionalStreamId_{0};
|
||||||
|
|
||||||
StreamId maxRemoteUnidirectionalStreamId_{kMaxStreamId};
|
StreamId maxRemoteUnidirectionalStreamId_{0};
|
||||||
|
|
||||||
StreamId initialBidirectionalStreamId_{0};
|
StreamId initialLocalBidirectionalStreamId_{0};
|
||||||
|
|
||||||
StreamId initialUnidirectionalStreamId_{0};
|
StreamId initialLocalUnidirectionalStreamId_{0};
|
||||||
|
|
||||||
|
StreamId initialRemoteBidirectionalStreamId_{0};
|
||||||
|
|
||||||
|
StreamId initialRemoteUnidirectionalStreamId_{0};
|
||||||
|
|
||||||
|
// The fraction to determine the window by which we will signal the need to
|
||||||
|
// send stream limit updates
|
||||||
|
uint64_t streamLimitWindowingFraction_{2};
|
||||||
|
|
||||||
|
// Contains the value of a stream window update that should be sent for
|
||||||
|
// remote bidirectional streams.
|
||||||
|
folly::Optional<uint64_t> remoteBidirectionalStreamLimitUpdate_;
|
||||||
|
|
||||||
|
// Contains the value of a stream window update that should be sent for
|
||||||
|
// remote bidirectional streams.
|
||||||
|
folly::Optional<uint64_t> remoteUnidirectionalStreamLimitUpdate_;
|
||||||
|
|
||||||
uint64_t numControlStreams_{0};
|
uint64_t numControlStreams_{0};
|
||||||
|
|
||||||
// Streams that are opened by the peer on the connection. Ordered by id.
|
// Bidirectional streams that are opened by the peer on the connection.
|
||||||
std::deque<StreamId> openPeerStreams_;
|
// Ordered by id.
|
||||||
|
std::deque<StreamId> openBidirectionalPeerStreams_;
|
||||||
|
|
||||||
|
// Unidirectional streams that are opened by the peer on the connection.
|
||||||
|
// Ordered by id.
|
||||||
|
std::deque<StreamId> openUnidirectionalPeerStreams_;
|
||||||
|
|
||||||
// Streams that are opened locally on the connection. Ordered by id.
|
// Streams that are opened locally on the connection. Ordered by id.
|
||||||
std::deque<StreamId> openLocalStreams_;
|
std::deque<StreamId> openLocalStreams_;
|
||||||
@@ -668,6 +770,8 @@ class QuicStreamManager {
|
|||||||
|
|
||||||
// Record whether or not we are app-idle.
|
// Record whether or not we are app-idle.
|
||||||
bool isAppIdle_{false};
|
bool isAppIdle_{false};
|
||||||
|
|
||||||
|
const TransportSettings* transportSettings_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace quic
|
} // namespace quic
|
||||||
|
@@ -63,6 +63,9 @@ folly::Optional<QuicSimpleFrame> updateSimpleFrameOnPacketClone(
|
|||||||
[&](const NewConnectionIdFrame& frame)
|
[&](const NewConnectionIdFrame& frame)
|
||||||
-> folly::Optional<QuicSimpleFrame> {
|
-> folly::Optional<QuicSimpleFrame> {
|
||||||
return QuicSimpleFrame(frame);
|
return QuicSimpleFrame(frame);
|
||||||
|
},
|
||||||
|
[&](const MaxStreamsFrame& frame) -> folly::Optional<QuicSimpleFrame> {
|
||||||
|
return QuicSimpleFrame(frame);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +127,9 @@ void updateSimpleFrameOnPacketLoss(
|
|||||||
},
|
},
|
||||||
[&](const NewConnectionIdFrame& frame) {
|
[&](const NewConnectionIdFrame& frame) {
|
||||||
conn.pendingEvents.frames.push_back(frame);
|
conn.pendingEvents.frames.push_back(frame);
|
||||||
|
},
|
||||||
|
[&](const MaxStreamsFrame& frame) {
|
||||||
|
conn.pendingEvents.frames.push_back(frame);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +182,16 @@ bool updateSimpleFrameOnPacketReceived(
|
|||||||
[&](const NewConnectionIdFrame&) {
|
[&](const NewConnectionIdFrame&) {
|
||||||
// TODO junqiw
|
// TODO junqiw
|
||||||
return false;
|
return false;
|
||||||
|
},
|
||||||
|
[&](const MaxStreamsFrame& maxStreamsFrame) {
|
||||||
|
if (maxStreamsFrame.isForBidirectionalStream()) {
|
||||||
|
conn.streamManager->setMaxLocalBidirectionalStreams(
|
||||||
|
maxStreamsFrame.maxStreams);
|
||||||
|
} else {
|
||||||
|
conn.streamManager->setMaxLocalUnidirectionalStreams(
|
||||||
|
maxStreamsFrame.maxStreams);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -594,6 +594,9 @@ struct QuicConnectionStateBase {
|
|||||||
// Settings for transports.
|
// Settings for transports.
|
||||||
TransportSettings transportSettings;
|
TransportSettings transportSettings;
|
||||||
|
|
||||||
|
// Whether we've set the transporot parameters from transportSettings yet.
|
||||||
|
bool transportParametersEncoded{false};
|
||||||
|
|
||||||
// Value of the negotiated ack delay exponent.
|
// Value of the negotiated ack delay exponent.
|
||||||
uint64_t peerAckDelayExponent{kDefaultAckDelayExponent};
|
uint64_t peerAckDelayExponent{kDefaultAckDelayExponent};
|
||||||
|
|
||||||
|
@@ -876,19 +876,19 @@ TEST_F(QuicServerStreamFunctionsTest, GetOrCreateClientOutOfOrderStream) {
|
|||||||
EXPECT_TRUE(conn.streamManager->streamExists(outOfOrderStream));
|
EXPECT_TRUE(conn.streamManager->streamExists(outOfOrderStream));
|
||||||
// peer stream starts from 0x00
|
// peer stream starts from 0x00
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
conn.streamManager->openPeerStreams().size(),
|
conn.streamManager->openBidirectionalPeerStreams().size(),
|
||||||
((outOfOrderStream) / kStreamIncrement) + 1);
|
((outOfOrderStream) / kStreamIncrement) + 1);
|
||||||
|
|
||||||
conn.streamManager->getStream(existingStream);
|
conn.streamManager->getStream(existingStream);
|
||||||
EXPECT_EQ(conn.streamManager->streamCount(), 2);
|
EXPECT_EQ(conn.streamManager->streamCount(), 2);
|
||||||
EXPECT_TRUE(conn.streamManager->streamExists(outOfOrderStream));
|
EXPECT_TRUE(conn.streamManager->streamExists(outOfOrderStream));
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
conn.streamManager->openPeerStreams().size(),
|
conn.streamManager->openBidirectionalPeerStreams().size(),
|
||||||
((outOfOrderStream) / kStreamIncrement) + 1);
|
((outOfOrderStream) / kStreamIncrement) + 1);
|
||||||
|
|
||||||
conn.streamManager->openPeerStreams().erase(std::find(
|
conn.streamManager->openBidirectionalPeerStreams().erase(std::find(
|
||||||
conn.streamManager->openPeerStreams().begin(),
|
conn.streamManager->openBidirectionalPeerStreams().begin(),
|
||||||
conn.streamManager->openPeerStreams().end(),
|
conn.streamManager->openBidirectionalPeerStreams().end(),
|
||||||
closedStream));
|
closedStream));
|
||||||
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
|
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
|
||||||
}
|
}
|
||||||
@@ -916,9 +916,9 @@ TEST_F(QuicServerStreamFunctionsTest, GetOrCreateClosedClientStream) {
|
|||||||
StreamId outOfOrderStream1 = 100;
|
StreamId outOfOrderStream1 = 100;
|
||||||
StreamId closedStream = 48;
|
StreamId closedStream = 48;
|
||||||
conn.streamManager->getStream(outOfOrderStream1);
|
conn.streamManager->getStream(outOfOrderStream1);
|
||||||
conn.streamManager->openPeerStreams().erase(std::find(
|
conn.streamManager->openBidirectionalPeerStreams().erase(std::find(
|
||||||
conn.streamManager->openPeerStreams().begin(),
|
conn.streamManager->openBidirectionalPeerStreams().begin(),
|
||||||
conn.streamManager->openPeerStreams().end(),
|
conn.streamManager->openBidirectionalPeerStreams().end(),
|
||||||
closedStream));
|
closedStream));
|
||||||
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
|
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
|
||||||
}
|
}
|
||||||
@@ -929,13 +929,13 @@ TEST_F(
|
|||||||
StreamId outOfOrderStream1 = 96;
|
StreamId outOfOrderStream1 = 96;
|
||||||
StreamId outOfOrderStream2 = 100;
|
StreamId outOfOrderStream2 = 100;
|
||||||
conn.streamManager->getStream(outOfOrderStream1);
|
conn.streamManager->getStream(outOfOrderStream1);
|
||||||
conn.streamManager->openPeerStreams().erase(std::find(
|
conn.streamManager->openBidirectionalPeerStreams().erase(std::find(
|
||||||
conn.streamManager->openPeerStreams().begin(),
|
conn.streamManager->openBidirectionalPeerStreams().begin(),
|
||||||
conn.streamManager->openPeerStreams().end(),
|
conn.streamManager->openBidirectionalPeerStreams().end(),
|
||||||
outOfOrderStream1));
|
outOfOrderStream1));
|
||||||
conn.streamManager->getStream(outOfOrderStream2);
|
conn.streamManager->getStream(outOfOrderStream2);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
conn.streamManager->openPeerStreams().size(),
|
conn.streamManager->openBidirectionalPeerStreams().size(),
|
||||||
(outOfOrderStream2) / kStreamIncrement);
|
(outOfOrderStream2) / kStreamIncrement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,13 +943,13 @@ TEST_F(QuicStreamFunctionsTest, GetOrCreateServerStreamAfterClosingLastStream) {
|
|||||||
StreamId outOfOrderStream1 = 97;
|
StreamId outOfOrderStream1 = 97;
|
||||||
StreamId outOfOrderStream2 = 101;
|
StreamId outOfOrderStream2 = 101;
|
||||||
conn.streamManager->getStream(outOfOrderStream1);
|
conn.streamManager->getStream(outOfOrderStream1);
|
||||||
conn.streamManager->openPeerStreams().erase(std::find(
|
conn.streamManager->openBidirectionalPeerStreams().erase(std::find(
|
||||||
conn.streamManager->openPeerStreams().begin(),
|
conn.streamManager->openBidirectionalPeerStreams().begin(),
|
||||||
conn.streamManager->openPeerStreams().end(),
|
conn.streamManager->openBidirectionalPeerStreams().end(),
|
||||||
outOfOrderStream1));
|
outOfOrderStream1));
|
||||||
conn.streamManager->getStream(outOfOrderStream2);
|
conn.streamManager->getStream(outOfOrderStream2);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
conn.streamManager->openPeerStreams().size(),
|
conn.streamManager->openBidirectionalPeerStreams().size(),
|
||||||
(outOfOrderStream2 + 1) / kStreamIncrement);
|
(outOfOrderStream2 + 1) / kStreamIncrement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -957,9 +957,9 @@ TEST_F(QuicStreamFunctionsTest, GetOrCreateClosedServerStream) {
|
|||||||
StreamId outOfOrderStream1 = 97;
|
StreamId outOfOrderStream1 = 97;
|
||||||
StreamId closedStream = 49;
|
StreamId closedStream = 49;
|
||||||
conn.streamManager->getStream(outOfOrderStream1);
|
conn.streamManager->getStream(outOfOrderStream1);
|
||||||
conn.streamManager->openPeerStreams().erase(std::find(
|
conn.streamManager->openBidirectionalPeerStreams().erase(std::find(
|
||||||
conn.streamManager->openPeerStreams().begin(),
|
conn.streamManager->openBidirectionalPeerStreams().begin(),
|
||||||
conn.streamManager->openPeerStreams().end(),
|
conn.streamManager->openBidirectionalPeerStreams().end(),
|
||||||
closedStream));
|
closedStream));
|
||||||
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
|
EXPECT_EQ(conn.streamManager->getStream(closedStream), nullptr);
|
||||||
}
|
}
|
||||||
@@ -1537,13 +1537,13 @@ TEST_F(QuicServerStreamFunctionsTest, ServerGetClientQuicStream) {
|
|||||||
std::deque<StreamId> newStreams = {0x0, 0x4, 0x8, 0xc, 0x10};
|
std::deque<StreamId> newStreams = {0x0, 0x4, 0x8, 0xc, 0x10};
|
||||||
EXPECT_EQ(conn.streamManager->getStream(clientStream)->id, clientStream);
|
EXPECT_EQ(conn.streamManager->getStream(clientStream)->id, clientStream);
|
||||||
EXPECT_EQ(conn.streamManager->streamCount(), 1);
|
EXPECT_EQ(conn.streamManager->streamCount(), 1);
|
||||||
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 5);
|
EXPECT_EQ(conn.streamManager->openBidirectionalPeerStreams().size(), 5);
|
||||||
EXPECT_EQ(conn.streamManager->newPeerStreams(), newStreams);
|
EXPECT_EQ(conn.streamManager->newPeerStreams(), newStreams);
|
||||||
|
|
||||||
StreamId clientStream2 = 0x4;
|
StreamId clientStream2 = 0x4;
|
||||||
EXPECT_EQ(conn.streamManager->getStream(clientStream2)->id, clientStream2);
|
EXPECT_EQ(conn.streamManager->getStream(clientStream2)->id, clientStream2);
|
||||||
EXPECT_EQ(conn.streamManager->streamCount(), 2);
|
EXPECT_EQ(conn.streamManager->streamCount(), 2);
|
||||||
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 5);
|
EXPECT_EQ(conn.streamManager->openBidirectionalPeerStreams().size(), 5);
|
||||||
EXPECT_EQ(conn.streamManager->newPeerStreams().size(), 5);
|
EXPECT_EQ(conn.streamManager->newPeerStreams().size(), 5);
|
||||||
EXPECT_EQ(conn.streamManager->newPeerStreams(), newStreams);
|
EXPECT_EQ(conn.streamManager->newPeerStreams(), newStreams);
|
||||||
|
|
||||||
@@ -1551,7 +1551,7 @@ TEST_F(QuicServerStreamFunctionsTest, ServerGetClientQuicStream) {
|
|||||||
newStreams = {0x0, 0x2, 0x4, 0x6, 0x8, 0xc, 0x10};
|
newStreams = {0x0, 0x2, 0x4, 0x6, 0x8, 0xc, 0x10};
|
||||||
EXPECT_EQ(conn.streamManager->getStream(clientStream3)->id, clientStream3);
|
EXPECT_EQ(conn.streamManager->getStream(clientStream3)->id, clientStream3);
|
||||||
EXPECT_EQ(conn.streamManager->streamCount(), 3);
|
EXPECT_EQ(conn.streamManager->streamCount(), 3);
|
||||||
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 7);
|
EXPECT_EQ(conn.streamManager->openUnidirectionalPeerStreams().size(), 2);
|
||||||
std::sort(
|
std::sort(
|
||||||
conn.streamManager->newPeerStreams().begin(),
|
conn.streamManager->newPeerStreams().begin(),
|
||||||
conn.streamManager->newPeerStreams().end());
|
conn.streamManager->newPeerStreams().end());
|
||||||
@@ -1636,12 +1636,12 @@ TEST_F(QuicStreamFunctionsTest, ClientGetServerQuicStream) {
|
|||||||
StreamId serverStream = 0x09;
|
StreamId serverStream = 0x09;
|
||||||
EXPECT_EQ(conn.streamManager->getStream(serverStream)->id, serverStream);
|
EXPECT_EQ(conn.streamManager->getStream(serverStream)->id, serverStream);
|
||||||
EXPECT_EQ(conn.streamManager->streamCount(), 1);
|
EXPECT_EQ(conn.streamManager->streamCount(), 1);
|
||||||
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 3);
|
EXPECT_EQ(conn.streamManager->openBidirectionalPeerStreams().size(), 3);
|
||||||
|
|
||||||
StreamId serverStream2 = 0x05;
|
StreamId serverStream2 = 0x05;
|
||||||
EXPECT_EQ(conn.streamManager->getStream(serverStream2)->id, serverStream2);
|
EXPECT_EQ(conn.streamManager->getStream(serverStream2)->id, serverStream2);
|
||||||
EXPECT_EQ(conn.streamManager->streamCount(), 2);
|
EXPECT_EQ(conn.streamManager->streamCount(), 2);
|
||||||
EXPECT_EQ(conn.streamManager->openPeerStreams().size(), 3);
|
EXPECT_EQ(conn.streamManager->openBidirectionalPeerStreams().size(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuicStreamFunctionsTest, ClientGetClientQuicStream) {
|
TEST_F(QuicStreamFunctionsTest, ClientGetClientQuicStream) {
|
||||||
@@ -1692,10 +1692,10 @@ TEST_F(QuicStreamFunctionsTest, StreamExists) {
|
|||||||
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened));
|
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened));
|
||||||
|
|
||||||
auto it = std::find(
|
auto it = std::find(
|
||||||
conn.streamManager->openPeerStreams().begin(),
|
conn.streamManager->openBidirectionalPeerStreams().begin(),
|
||||||
conn.streamManager->openPeerStreams().end(),
|
conn.streamManager->openBidirectionalPeerStreams().end(),
|
||||||
peerAutoOpened);
|
peerAutoOpened);
|
||||||
conn.streamManager->openPeerStreams().erase(it);
|
conn.streamManager->openBidirectionalPeerStreams().erase(it);
|
||||||
|
|
||||||
conn.streamManager->removeClosedStream(peerStream);
|
conn.streamManager->removeClosedStream(peerStream);
|
||||||
|
|
||||||
@@ -1704,6 +1704,34 @@ TEST_F(QuicStreamFunctionsTest, StreamExists) {
|
|||||||
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened2));
|
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(QuicStreamFunctionsTest, StreamLimitUpdates) {
|
||||||
|
StreamId peerStream = 13;
|
||||||
|
StreamId peerAutoOpened = 5;
|
||||||
|
StreamId peerAutoOpened2 = 9;
|
||||||
|
StreamId notOpenedPeer = 17;
|
||||||
|
|
||||||
|
conn.streamManager->setStreamLimitWindowingFraction(
|
||||||
|
conn.transportSettings.advertisedInitialMaxStreamsBidi);
|
||||||
|
conn.streamManager->getStream(peerStream)->send.state =
|
||||||
|
StreamSendStates::Closed{};
|
||||||
|
conn.streamManager->getStream(peerStream)->recv.state =
|
||||||
|
StreamReceiveStates::Closed{};
|
||||||
|
EXPECT_FALSE(conn.streamManager->streamExists(notOpenedPeer));
|
||||||
|
EXPECT_TRUE(conn.streamManager->streamExists(peerStream));
|
||||||
|
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened));
|
||||||
|
|
||||||
|
conn.streamManager->removeClosedStream(peerStream);
|
||||||
|
|
||||||
|
EXPECT_FALSE(conn.streamManager->streamExists(peerStream));
|
||||||
|
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened));
|
||||||
|
EXPECT_TRUE(conn.streamManager->streamExists(peerAutoOpened2));
|
||||||
|
auto update = conn.streamManager->remoteBidirectionalStreamLimitUpdate();
|
||||||
|
ASSERT_TRUE(update);
|
||||||
|
EXPECT_EQ(
|
||||||
|
update.value(),
|
||||||
|
conn.transportSettings.advertisedInitialMaxStreamsBidi + 1);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(QuicStreamFunctionsTest, AllBytesTillFinAcked) {
|
TEST_F(QuicStreamFunctionsTest, AllBytesTillFinAcked) {
|
||||||
StreamId id = 3;
|
StreamId id = 3;
|
||||||
QuicStreamState stream(id, conn);
|
QuicStreamState stream(id, conn);
|
||||||
|
@@ -178,5 +178,75 @@ TEST_F(QuicStreamManagerTest, TestAppIdleCloseControlStream) {
|
|||||||
manager.removeClosedStream(stream->id);
|
manager.removeClosedStream(stream->id);
|
||||||
EXPECT_TRUE(manager.isAppIdle());
|
EXPECT_TRUE(manager.isAppIdle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(QuicStreamManagerTest, StreamLimitWindowedUpdate) {
|
||||||
|
auto& manager = *conn.streamManager;
|
||||||
|
conn.transportSettings.advertisedInitialMaxStreamsBidi = 100;
|
||||||
|
conn.transportSettings.advertisedInitialMaxStreamsUni = 100;
|
||||||
|
manager.refreshTransportSettings(conn.transportSettings);
|
||||||
|
manager.setStreamLimitWindowingFraction(4);
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
manager.getStream(i * detail::kStreamIncrement);
|
||||||
|
manager.getStream(2 + i * detail::kStreamIncrement);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 25; i++) {
|
||||||
|
auto stream = manager.getStream(i * detail::kStreamIncrement);
|
||||||
|
stream->send.state = StreamSendStates::Closed();
|
||||||
|
stream->recv.state = StreamReceiveStates::Closed();
|
||||||
|
manager.removeClosedStream(stream->id);
|
||||||
|
stream = manager.getStream(2 + i * detail::kStreamIncrement);
|
||||||
|
stream->send.state = StreamSendStates::Closed();
|
||||||
|
stream->recv.state = StreamReceiveStates::Closed();
|
||||||
|
manager.removeClosedStream(stream->id);
|
||||||
|
}
|
||||||
|
auto update = manager.remoteBidirectionalStreamLimitUpdate();
|
||||||
|
ASSERT_TRUE(update);
|
||||||
|
EXPECT_EQ(update.value(), 125);
|
||||||
|
EXPECT_FALSE(manager.remoteBidirectionalStreamLimitUpdate());
|
||||||
|
|
||||||
|
update = manager.remoteUnidirectionalStreamLimitUpdate();
|
||||||
|
ASSERT_TRUE(update);
|
||||||
|
EXPECT_EQ(update.value(), 125);
|
||||||
|
EXPECT_FALSE(manager.remoteUnidirectionalStreamLimitUpdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QuicStreamManagerTest, StreamLimitNoWindowedUpdate) {
|
||||||
|
auto& manager = *conn.streamManager;
|
||||||
|
conn.transportSettings.advertisedInitialMaxStreamsBidi = 100;
|
||||||
|
manager.refreshTransportSettings(conn.transportSettings);
|
||||||
|
manager.setStreamLimitWindowingFraction(4);
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
manager.getStream(i * detail::kStreamIncrement);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 24; i++) {
|
||||||
|
auto stream = manager.getStream(i * detail::kStreamIncrement);
|
||||||
|
stream->send.state = StreamSendStates::Closed();
|
||||||
|
stream->recv.state = StreamReceiveStates::Closed();
|
||||||
|
manager.removeClosedStream(stream->id);
|
||||||
|
}
|
||||||
|
auto update = manager.remoteBidirectionalStreamLimitUpdate();
|
||||||
|
EXPECT_FALSE(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(QuicStreamManagerTest, StreamLimitManyWindowedUpdate) {
|
||||||
|
auto& manager = *conn.streamManager;
|
||||||
|
conn.transportSettings.advertisedInitialMaxStreamsBidi = 100;
|
||||||
|
manager.refreshTransportSettings(conn.transportSettings);
|
||||||
|
manager.setStreamLimitWindowingFraction(4);
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
manager.getStream(i * detail::kStreamIncrement);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 50; i++) {
|
||||||
|
auto stream = manager.getStream(i * detail::kStreamIncrement);
|
||||||
|
stream->send.state = StreamSendStates::Closed();
|
||||||
|
stream->recv.state = StreamReceiveStates::Closed();
|
||||||
|
manager.removeClosedStream(stream->id);
|
||||||
|
}
|
||||||
|
auto update = manager.remoteBidirectionalStreamLimitUpdate();
|
||||||
|
ASSERT_TRUE(update);
|
||||||
|
EXPECT_EQ(update.value(), 150);
|
||||||
|
EXPECT_FALSE(manager.remoteBidirectionalStreamLimitUpdate());
|
||||||
|
EXPECT_FALSE(manager.remoteUnidirectionalStreamLimitUpdate());
|
||||||
|
}
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace quic
|
} // namespace quic
|
||||||
|
Reference in New Issue
Block a user