mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-08-05 11:21:09 +03:00
Allow unset read callback during connection close
Summary: setReadCallback didn't function properly during shutdown 1) it was completely ignored when state_ == CLOSING 2) cancelAllAppCallbacks made a copy of readCallbacks_ This is problematic for application constructs that use groups of streams -- eg: HTTP WebTransport. When one stream (the WebTransport session) is reset during shutdown, it needs to clean up any dependent streams as well, including preventing them from getting error callbacks. The fix is to use only the streamId's from readCallbacksCopy for iteration, but look up the actual callback value from readCallbacks_. Note: there's an as yet unhandled corner case which is that a readError callback installs a new stream read callback, but it seems far fetched enough I'm not including a fix here. Reviewed By: sharmafb Differential Revision: D48159644 fbshipit-source-id: c9d522a6b200538193969d60d242a505831e4cd0
This commit is contained in:
committed by
Facebook GitHub Bot
parent
185d853a9c
commit
900e22e18d
@@ -3094,12 +3094,15 @@ TEST_P(QuicTransportImplTestBase, TestGracefulCloseWithNoActiveStream) {
|
||||
|
||||
TEST_P(QuicTransportImplTestBase, TestImmediateClose) {
|
||||
auto stream = transport->createBidirectionalStream().value();
|
||||
auto stream2 = transport->createBidirectionalStream().value();
|
||||
NiceMock<MockWriteCallback> wcb;
|
||||
NiceMock<MockWriteCallback> wcbConn;
|
||||
NiceMock<MockReadCallback> rcb;
|
||||
NiceMock<MockReadCallback> rcb2;
|
||||
NiceMock<MockPeekCallback> pcb;
|
||||
NiceMock<MockDeliveryCallback> deliveryCb;
|
||||
NiceMock<MockByteEventCallback> txCb;
|
||||
uint8_t resetCount = 0;
|
||||
EXPECT_CALL(
|
||||
wcb,
|
||||
onStreamWriteError(
|
||||
@@ -3107,8 +3110,21 @@ TEST_P(QuicTransportImplTestBase, TestImmediateClose) {
|
||||
EXPECT_CALL(
|
||||
wcbConn,
|
||||
onConnectionWriteError(IsAppError(GenericApplicationErrorCode::UNKNOWN)));
|
||||
EXPECT_CALL(
|
||||
rcb, readError(stream, IsAppError(GenericApplicationErrorCode::UNKNOWN)));
|
||||
// The first stream to get a reset will clear the other read callback, so only
|
||||
// one will receive a reset.
|
||||
ON_CALL(
|
||||
rcb, readError(stream, IsAppError(GenericApplicationErrorCode::UNKNOWN)))
|
||||
.WillByDefault(InvokeWithoutArgs([this, stream2, &resetCount] {
|
||||
transport->setReadCallback(stream2, nullptr);
|
||||
resetCount++;
|
||||
}));
|
||||
ON_CALL(
|
||||
rcb2,
|
||||
readError(stream2, IsAppError(GenericApplicationErrorCode::UNKNOWN)))
|
||||
.WillByDefault(InvokeWithoutArgs([this, stream, &resetCount] {
|
||||
transport->setReadCallback(stream, nullptr);
|
||||
resetCount++;
|
||||
}));
|
||||
EXPECT_CALL(
|
||||
pcb, peekError(stream, IsAppError(GenericApplicationErrorCode::UNKNOWN)));
|
||||
EXPECT_CALL(deliveryCb, onCanceled(stream, _));
|
||||
@@ -3120,6 +3136,7 @@ TEST_P(QuicTransportImplTestBase, TestImmediateClose) {
|
||||
transport->notifyPendingWriteOnConnection(&wcbConn);
|
||||
transport->notifyPendingWriteOnStream(stream, &wcb);
|
||||
transport->setReadCallback(stream, &rcb);
|
||||
transport->setReadCallback(stream2, &rcb2);
|
||||
transport->setPeekCallback(stream, &pcb);
|
||||
EXPECT_CALL(*socketPtr, write(_, _, _))
|
||||
.WillRepeatedly(SetErrnoAndReturn(EAGAIN, -1));
|
||||
@@ -3151,6 +3168,7 @@ TEST_P(QuicTransportImplTestBase, TestImmediateClose) {
|
||||
EXPECT_EQ(
|
||||
transport->transportConn->streamManager->getStream(stream), nullptr);
|
||||
qEvb->loopOnce();
|
||||
EXPECT_EQ(resetCount, 1);
|
||||
}
|
||||
|
||||
TEST_P(QuicTransportImplTestBase, ResetStreamUnsetWriteCallback) {
|
||||
|
Reference in New Issue
Block a user