diff --git a/quic/api/QuicTransportBase.cpp b/quic/api/QuicTransportBase.cpp index 77fd5a7e1..d1195287f 100644 --- a/quic/api/QuicTransportBase.cpp +++ b/quic/api/QuicTransportBase.cpp @@ -2351,10 +2351,14 @@ void QuicTransportBase::idleTimeoutExpired(bool drain) noexcept { // idle timeout is expired, just close the connection and drain or // send connection close immediately depending on 'drain' DCHECK_NE(closeState_, CloseState::CLOSED); + uint64_t numOpenStreans = conn_->streamManager->streamCount(); closeImpl( std::make_pair( QuicErrorCode(LocalErrorCode::IDLE_TIMEOUT), - toString(LocalErrorCode::IDLE_TIMEOUT).str()), + folly::to( + toString(LocalErrorCode::IDLE_TIMEOUT), + ", num non control streams: ", + numOpenStreans - conn_->streamManager->numControlStreams())), drain /* drainConnection */, !drain /* sendCloseImmediately */); } diff --git a/quic/api/test/QuicTransportBaseTest.cpp b/quic/api/test/QuicTransportBaseTest.cpp index 5db887ddf..c76f0db65 100644 --- a/quic/api/test/QuicTransportBaseTest.cpp +++ b/quic/api/test/QuicTransportBaseTest.cpp @@ -429,6 +429,32 @@ TEST_F(QuicTransportImplTest, IdleTimeoutExpiredDestroysTransport) { transport->invokeIdleTimeout(); } +TEST_F(QuicTransportImplTest, IdleTimeoutStreamMaessage) { + auto stream1 = transport->createBidirectionalStream().value(); + auto stream2 = transport->createBidirectionalStream().value(); + auto stream3 = transport->createUnidirectionalStream().value(); + transport->setControlStream(stream3); + + NiceMock readCb1; + NiceMock readCb2; + + transport->setReadCallback(stream1, &readCb1); + transport->setReadCallback(stream2, &readCb2); + + transport->addDataToStream( + stream1, StreamBuffer(folly::IOBuf::copyBuffer("actual stream data"), 0)); + transport->addDataToStream( + stream2, + StreamBuffer(folly::IOBuf::copyBuffer("actual stream data"), 10)); + EXPECT_CALL(readCb1, readError(stream1, _)) + .Times(1) + .WillOnce(Invoke([](auto, auto error) { + EXPECT_EQ( + "Idle timeout, num non control streams: 2", error.second->str()); + })); + transport->invokeIdleTimeout(); +} + TEST_F(QuicTransportImplTest, WriteAckPacketUnsetsLooper) { // start looper in running state first transport->writeLooper()->run(true); diff --git a/quic/state/QuicStreamManager.h b/quic/state/QuicStreamManager.h index dd4d65bb7..5d904a5b2 100644 --- a/quic/state/QuicStreamManager.h +++ b/quic/state/QuicStreamManager.h @@ -725,6 +725,13 @@ class QuicStreamManager { return streams_.size() != numControlStreams_; } + /* + * Returns number of control streams. + */ + auto numControlStreams() { + return numControlStreams_; + } + /* * Sets the given stream to be tracked as a control stream. */