Add Test Interface for Datapath Filtering (#361)

This commit is contained in:
Nick Banks 2020-05-07 14:01:56 -07:00 коммит произвёл GitHub
Родитель bb9439da88
Коммит bb010bc13b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 446 добавлений и 102 удалений

Просмотреть файл

@ -78,7 +78,7 @@ QuicBindingInitialize(
Binding->RandomReservedVersion =
(Binding->RandomReservedVersion & ~QUIC_VERSION_RESERVED_MASK) |
QUIC_VERSION_RESERVED;
QuicRandom(sizeof(HashSalt), HashSalt);
Status =
QuicHashCreate(
@ -383,7 +383,7 @@ QuicBindingGetListener(
for (QUIC_LIST_ENTRY* Link = Binding->Listeners.Flink;
Link != &Binding->Listeners;
Link = Link->Flink) {
QUIC_LISTENER* ExistingListener =
QUIC_CONTAINING_RECORD(Link, QUIC_LISTENER, Link);
const QUIC_ADDR* ExistingAddr = &ExistingListener->LocalAddress;
@ -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.
//
*PacketKeyType = Connection->Crypto.TlsState.WriteKey;
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
TEST_TRUE(Server->GetPeerClosed());
TEST_EQUAL(Server->GetPeerCloseErrorCode(), QUIC_TEST_NO_ERROR);
#endif
if (RandomLossPercentage == 0) {
TEST_TRUE(Server->GetPeerClosed());
TEST_EQUAL(Server->GetPeerCloseErrorCode(), QUIC_TEST_NO_ERROR);
}
}
}
}

Просмотреть файл

@ -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,7 +724,19 @@ TestConnection::HandleConnectionEvent(
TransportClosed = true;
TransportCloseStatus = Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status;
if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status != ExpectedTransportCloseStatus) {
TEST_FAILURE("Unexpected transport Close Error, %u", Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status);
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