зеркало из https://github.com/microsoft/msquic.git
Add Test Interface for Datapath Filtering (#361)
This commit is contained in:
Родитель
bb9439da88
Коммит
bb010bc13b
|
@ -1414,6 +1414,28 @@ QuicBindingReceive(
|
|||
DatagramChain = Datagram->Next;
|
||||
Datagram->Next = NULL;
|
||||
|
||||
QUIC_RECV_PACKET* Packet =
|
||||
QuicDataPathRecvDatagramToRecvPacket(Datagram);
|
||||
QuicZeroMemory(Packet, sizeof(QUIC_RECV_PACKET));
|
||||
Packet->Buffer = Datagram->Buffer;
|
||||
Packet->BufferLength = Datagram->BufferLength;
|
||||
|
||||
#if DEBUG
|
||||
//
|
||||
// The test datapath receive callback allows for test code to modify
|
||||
// the datagrams on the receive path, and optionally indicate one or
|
||||
// more to be dropped.
|
||||
//
|
||||
if (MsQuicLib.TestDatapathHooks != NULL) {
|
||||
if (MsQuicLib.TestDatapathHooks->Receive(Datagram)) {
|
||||
*ReleaseChainTail = Datagram;
|
||||
ReleaseChainTail = &Datagram->Next;
|
||||
QuicPacketLogDrop(Binding, Packet, "Test Dopped");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Perform initial validation.
|
||||
//
|
||||
|
@ -1426,8 +1448,6 @@ QuicBindingReceive(
|
|||
continue;
|
||||
}
|
||||
|
||||
QUIC_RECV_PACKET* Packet =
|
||||
QuicDataPathRecvDatagramToRecvPacket(Datagram);
|
||||
QUIC_DBG_ASSERT(Packet->DestCid != NULL);
|
||||
QUIC_DBG_ASSERT(Packet->DestCidLen != 0 || Binding->Exclusive);
|
||||
QUIC_DBG_ASSERT(Packet->ValidatedHeaderInv);
|
||||
|
@ -1530,8 +1550,38 @@ QuicBindingSendTo(
|
|||
{
|
||||
QUIC_STATUS Status;
|
||||
|
||||
#if QUIC_SEND_FAKE_LOSS
|
||||
if (QuicFakeLossCanSend()) {
|
||||
#if DEBUG
|
||||
if (MsQuicLib.TestDatapathHooks != NULL) {
|
||||
|
||||
QUIC_ADDR RemoteAddressCopy = *RemoteAddress;
|
||||
BOOLEAN Drop =
|
||||
MsQuicLib.TestDatapathHooks->Send(
|
||||
&RemoteAddressCopy,
|
||||
NULL,
|
||||
SendContext);
|
||||
|
||||
if (Drop) {
|
||||
QuicTraceLogVerbose(
|
||||
BindingSendToTestDrop,
|
||||
"[bind][%p] Test dropped packet",
|
||||
Binding);
|
||||
QuicDataPathBindingFreeSendContext(SendContext);
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
} else {
|
||||
Status =
|
||||
QuicDataPathBindingSendTo(
|
||||
Binding->DatapathBinding,
|
||||
&RemoteAddressCopy,
|
||||
SendContext);
|
||||
if (QUIC_FAILED(Status)) {
|
||||
QuicTraceLogWarning(
|
||||
BindingSendToFailed,
|
||||
"[bind][%p] SendTo failed, 0x%x",
|
||||
Binding,
|
||||
Status);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
Status =
|
||||
QuicDataPathBindingSendTo(
|
||||
|
@ -1545,14 +1595,7 @@ QuicBindingSendTo(
|
|||
Binding,
|
||||
Status);
|
||||
}
|
||||
#if QUIC_SEND_FAKE_LOSS
|
||||
} else {
|
||||
QuicTraceLogVerbose(
|
||||
BindingSendToFakeDrop,
|
||||
"[bind][%p] Dropped (fake loss) packet",
|
||||
Binding);
|
||||
QuicDataPathBindingFreeSendContext(SendContext);
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
#if DEBUG
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1570,8 +1613,40 @@ QuicBindingSendFromTo(
|
|||
{
|
||||
QUIC_STATUS Status;
|
||||
|
||||
#if QUIC_SEND_FAKE_LOSS
|
||||
if (QuicFakeLossCanSend()) {
|
||||
#if DEBUG
|
||||
if (MsQuicLib.TestDatapathHooks != NULL) {
|
||||
|
||||
QUIC_ADDR RemoteAddressCopy = *RemoteAddress;
|
||||
QUIC_ADDR LocalAddressCopy = *LocalAddress;
|
||||
BOOLEAN Drop =
|
||||
MsQuicLib.TestDatapathHooks->Send(
|
||||
&RemoteAddressCopy,
|
||||
&LocalAddressCopy,
|
||||
SendContext);
|
||||
|
||||
if (Drop) {
|
||||
QuicTraceLogVerbose(
|
||||
BindingSendFromToTestDrop,
|
||||
"[bind][%p] Test dropped packet",
|
||||
Binding);
|
||||
QuicDataPathBindingFreeSendContext(SendContext);
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
} else {
|
||||
Status =
|
||||
QuicDataPathBindingSendFromTo(
|
||||
Binding->DatapathBinding,
|
||||
&LocalAddressCopy,
|
||||
&RemoteAddressCopy,
|
||||
SendContext);
|
||||
if (QUIC_FAILED(Status)) {
|
||||
QuicTraceLogWarning(
|
||||
BindingSendFromToFailed,
|
||||
"[bind][%p] SendFromTo failed, 0x%x",
|
||||
Binding,
|
||||
Status);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
Status =
|
||||
QuicDataPathBindingSendFromTo(
|
||||
|
@ -1586,14 +1661,7 @@ QuicBindingSendFromTo(
|
|||
Binding,
|
||||
Status);
|
||||
}
|
||||
#if QUIC_SEND_FAKE_LOSS
|
||||
} else {
|
||||
QuicTraceLogVerbose(
|
||||
SendFromToFakeDrop,
|
||||
"[bind][%p] Dropped (fake loss) packet",
|
||||
Binding);
|
||||
QuicDataPathBindingFreeSendContext(SendContext);
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
#if DEBUG
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1422,10 +1422,9 @@ QuicConnTryClose(
|
|||
if (!ClosedRemotely) {
|
||||
|
||||
if ((Flags & QUIC_CLOSE_APPLICATION) &&
|
||||
Connection->Crypto.TlsState.WriteKeys[QUIC_PACKET_KEY_0_RTT] == NULL &&
|
||||
Connection->Crypto.TlsState.WriteKeys[QUIC_PACKET_KEY_1_RTT] == NULL) {
|
||||
//
|
||||
// Application close can only happen if we have 0/1-RTT keys.
|
||||
// Application close can only happen if we have 1-RTT keys.
|
||||
// Otherwise we have to send "user_canceled" TLS error code as a
|
||||
// connection close. Overwrite all application provided parameters.
|
||||
//
|
||||
|
|
|
@ -516,31 +516,6 @@ QuicLibrarySetGlobalParam(
|
|||
Status = QUIC_STATUS_SUCCESS;
|
||||
break;
|
||||
|
||||
case QUIC_PARAM_GLOBAL_ENCRYPTION:
|
||||
|
||||
if (BufferLength != sizeof(uint8_t)) {
|
||||
Status = QUIC_STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
if (MsQuicLib.InUse &&
|
||||
MsQuicLib.EncryptionDisabled != (*(uint8_t*)Buffer == FALSE)) {
|
||||
QuicTraceLogError(
|
||||
LibraryEncryptionSetAfterInUse,
|
||||
"[ lib] Tried to change encryption state after library in use!");
|
||||
Status = QUIC_STATUS_INVALID_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
MsQuicLib.EncryptionDisabled = *(uint8_t*)Buffer == FALSE;
|
||||
QuicTraceLogWarning(
|
||||
LibraryEncryptionSet,
|
||||
"[ lib] Updated encryption disabled = %hu",
|
||||
MsQuicLib.EncryptionDisabled);
|
||||
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
break;
|
||||
|
||||
case QUIC_PARAM_GLOBAL_LOAD_BALACING_MODE: {
|
||||
|
||||
if (BufferLength != sizeof(uint16_t)) {
|
||||
|
@ -571,6 +546,56 @@ QuicLibrarySetGlobalParam(
|
|||
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
break;
|
||||
|
||||
case QUIC_PARAM_GLOBAL_ENCRYPTION:
|
||||
|
||||
if (BufferLength != sizeof(uint8_t)) {
|
||||
Status = QUIC_STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
if (MsQuicLib.InUse &&
|
||||
MsQuicLib.EncryptionDisabled != (*(uint8_t*)Buffer == FALSE)) {
|
||||
QuicTraceLogError(
|
||||
LibraryEncryptionSetAfterInUse,
|
||||
"[ lib] Tried to change encryption state after library in use!");
|
||||
Status = QUIC_STATUS_INVALID_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
MsQuicLib.EncryptionDisabled = *(uint8_t*)Buffer == FALSE;
|
||||
QuicTraceLogWarning(
|
||||
LibraryEncryptionSet,
|
||||
"[ lib] Updated encryption disabled = %hu",
|
||||
MsQuicLib.EncryptionDisabled);
|
||||
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
break;
|
||||
|
||||
#if DEBUG
|
||||
case QUIC_PARAM_GLOBAL_TEST_DATAPATH_HOOKS:
|
||||
|
||||
if (BufferLength != sizeof(QUIC_TEST_DATAPATH_HOOKS*)) {
|
||||
Status = QUIC_STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
if (MsQuicLib.InUse) {
|
||||
QuicTraceLogError(
|
||||
LibraryTestDatapathHooksSetAfterInUse,
|
||||
"[ lib] Tried to change test datapath hooks after library in use!");
|
||||
Status = QUIC_STATUS_INVALID_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
MsQuicLib.TestDatapathHooks = *(QUIC_TEST_DATAPATH_HOOKS**)Buffer;
|
||||
QuicTraceLogWarning(
|
||||
LibraryTestDatapathHooksSet,
|
||||
"[ lib] Updated test datapath hooks");
|
||||
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
|
@ -207,6 +207,13 @@ typedef struct QUIC_LIBRARY {
|
|||
//
|
||||
QUIC_TOEPLITZ_HASH ToeplitzHash;
|
||||
|
||||
#if DEBUG
|
||||
//
|
||||
// An optional callback to allow test code to modify the data path.
|
||||
//
|
||||
QUIC_TEST_DATAPATH_HOOKS* TestDatapathHooks;
|
||||
#endif
|
||||
|
||||
} QUIC_LIBRARY;
|
||||
|
||||
extern QUIC_LIBRARY MsQuicLib;
|
||||
|
|
|
@ -376,13 +376,14 @@ QuicPacketBuilderGetPacketTypeAndKeyForControlFrames(
|
|||
KeyType <= Connection->Crypto.TlsState.WriteKey;
|
||||
++KeyType) {
|
||||
|
||||
if (KeyType == QUIC_PACKET_KEY_0_RTT) {
|
||||
continue; // Crypto is never written with 0-RTT key.
|
||||
}
|
||||
|
||||
QUIC_PACKET_KEY* PacketsKey =
|
||||
Connection->Crypto.TlsState.WriteKeys[KeyType];
|
||||
if (PacketsKey == NULL) {
|
||||
//
|
||||
// Key has been discarded.
|
||||
//
|
||||
continue;
|
||||
continue; // Key has been discarded.
|
||||
}
|
||||
|
||||
QUIC_ENCRYPT_LEVEL EncryptLevel = QuicKeyTypeToEncryptLevel(KeyType);
|
||||
|
@ -427,7 +428,11 @@ QuicPacketBuilderGetPacketTypeAndKeyForControlFrames(
|
|||
// this key, so the CLOSE frame should be sent at the current and
|
||||
// previous encryption level if the handshake hasn't been confirmed.
|
||||
//
|
||||
if (Connection->Crypto.TlsState.WriteKey == QUIC_PACKET_KEY_0_RTT) {
|
||||
*PacketKeyType = QUIC_PACKET_KEY_INITIAL;
|
||||
} else {
|
||||
*PacketKeyType = Connection->Crypto.TlsState.WriteKey;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,8 +98,7 @@ QuicSendCanSendFlagsNow(
|
|||
)
|
||||
{
|
||||
QUIC_CONNECTION* Connection = QuicSendGetConnection(Send);
|
||||
if (Connection->Crypto.TlsState.WriteKey < QUIC_PACKET_KEY_1_RTT &&
|
||||
Connection->Crypto.TlsState.WriteKeys[QUIC_PACKET_KEY_0_RTT] == NULL) {
|
||||
if (Connection->Crypto.TlsState.WriteKey < QUIC_PACKET_KEY_1_RTT) {
|
||||
if ((!Connection->State.Started && !QuicConnIsServer(Connection)) ||
|
||||
!(Send->SendFlags & QUIC_CONN_SEND_FLAG_ALLOWED_HANDSHAKE)) {
|
||||
return FALSE;
|
||||
|
@ -988,8 +987,7 @@ QuicSendFlush(
|
|||
}
|
||||
|
||||
uint32_t SendFlags = Send->SendFlags;
|
||||
if (Connection->Crypto.TlsState.WriteKey < QUIC_PACKET_KEY_1_RTT &&
|
||||
Connection->Crypto.TlsState.WriteKeys[QUIC_PACKET_KEY_0_RTT] == NULL) {
|
||||
if (Connection->Crypto.TlsState.WriteKey < QUIC_PACKET_KEY_1_RTT) {
|
||||
SendFlags &= QUIC_CONN_SEND_FLAG_ALLOWED_HANDSHAKE;
|
||||
}
|
||||
|
||||
|
@ -1037,6 +1035,7 @@ QuicSendFlush(
|
|||
BOOLEAN WrotePacketFrames;
|
||||
BOOLEAN FlushBatchedDatagrams = FALSE;
|
||||
if ((SendFlags & ~QUIC_CONN_SEND_FLAG_PMTUD) != 0) {
|
||||
QUIC_DBG_ASSERT(QuicSendCanSendFlagsNow(Send));
|
||||
if (!QuicPacketBuilderPrepareForControlFrames(
|
||||
&Builder,
|
||||
Send->TailLossProbeNeeded,
|
||||
|
|
|
@ -399,19 +399,3 @@ QuicSendOnMtuProbePacketAcked(
|
|||
_In_ QUIC_PATH* Path,
|
||||
_In_ QUIC_SENT_PACKET_METADATA* Packet
|
||||
);
|
||||
|
||||
#if QUIC_SEND_FAKE_LOSS
|
||||
//
|
||||
// QUIC_SEND_FAKE_LOSS defines a percentage of dropped packets.
|
||||
//
|
||||
inline
|
||||
BOOLEAN
|
||||
QuicFakeLossCanSend(
|
||||
void
|
||||
)
|
||||
{
|
||||
uint8_t RandomValue;
|
||||
QuicRandom(sizeof(RandomValue), &RandomValue);
|
||||
return (RandomValue % 100) >= QUIC_SEND_FAKE_LOSS;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -29,7 +29,36 @@ extern "C" {
|
|||
//
|
||||
// The different private parameters for QUIC_PARAM_LEVEL_GLOBAL.
|
||||
//
|
||||
|
||||
//
|
||||
// Returns TRUE to drop the packet.
|
||||
//
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
(QUIC_API * QUIC_TEST_DATAPATH_RECEIVE_HOOK)(
|
||||
_Inout_ struct QUIC_RECV_DATAGRAM* Datagram
|
||||
);
|
||||
|
||||
//
|
||||
// Returns TRUE to drop the packet.
|
||||
//
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
BOOLEAN
|
||||
(QUIC_API * QUIC_TEST_DATAPATH_SEND_HOOK)(
|
||||
_Inout_ QUIC_ADDR* RemoteAddress,
|
||||
_Inout_opt_ QUIC_ADDR* LocalAddress,
|
||||
_Inout_ struct QUIC_DATAPATH_SEND_CONTEXT* SendContext
|
||||
);
|
||||
|
||||
typedef struct QUIC_TEST_DATAPATH_HOOKS {
|
||||
QUIC_TEST_DATAPATH_RECEIVE_HOOK Receive;
|
||||
QUIC_TEST_DATAPATH_SEND_HOOK Send;
|
||||
} QUIC_TEST_DATAPATH_HOOKS;
|
||||
|
||||
#define QUIC_PARAM_GLOBAL_ENCRYPTION 0x80000001 // uint8_t (BOOLEAN)
|
||||
#define QUIC_PARAM_GLOBAL_TEST_DATAPATH_HOOKS 0x80000002 // QUIC_TEST_DATAPATH_HOOKS*
|
||||
|
||||
//
|
||||
// The different private parameters for QUIC_PARAM_LEVEL_SESSION.
|
||||
|
|
|
@ -72,7 +72,8 @@ QuicTestConnect(
|
|||
_In_ bool MultipleALPNs,
|
||||
_In_ bool AsyncSecConfig,
|
||||
_In_ bool MultiPacketClientInitial,
|
||||
_In_ bool SessionResumption
|
||||
_In_ bool SessionResumption,
|
||||
_In_ uint8_t RandomLossPercentage // 0 to 100
|
||||
);
|
||||
|
||||
void
|
||||
|
@ -355,6 +356,7 @@ typedef struct {
|
|||
uint8_t AsyncSecConfig;
|
||||
uint8_t MultiPacketClientInitial;
|
||||
uint8_t SessionResumption;
|
||||
uint8_t RandomLossPercentage;
|
||||
} QUIC_RUN_CONNECT_PARAMS;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
|
|
@ -341,7 +341,8 @@ TEST_P(WithHandshakeArgs1, Connect) {
|
|||
(uint8_t)GetParam().MultipleALPNs,
|
||||
0, // AsyncSecConfig
|
||||
(uint8_t)GetParam().MultiPacketClientInitial,
|
||||
(uint8_t)GetParam().SessionResumption
|
||||
(uint8_t)GetParam().SessionResumption,
|
||||
0 // RandomLossPercentage
|
||||
};
|
||||
ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_CONNECT, Params));
|
||||
} else {
|
||||
|
@ -354,7 +355,8 @@ TEST_P(WithHandshakeArgs1, Connect) {
|
|||
GetParam().MultipleALPNs,
|
||||
false, // AsyncSecConfig
|
||||
GetParam().MultiPacketClientInitial,
|
||||
GetParam().SessionResumption);
|
||||
GetParam().SessionResumption,
|
||||
0); // RandomLossPercentage
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,7 +371,9 @@ TEST_P(WithHandshakeArgs2, OldVersion) {
|
|||
0, // ChangeMaxStreamID
|
||||
0, // MultipleALPNs
|
||||
0, // AsyncSecConfig
|
||||
0 // SessionResumption
|
||||
0, // MultiPacketClientInitial
|
||||
0, // SessionResumption
|
||||
0 // RandomLossPercentage
|
||||
};
|
||||
ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_CONNECT, Params));
|
||||
} else {
|
||||
|
@ -382,7 +386,8 @@ TEST_P(WithHandshakeArgs2, OldVersion) {
|
|||
false, // MultipleALPNs
|
||||
false, // AsyncSecConfig
|
||||
false, // MultiPacketClientInitial
|
||||
false); // SessionResumption
|
||||
false, // SessionResumption
|
||||
0); // RandomLossPercentage
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,7 +413,9 @@ TEST_P(WithFamilyArgs, Rebind) {
|
|||
0, // ChangeMaxStreamID
|
||||
0, // MultipleALPNs
|
||||
0, // AsyncSecConfig
|
||||
0 // SessionResumption
|
||||
0, // MultiPacketClientInitial
|
||||
0, // SessionResumption
|
||||
0 // RandomLossPercentage
|
||||
};
|
||||
ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_CONNECT, Params));*/
|
||||
} else {
|
||||
|
@ -421,7 +428,8 @@ TEST_P(WithFamilyArgs, Rebind) {
|
|||
false, // MultipleALPNs
|
||||
false, // AsyncSecConfig
|
||||
false, // MultiPacketClientInitial
|
||||
false); // SessionResumption
|
||||
false, // SessionResumption
|
||||
0); // RandomLossPercentage
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,7 +444,9 @@ TEST_P(WithFamilyArgs, ChangeMaxStreamIDs) {
|
|||
1, // ChangeMaxStreamID
|
||||
0, // MultipleALPNs
|
||||
0, // AsyncSecConfig
|
||||
0 // SessionResumption
|
||||
0, // MultiPacketClientInitial
|
||||
0, // SessionResumption
|
||||
0 // RandomLossPercentage
|
||||
};
|
||||
ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_CONNECT, Params));
|
||||
} else {
|
||||
|
@ -449,11 +459,12 @@ TEST_P(WithFamilyArgs, ChangeMaxStreamIDs) {
|
|||
false, // MultipleALPNs
|
||||
false, // AsyncSecConfig
|
||||
false, // MultiPacketClientInitial
|
||||
false); // SessionResumption
|
||||
false, // SessionResumption
|
||||
0); // RandomLossPercentage
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(WithHandshakeArgs1, AsyncSecurityConfig) {
|
||||
TEST_P(WithHandshakeArgs3, AsyncSecurityConfig) {
|
||||
TestLoggerT<ParamType> Logger("QuicTestConnect-AsyncSecurityConfig", GetParam());
|
||||
if (TestingKernelMode) {
|
||||
QUIC_RUN_CONNECT_PARAMS Params = {
|
||||
|
@ -464,7 +475,9 @@ TEST_P(WithHandshakeArgs1, AsyncSecurityConfig) {
|
|||
0, // ChangeMaxStreamID
|
||||
(uint8_t)GetParam().MultipleALPNs,
|
||||
1, // AsyncSecConfig
|
||||
0 // SessionResumption
|
||||
0, // MultiPacketClientInitial
|
||||
0, // SessionResumption
|
||||
0 // RandomLossPercentage
|
||||
};
|
||||
ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_CONNECT, Params));
|
||||
} else {
|
||||
|
@ -477,7 +490,39 @@ TEST_P(WithHandshakeArgs1, AsyncSecurityConfig) {
|
|||
GetParam().MultipleALPNs,
|
||||
true, // AsyncSecConfig
|
||||
false, // MultiPacketClientInitial
|
||||
false); // SessionResumption
|
||||
false, // SessionResumption
|
||||
0); // RandomLossPercentage
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(WithHandshakeArgs4, RandomLoss) {
|
||||
TestLoggerT<ParamType> Logger("QuicTestConnect-RandomLoss", GetParam());
|
||||
if (TestingKernelMode) {
|
||||
QUIC_RUN_CONNECT_PARAMS Params = {
|
||||
GetParam().Family,
|
||||
(uint8_t)GetParam().ServerStatelessRetry,
|
||||
0, // ClientUsesOldVersion
|
||||
0, // ClientRebind
|
||||
0, // ChangeMaxStreamID
|
||||
0, // MultipleALPNs
|
||||
0, // AsyncSecConfig
|
||||
(uint8_t)GetParam().MultiPacketClientInitial,
|
||||
(uint8_t)GetParam().SessionResumption,
|
||||
GetParam().RandomLossPercentage
|
||||
};
|
||||
ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_CONNECT, Params));
|
||||
} else {
|
||||
QuicTestConnect(
|
||||
GetParam().Family,
|
||||
GetParam().ServerStatelessRetry,
|
||||
false, // ClientUsesOldVersion
|
||||
false, // ClientRebind
|
||||
false, // ChangeMaxStreamID
|
||||
false, // MultipleALPNs,
|
||||
false, // AsyncSecConfig
|
||||
GetParam().MultiPacketClientInitial,
|
||||
GetParam().SessionResumption,
|
||||
GetParam().RandomLossPercentage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -893,6 +938,16 @@ INSTANTIATE_TEST_CASE_P(
|
|||
WithHandshakeArgs2,
|
||||
testing::ValuesIn(HandshakeArgs2::Generate()));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Handshake,
|
||||
WithHandshakeArgs3,
|
||||
testing::ValuesIn(HandshakeArgs3::Generate()));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Handshake,
|
||||
WithHandshakeArgs4,
|
||||
testing::ValuesIn(HandshakeArgs4::Generate()));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
AppData,
|
||||
WithSendArgs1,
|
||||
|
|
|
@ -94,6 +94,66 @@ class WithHandshakeArgs2 : public testing::Test,
|
|||
public testing::WithParamInterface<HandshakeArgs2> {
|
||||
};
|
||||
|
||||
struct HandshakeArgs3 {
|
||||
int Family;
|
||||
bool ServerStatelessRetry;
|
||||
bool MultipleALPNs;
|
||||
static ::std::vector<HandshakeArgs3> Generate() {
|
||||
::std::vector<HandshakeArgs3> list;
|
||||
for (int Family : { 4, 6})
|
||||
for (bool ServerStatelessRetry : { false, true })
|
||||
for (bool MultipleALPNs : { false, true })
|
||||
list.push_back({ Family, ServerStatelessRetry, MultipleALPNs });
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& o, const HandshakeArgs3& args) {
|
||||
return o <<
|
||||
(args.Family == 4 ? "v4" : "v6") << "/" <<
|
||||
(args.ServerStatelessRetry ? "Retry" : "NoRetry") << "/" <<
|
||||
(args.MultipleALPNs ? "MultipleALPNs" : "SingleALPN");
|
||||
}
|
||||
|
||||
class WithHandshakeArgs3 : public testing::Test,
|
||||
public testing::WithParamInterface<HandshakeArgs3> {
|
||||
};
|
||||
|
||||
struct HandshakeArgs4 {
|
||||
int Family;
|
||||
bool ServerStatelessRetry;
|
||||
bool MultiPacketClientInitial;
|
||||
bool SessionResumption;
|
||||
uint8_t RandomLossPercentage;
|
||||
static ::std::vector<HandshakeArgs4> Generate() {
|
||||
::std::vector<HandshakeArgs4> list;
|
||||
for (int Family : { 4, 6})
|
||||
for (bool ServerStatelessRetry : { false, true })
|
||||
for (bool MultiPacketClientInitial : { false, true })
|
||||
#ifdef QUIC_DISABLE_RESUMPTION
|
||||
for (bool SessionResumption : { false })
|
||||
#else
|
||||
for (bool SessionResumption : { false, true })
|
||||
#endif
|
||||
for (uint8_t RandomLossPercentage : { 1, 5, 10 })
|
||||
list.push_back({ Family, ServerStatelessRetry, MultiPacketClientInitial, SessionResumption, RandomLossPercentage });
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& o, const HandshakeArgs4& args) {
|
||||
return o <<
|
||||
(args.Family == 4 ? "v4" : "v6") << "/" <<
|
||||
(args.ServerStatelessRetry ? "Retry" : "NoRetry") << "/" <<
|
||||
(args.MultiPacketClientInitial ? "MultipleInitials" : "SingleInitial") << "/" <<
|
||||
(args.SessionResumption ? "Resume" : "NoResume") << "/" <<
|
||||
(uint32_t)args.RandomLossPercentage << "% loss";
|
||||
}
|
||||
|
||||
class WithHandshakeArgs4 : public testing::Test,
|
||||
public testing::WithParamInterface<HandshakeArgs4> {
|
||||
};
|
||||
|
||||
struct SendArgs1 {
|
||||
int Family;
|
||||
uint64_t Length;
|
||||
|
|
|
@ -750,7 +750,8 @@ QuicTestCtlEvtIoDeviceControl(
|
|||
Params->Params1.MultipleALPNs != 0,
|
||||
Params->Params1.AsyncSecConfig != 0,
|
||||
Params->Params1.MultiPacketClientInitial != 0,
|
||||
Params->Params1.SessionResumption != 0
|
||||
Params->Params1.SessionResumption != 0,
|
||||
Params->Params1.RandomLossPercentage
|
||||
));
|
||||
break;
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ Abstract:
|
|||
--*/
|
||||
|
||||
#include "precomp.h"
|
||||
#include "quic_trace.h"
|
||||
|
||||
//#define QUIC_TEST_DISABLE_DNS 1
|
||||
|
||||
|
@ -322,6 +321,8 @@ ListenerAcceptConnection(
|
|||
TEST_FAILURE("Failed to accept new TestConnection.");
|
||||
delete NewConnection;
|
||||
MsQuic->ConnectionClose(ConnectionHandle);
|
||||
} else {
|
||||
NewConnection->SetHasRandomLoss(Listener->GetHasRandomLoss());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -335,6 +336,8 @@ ListenerAcceptConnection(
|
|||
delete *AcceptContext->NewConnection;
|
||||
*AcceptContext->NewConnection = nullptr;
|
||||
MsQuic->ConnectionClose(ConnectionHandle);
|
||||
} else {
|
||||
(*AcceptContext->NewConnection)->SetHasRandomLoss(Listener->GetHasRandomLoss());
|
||||
}
|
||||
QuicEventSet(AcceptContext->NewConnectionReady);
|
||||
}
|
||||
|
@ -388,6 +391,76 @@ struct PrivateTransportHelper : QUIC_PRIVATE_TRANSPORT_PARAMETER
|
|||
}
|
||||
};
|
||||
|
||||
struct RandomLossHelper
|
||||
{
|
||||
static uint8_t LossPercentage;
|
||||
static QUIC_TEST_DATAPATH_HOOKS DataPathFuncTable;
|
||||
RandomLossHelper(uint8_t _LossPercentage) {
|
||||
LossPercentage = _LossPercentage;
|
||||
if (LossPercentage != 0) {
|
||||
QUIC_TEST_DATAPATH_HOOKS* Value = &DataPathFuncTable;
|
||||
TEST_QUIC_SUCCEEDED(
|
||||
MsQuic->SetParam(
|
||||
nullptr,
|
||||
QUIC_PARAM_LEVEL_GLOBAL,
|
||||
QUIC_PARAM_GLOBAL_TEST_DATAPATH_HOOKS,
|
||||
sizeof(Value),
|
||||
&Value));
|
||||
}
|
||||
}
|
||||
~RandomLossHelper() {
|
||||
if (LossPercentage != 0) {
|
||||
QUIC_TEST_DATAPATH_HOOKS* Value = nullptr;
|
||||
uint32_t TryCount = 0;
|
||||
while (TryCount++ < 10) {
|
||||
if (QUIC_SUCCEEDED(
|
||||
MsQuic->SetParam(
|
||||
nullptr,
|
||||
QUIC_PARAM_LEVEL_GLOBAL,
|
||||
QUIC_PARAM_GLOBAL_TEST_DATAPATH_HOOKS,
|
||||
sizeof(Value),
|
||||
&Value))) {
|
||||
break;
|
||||
}
|
||||
QuicSleep(100); // Let the current datapath queue drain.
|
||||
}
|
||||
if (TryCount == 10) {
|
||||
TEST_FAILURE("Failed to disable test datapath hook");
|
||||
}
|
||||
}
|
||||
}
|
||||
static
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
QUIC_API
|
||||
ReceiveCallback(
|
||||
_Inout_ struct QUIC_RECV_DATAGRAM* /* Datagram */
|
||||
)
|
||||
{
|
||||
uint8_t RandomValue;
|
||||
QuicRandom(sizeof(RandomValue), &RandomValue);
|
||||
return (RandomValue % 100) < LossPercentage;
|
||||
}
|
||||
static
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
BOOLEAN
|
||||
QUIC_API
|
||||
SendCallback(
|
||||
_Inout_ QUIC_ADDR* /* RemoteAddress */,
|
||||
_Inout_opt_ QUIC_ADDR* /* LocalAddress */,
|
||||
_Inout_ struct QUIC_DATAPATH_SEND_CONTEXT* /* SendContext */
|
||||
)
|
||||
{
|
||||
return FALSE; // Don't drop
|
||||
}
|
||||
};
|
||||
|
||||
uint8_t RandomLossHelper::LossPercentage = 0;
|
||||
QUIC_TEST_DATAPATH_HOOKS RandomLossHelper::DataPathFuncTable = {
|
||||
RandomLossHelper::ReceiveCallback,
|
||||
RandomLossHelper::SendCallback
|
||||
};
|
||||
|
||||
void
|
||||
QuicTestConnect(
|
||||
_In_ int Family,
|
||||
|
@ -398,18 +471,22 @@ QuicTestConnect(
|
|||
_In_ bool MultipleALPNs,
|
||||
_In_ bool AsyncSecConfig,
|
||||
_In_ bool MultiPacketClientInitial,
|
||||
_In_ bool SessionResumption
|
||||
_In_ bool SessionResumption,
|
||||
_In_ uint8_t RandomLossPercentage
|
||||
)
|
||||
{
|
||||
MsQuicSession Session;
|
||||
TEST_TRUE(Session.IsValid());
|
||||
TEST_QUIC_SUCCEEDED(Session.SetPeerBidiStreamCount(4));
|
||||
TEST_QUIC_SUCCEEDED(Session.SetIdleTimeout(10000));
|
||||
MsQuicSession Session2("MsQuicTest2", "MsQuicTest");
|
||||
TEST_TRUE(Session2.IsValid());
|
||||
TEST_QUIC_SUCCEEDED(Session2.SetPeerBidiStreamCount(4));
|
||||
TEST_QUIC_SUCCEEDED(Session2.SetIdleTimeout(10000));
|
||||
|
||||
StatelessRetryHelper RetryHelper(ServerStatelessRetry);
|
||||
PrivateTransportHelper TpHelper(MultiPacketClientInitial);
|
||||
RandomLossHelper LossHelper(RandomLossPercentage);
|
||||
|
||||
{
|
||||
TestListener Listener(
|
||||
|
@ -417,6 +494,7 @@ QuicTestConnect(
|
|||
ListenerAcceptConnection,
|
||||
AsyncSecConfig);
|
||||
TEST_TRUE(Listener.IsValid());
|
||||
Listener.SetHasRandomLoss(RandomLossPercentage != 0);
|
||||
|
||||
QUIC_ADDRESS_FAMILY QuicAddrFamily = (Family == 4) ? AF_INET : AF_INET6;
|
||||
QuicAddr ServerLocalAddr(QuicAddrFamily);
|
||||
|
@ -431,6 +509,7 @@ QuicTestConnect(
|
|||
ConnectionDoNothingCallback,
|
||||
false);
|
||||
TEST_TRUE(Client.IsValid());
|
||||
Client.SetHasRandomLoss(RandomLossPercentage != 0);
|
||||
#if QUIC_TEST_DISABLE_DNS
|
||||
QuicAddr RemoteAddr(QuicAddrFamily, true);
|
||||
TEST_QUIC_SUCCEEDED(Client.SetRemoteAddr(RemoteAddr));
|
||||
|
@ -465,6 +544,7 @@ QuicTestConnect(
|
|||
ConnectionDoNothingCallback,
|
||||
false);
|
||||
TEST_TRUE(Client.IsValid());
|
||||
Client.SetHasRandomLoss(RandomLossPercentage != 0);
|
||||
|
||||
if (ClientUsesOldVersion) {
|
||||
TEST_QUIC_SUCCEEDED(
|
||||
|
@ -573,10 +653,10 @@ QuicTestConnect(
|
|||
TEST_FALSE(Client.GetTransportClosed());
|
||||
}
|
||||
|
||||
#if !QUIC_SEND_FAKE_LOSS
|
||||
if (RandomLossPercentage == 0) {
|
||||
TEST_TRUE(Server->GetPeerClosed());
|
||||
TEST_EQUAL(Server->GetPeerCloseErrorCode(), QUIC_TEST_NO_ERROR);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ Abstract:
|
|||
--*/
|
||||
|
||||
#include <quic_platform.h>
|
||||
#include <quic_datapath.h>
|
||||
#include <MsQuicTests.h>
|
||||
|
||||
const uint32_t TestWaitTimeout = 1000;
|
||||
|
|
|
@ -123,8 +123,8 @@ TestConnection::NewStream(
|
|||
bool
|
||||
TestConnection::WaitForConnectionComplete()
|
||||
{
|
||||
if (!QuicEventWaitWithTimeout(EventConnectionComplete, TestWaitTimeout)) {
|
||||
TEST_FAILURE("WaitForConnectionComplete timed out after %u ms.", TestWaitTimeout);
|
||||
if (!QuicEventWaitWithTimeout(EventConnectionComplete, GetWaitTimeout())) {
|
||||
TEST_FAILURE("WaitForConnectionComplete timed out after %u ms.", GetWaitTimeout());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -151,8 +151,8 @@ bool
|
|||
TestConnection::WaitForShutdownComplete()
|
||||
{
|
||||
if (IsStarted) {
|
||||
if (!QuicEventWaitWithTimeout(EventShutdownComplete, TestWaitTimeout)) {
|
||||
TEST_FAILURE("WaitForShutdownComplete timed out after %u ms.", TestWaitTimeout);
|
||||
if (!QuicEventWaitWithTimeout(EventShutdownComplete, GetWaitTimeout())) {
|
||||
TEST_FAILURE("WaitForShutdownComplete timed out after %u ms.", GetWaitTimeout());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -162,8 +162,8 @@ TestConnection::WaitForShutdownComplete()
|
|||
bool
|
||||
TestConnection::WaitForPeerClose()
|
||||
{
|
||||
if (!QuicEventWaitWithTimeout(EventPeerClosed, TestWaitTimeout)) {
|
||||
TEST_FAILURE("WaitForPeerClose timed out after %u ms.", TestWaitTimeout);
|
||||
if (!QuicEventWaitWithTimeout(EventPeerClosed, GetWaitTimeout())) {
|
||||
TEST_FAILURE("WaitForPeerClose timed out after %u ms.", GetWaitTimeout());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -724,8 +724,20 @@ TestConnection::HandleConnectionEvent(
|
|||
TransportClosed = true;
|
||||
TransportCloseStatus = Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status;
|
||||
if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status != ExpectedTransportCloseStatus) {
|
||||
bool IsTimeoutStatus =
|
||||
Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_TIMEOUT ||
|
||||
Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_IDLE;
|
||||
if (IsTimeoutStatus && HasRandomLoss) {
|
||||
//
|
||||
// Ignoring unexpected status because of random loss
|
||||
//
|
||||
QuicTraceLogInfo(
|
||||
TestIgnoreConnectionTimeout,
|
||||
"[test] Ignoring timeout unexpected status because of random loss");
|
||||
} else {
|
||||
TEST_FAILURE("Unexpected transport Close Error, %u", Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status);
|
||||
}
|
||||
}
|
||||
QuicEventSet(EventConnectionComplete);
|
||||
break;
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ class TestConnection
|
|||
bool ShutdownTimedOut : 1;
|
||||
bool AutoDelete : 1;
|
||||
bool UseSendBuffer : 1;
|
||||
bool HasRandomLoss : 1;
|
||||
|
||||
bool ExpectedResumed : 1;
|
||||
QUIC_STATUS ExpectedTransportCloseStatus;
|
||||
|
@ -123,6 +124,14 @@ public:
|
|||
_In_ QUIC_STREAM_OPEN_FLAGS Flags
|
||||
);
|
||||
|
||||
uint32_t GetWaitTimeout() const {
|
||||
uint32_t WaitTime = TestWaitTimeout;
|
||||
if (HasRandomLoss) {
|
||||
WaitTime *= 10; // TODO - Enough?
|
||||
}
|
||||
return WaitTime;
|
||||
}
|
||||
|
||||
bool WaitForConnectionComplete();
|
||||
|
||||
bool WaitForZeroRttTicket();
|
||||
|
@ -155,6 +164,9 @@ public:
|
|||
bool GetExpectedResumed() const { return ExpectedResumed; };
|
||||
void SetExpectedResumed(bool Value) { ExpectedResumed = Value; }
|
||||
|
||||
bool GetHasRandomLoss() const { return HasRandomLoss; }
|
||||
void SetHasRandomLoss(bool Value) { HasRandomLoss = Value; }
|
||||
|
||||
QUIC_STATUS GetTransportCloseStatus() const { return TransportCloseStatus; };
|
||||
QUIC_UINT62 GetPeerCloseErrorCode() const { return PeerCloseErrorCode; };
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ class TestListener
|
|||
bool FilterConnections : 1;
|
||||
bool SetSecConfig : 1;
|
||||
bool UseSendBuffer : 1;
|
||||
bool HasRandomLoss : 1;
|
||||
|
||||
NEW_CONNECTION_CALLBACK_HANDLER NewConnectionCallback;
|
||||
|
||||
|
@ -93,4 +94,7 @@ public:
|
|||
|
||||
QUIC_STATUS GetLocalAddr(_Out_ QuicAddr &localAddr);
|
||||
QUIC_STATUS GetStatistics(_Out_ QUIC_LISTENER_STATISTICS &stats);
|
||||
|
||||
bool GetHasRandomLoss() const { return HasRandomLoss; }
|
||||
void SetHasRandomLoss(bool Value) { HasRandomLoss = Value; }
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <msquic.h>
|
||||
#include <msquicp.h>
|
||||
#include <quic_versions.h>
|
||||
#include <quic_trace.h>
|
||||
|
||||
#ifdef _KERNEL_MODE
|
||||
#ifdef PAGEDX
|
||||
|
|
Загрузка…
Ссылка в новой задаче