diff --git a/src/core/stream.h b/src/core/stream.h index a218e0ac1c..4e05e2cfc8 100644 --- a/src/core/stream.h +++ b/src/core/stream.h @@ -124,7 +124,7 @@ typedef union QUIC_STREAM_FLAGS { BOOLEAN LocalCloseReset : 1; // Locally closed (locally aborted). BOOLEAN LocalCloseResetReliable : 1; // Indicates that we should shutdown the send path once we sent/ACK'd ReliableOffsetSend bytes. BOOLEAN LocalCloseResetReliableAcked : 1; // Indicates the peer has acknowledged we will stop sending once we sent/ACK'd ReliableOffsetSend bytes. - BOOLEAN RemoteCloseResetReliable : 1; // Indicates that the peer initiaited a reliable reset. Keep Recv path available for RecvMaxLength bytes. + BOOLEAN RemoteCloseResetReliable : 1; // Indicates that the peer initiated a reliable reset. Keep Recv path available for RecvMaxLength bytes. BOOLEAN ReceivedStopSending : 1; // Peer sent STOP_SENDING frame. BOOLEAN LocalCloseAcked : 1; // Any close acknowledged. BOOLEAN FinAcked : 1; // Our FIN was acknowledged. @@ -144,6 +144,8 @@ typedef union QUIC_STREAM_FLAGS { BOOLEAN ReceiveCallPending : 1; // There is an uncompleted receive to the app. BOOLEAN ReceiveCallActive : 1; // There is an active receive to the app. BOOLEAN SendDelayed : 1; // A delayed send is currently queued. + BOOLEAN CancelOnLoss : 1; // Indicates that the stream is to be canceled + // if loss is detected. BOOLEAN HandleSendShutdown : 1; // Send shutdown complete callback delivered. BOOLEAN HandleShutdown : 1; // Shutdown callback delivered. @@ -155,8 +157,6 @@ typedef union QUIC_STREAM_FLAGS { BOOLEAN InStreamTable : 1; // The stream is currently in the connection's table. BOOLEAN DelayIdFcUpdate : 1; // Delay stream ID FC updates to StreamClose. - - BOOLEAN CancelOnLoss : 1; // Indicates that the stream is to be canceled if loss is detected. }; } QUIC_STREAM_FLAGS; diff --git a/src/core/stream_send.c b/src/core/stream_send.c index ece3f86ed4..2ce3864417 100644 --- a/src/core/stream_send.c +++ b/src/core/stream_send.c @@ -613,8 +613,10 @@ QuicStreamSendFlush( CXPLAT_DBG_ASSERT(!(SendRequest->Flags & QUIC_SEND_FLAG_BUFFERED)); + // // If a send has the 'cancel on loss' flag set, we irreversibly switch // the associated stream over to that behavior. + // if (!Stream->Flags.CancelOnLoss && (SendRequest->Flags & QUIC_SEND_FLAG_CANCEL_ON_LOSS) != 0) { Stream->Flags.CancelOnLoss = TRUE; @@ -1371,25 +1373,26 @@ QuicStreamOnLoss( Done: if (AddSendFlags != 0) { - - // Check stream's 'cancel on loss' flag to determine how to handle the resends queued up at this point. + // + // Check stream's 'cancel on loss' flag to determine how to handle + // the resends queued up at this point. + // if (Stream->Flags.CancelOnLoss) { QUIC_STREAM_EVENT Event; Event.Type = QUIC_STREAM_EVENT_CANCEL_ON_LOSS; Event.CANCEL_ON_LOSS.ErrorCode = 0; - - // Call to app callback requesting error code. (void)QuicStreamIndicateEvent(Stream, &Event); + // // Immediately terminate stream (in both directions, if open) // giving the error code from the app. + // QuicStreamShutdown( Stream, QUIC_STREAM_SHUTDOWN_FLAG_ABORT, Event.CANCEL_ON_LOSS.ErrorCode); - // Don't resend any data. - return FALSE; + return FALSE; // Don't resend any data. } if (!Stream->Flags.InRecovery) { diff --git a/src/plugins/dbg/quictypes.h b/src/plugins/dbg/quictypes.h index eb13feeaa8..413e62b810 100644 --- a/src/plugins/dbg/quictypes.h +++ b/src/plugins/dbg/quictypes.h @@ -62,6 +62,8 @@ typedef union QUIC_STREAM_FLAGS { BOOLEAN ReceiveCallPending : 1; // There is an uncompleted receive to the app. BOOLEAN ReceiveCallActive : 1; // There is an active receive to the app. BOOLEAN SendDelayed : 1; // A delayed send is currently queued. + BOOLEAN CancelOnLoss : 1; // Indicates that the stream is to be canceled + // if loss is detected. BOOLEAN HandleSendShutdown : 1; // Send shutdown complete callback delivered. BOOLEAN HandleShutdown : 1; // Shutdown callback delivered. diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index d0716a841a..6736958196 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -470,7 +470,7 @@ QuicAbortiveTransfers( void QuicCancelOnLossSend( _In_ bool DropPackets -); + ); void QuicTestCidUpdate( @@ -1262,6 +1262,6 @@ typedef struct { #define IOCTL_QUIC_RUN_CANCEL_ON_LOSS \ QUIC_CTL_CODE(118, METHOD_BUFFERED, FILE_WRITE_DATA) -// QUIC_RUN_CANCEL_ON_LOSS_PARAMS + // QUIC_RUN_CANCEL_ON_LOSS_PARAMS #define QUIC_MAX_IOCTL_FUNC_CODE 118 diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index 394b8b2db1..7c3daf52b4 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1967,6 +1967,7 @@ TEST_P(WithAbortiveArgs, AbortiveShutdown) { } } +#if QUIC_TEST_DATAPATH_HOOKS_ENABLED TEST_P(WithCancelOnLossArgs, CancelOnLossSend) { TestLoggerT Logger("QuicCancelOnLossSend", GetParam()); if (TestingKernelMode) { @@ -1978,6 +1979,7 @@ TEST_P(WithCancelOnLossArgs, CancelOnLossSend) { QuicCancelOnLossSend(GetParam().DropPackets); } } +#endif TEST_P(WithCidUpdateArgs, CidUpdate) { TestLoggerT Logger("QuicTestCidUpdate", GetParam()); @@ -2443,11 +2445,15 @@ INSTANTIATE_TEST_SUITE_P( WithAbortiveArgs, testing::ValuesIn(AbortiveArgs::Generate())); +#if QUIC_TEST_DATAPATH_HOOKS_ENABLED + INSTANTIATE_TEST_SUITE_P( Misc, WithCancelOnLossArgs, testing::ValuesIn(CancelOnLossArgs::Generate())); +#endif + INSTANTIATE_TEST_SUITE_P( Misc, WithCidUpdateArgs, diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index 94e8350d4f..112e70cccd 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -1534,9 +1534,7 @@ QuicTestCtlEvtIoDeviceControl( case IOCTL_QUIC_RUN_CANCEL_ON_LOSS: CXPLAT_FRE_ASSERT(Params != nullptr); - QuicTestCtlRun( - QuicCancelOnLossSend( - Params->DropPackets)); + QuicTestCtlRun(QuicCancelOnLossSend(Params->DropPackets)); break; default: diff --git a/src/test/lib/DataTest.cpp b/src/test/lib/DataTest.cpp index c673913466..d1fd2dbc3f 100644 --- a/src/test/lib/DataTest.cpp +++ b/src/test/lib/DataTest.cpp @@ -1405,7 +1405,7 @@ QuicCancelOnLossStreamHandler( _In_ struct MsQuicStream* /* Stream */, _In_opt_ void* Context, _Inout_ QUIC_STREAM_EVENT* Event -) + ) { if (Context == nullptr) { return QUIC_STATUS_INVALID_PARAMETER; @@ -1426,8 +1426,7 @@ QuicCancelOnLossStreamHandler( if (TestContext->IsServer) { // server-side 'cancel on loss' detection TestContext->SendPhaseEndedEvent.Set(); TestContext->ExitCode = Event->PEER_SEND_ABORTED.ErrorCode; - } - else { + } else { Status = QUIC_STATUS_INVALID_STATE; } break; @@ -1441,8 +1440,7 @@ QuicCancelOnLossStreamHandler( if (!TestContext->IsDropScenario) { // if drop scenario, we use 'cancel on loss' event TestContext->SendPhaseEndedEvent.Set(); } - } - else { + } else { Status = QUIC_STATUS_INVALID_STATE; } break; @@ -1450,8 +1448,7 @@ QuicCancelOnLossStreamHandler( if (!TestContext->IsServer && TestContext->IsDropScenario) { // only client sends & only happens if in drop scenario Event->CANCEL_ON_LOSS.ErrorCode = CancelOnLossContext::ErrorExitCode; TestContext->SendPhaseEndedEvent.Set(); - } - else { + } else { Status = QUIC_STATUS_INVALID_STATE; } break; @@ -1468,7 +1465,7 @@ QuicCancelOnLossConnectionHandler( _In_ struct MsQuicConnection* /* Connection */, _In_opt_ void* Context, _Inout_ QUIC_CONNECTION_EVENT* Event -) + ) { if (Context == nullptr) { return QUIC_STATUS_INVALID_PARAMETER; @@ -1532,7 +1529,7 @@ QuicCancelOnLossListenerHandler( void QuicCancelOnLossSend( _In_ bool DropPackets -) + ) { MsQuicRegistration Registration; TEST_TRUE(Registration.IsValid()); @@ -1640,8 +1637,7 @@ QuicCancelOnLossSend( // Check results. if (DropPackets) { TEST_EQUAL(ServerContext.ExitCode, CancelOnLossContext::ErrorExitCode); - } - else { + } else { TEST_EQUAL(ServerContext.ExitCode, CancelOnLossContext::SuccessExitCode); } }