diff --git a/scripts/update-sidecar.ps1 b/scripts/update-sidecar.ps1 index d756e2dbd0..6a164a9ad5 100644 --- a/scripts/update-sidecar.ps1 +++ b/scripts/update-sidecar.ps1 @@ -1,18 +1,10 @@ <# .SYNOPSIS -This updates/regenerates the CLOG sidecar file. - -.PARAMETER Clean - Deletes the old sidecar file first. +This regenerates the CLOG sidecar file. #> -param ( - [Parameter(Mandatory = $false)] - [switch]$Clean = $false -) - Set-StrictMode -Version 'Latest' $PSDefaultParameterValues['*:ErrorAction'] = 'Stop' @@ -35,9 +27,7 @@ $ConfigFile = Join-Path $SrcDir "manifest" "msquic.clog_config" $OutputDir = Join-Path $RootDir "build" "tmp" New-Item -Path $OutputDir -ItemType Directory -Force | Out-Null -if ($Clean) { - Remove-Item $Sidecar -Force -ErrorAction Ignore | Out-Null -} +Remove-Item $Sidecar -Force -ErrorAction Ignore | Out-Null foreach ($File in $Files) { clog -p windows --scopePrefix "QUIC" -s $Sidecar -c $ConfigFile -i $File --outputDirectory "$OutputDir" diff --git a/src/core/crypto.c b/src/core/crypto.c index 3486a01c2f..00b319a6f4 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -1614,7 +1614,6 @@ QuicCryptoCustomCertValidationComplete( _In_ BOOLEAN Result ) { - CXPLAT_TEL_ASSERT(Crypto->CertValidationPending); if (!Crypto->CertValidationPending) { return; } diff --git a/src/core/send.c b/src/core/send.c index d19c4a39b4..4447f14feb 100644 --- a/src/core/send.c +++ b/src/core/send.c @@ -150,7 +150,19 @@ QuicSendQueueFlushForStream( // Not previously queued, so add the stream to the end of the queue. // CXPLAT_DBG_ASSERT(Stream->SendLink.Flink == NULL); - CxPlatListInsertTail(&Send->SendStreams, &Stream->SendLink); + CXPLAT_LIST_ENTRY* Entry = Send->SendStreams.Blink; + while (Entry != &Send->SendStreams) { + // + // Search back to front for the right place (based on priority) to + // insert the stream. + // + if (Stream->SendPriority <= + CXPLAT_CONTAINING_RECORD(Entry, QUIC_STREAM, SendLink)->SendPriority) { + break; + } + Entry = Entry->Blink; + } + CxPlatListInsertHead(Entry, &Stream->SendLink); // Insert after current Entry QuicStreamAddRef(Stream, QUIC_STREAM_REF_SEND); } @@ -172,6 +184,31 @@ QuicSendQueueFlushForStream( } } +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicSendUpdateStreamPriority( + _In_ QUIC_SEND* Send, + _In_ QUIC_STREAM* Stream + ) +{ + CXPLAT_DBG_ASSERT(Stream->SendLink.Flink != NULL); + CxPlatListEntryRemove(&Stream->SendLink); + + CXPLAT_LIST_ENTRY* Entry = Send->SendStreams.Blink; + while (Entry != &Send->SendStreams) { + // + // Search back to front for the right place (based on priority) to + // insert the stream. + // + if (Stream->SendPriority <= + CXPLAT_CONTAINING_RECORD(Entry, QUIC_STREAM, SendLink)->SendPriority) { + break; + } + Entry = Entry->Blink; + } + CxPlatListInsertHead(Entry, &Stream->SendLink); // Insert after current Entry +} + #if DEBUG _IRQL_requires_max_(DISPATCH_LEVEL) void @@ -888,10 +925,23 @@ QuicSendGetNextStream( if (Connection->State.UseRoundRobinStreamScheduling) { // - // Move the stream to the end of the queue. + // Move the stream after any streams of the same priority. Start + // with the "next" entry in the list and keep going until the + // next entry's priority is less. Then move the stream before + // that entry. // - CxPlatListEntryRemove(&Stream->SendLink); - CxPlatListInsertTail(&Send->SendStreams, &Stream->SendLink); + CXPLAT_LIST_ENTRY* LastEntry = Stream->SendLink.Flink; + while (Stream->SendLink.Flink != &Send->SendStreams) { + if (Stream->SendPriority > + CXPLAT_CONTAINING_RECORD(LastEntry, QUIC_STREAM, SendLink)->SendPriority) { + break; + } + LastEntry = LastEntry->Flink; + } + if (LastEntry->Blink != &Stream->SendLink) { + CxPlatListEntryRemove(&Stream->SendLink); + CxPlatListInsertTail(LastEntry, &Stream->SendLink); + } *PacketCount = QUIC_STREAM_SEND_BATCH_COUNT; diff --git a/src/core/send.h b/src/core/send.h index 6797f9ee72..f90bf13940 100644 --- a/src/core/send.h +++ b/src/core/send.h @@ -312,6 +312,16 @@ QuicSendQueueFlushForStream( _In_ BOOLEAN DelaySend ); +// +// Updates the stream's order in response to a priority change. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicSendUpdateStreamPriority( + _In_ QUIC_SEND* Send, + _In_ QUIC_STREAM* Stream + ); + // // Tries to drain all queued data that needs to be sent. Returns TRUE if all the // data was drained. diff --git a/src/core/stream.c b/src/core/stream.c index dbab510606..7d5d89d7a7 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -57,6 +57,7 @@ QuicStreamInitialize( Stream->RecvMaxLength = UINT64_MAX; Stream->RefCount = 1; Stream->SendRequestsTail = &Stream->SendRequests; + Stream->SendPriority = QUIC_STREAM_PRIORITY_DEFAULT; CxPlatDispatchLockInitialize(&Stream->ApiSendRequestLock); CxPlatRefInitialize(&Stream->RefCount); QuicRangeInitialize( @@ -538,11 +539,49 @@ QuicStreamParamSet( const void* Buffer ) { - UNREFERENCED_PARAMETER(Stream); - UNREFERENCED_PARAMETER(Param); - UNREFERENCED_PARAMETER(BufferLength); - UNREFERENCED_PARAMETER(Buffer); - return QUIC_STATUS_INVALID_PARAMETER; + QUIC_STATUS Status; + + switch (Param) { + case QUIC_PARAM_STREAM_ID: + case QUIC_PARAM_STREAM_0RTT_LENGTH: + case QUIC_PARAM_STREAM_IDEAL_SEND_BUFFER_SIZE: + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + + case QUIC_PARAM_STREAM_PRIORITY: { + + if (BufferLength != sizeof(Stream->SendPriority)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + if (Stream->SendPriority != *(uint16_t*)Buffer) { + Stream->SendPriority = *(uint16_t*)Buffer; + + QuicTraceLogStreamInfo( + UpdatePriority, + Stream, + "New send priority = %hu", + Stream->SendPriority); + + if (Stream->Flags.Started && Stream->SendFlags != 0) { + // + // Update the stream's place in the send queue if necessary. + // + QuicSendUpdateStreamPriority(&Stream->Connection->Send, Stream); + } + } + + Status = QUIC_STATUS_SUCCESS; + break; + } + + default: + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + return Status; } QUIC_STATUS @@ -556,8 +595,7 @@ QuicStreamParamGet( { QUIC_STATUS Status; - switch (Param) - { + switch (Param) { case QUIC_PARAM_STREAM_ID: if (*BufferLength < sizeof(Stream->ID)) { @@ -627,6 +665,25 @@ QuicStreamParamGet( Status = QUIC_STATUS_SUCCESS; break; + case QUIC_PARAM_STREAM_PRIORITY: + + if (*BufferLength < sizeof(Stream->SendPriority)) { + *BufferLength = sizeof(Stream->SendPriority); + Status = QUIC_STATUS_BUFFER_TOO_SMALL; + break; + } + + if (Buffer == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + *BufferLength = sizeof(Stream->SendPriority); + *(uint16_t*)Buffer = Stream->SendPriority; + + Status = QUIC_STATUS_SUCCESS; + break; + default: Status = QUIC_STATUS_INVALID_PARAMETER; break; diff --git a/src/core/stream.h b/src/core/stream.h index a9db3fcb0b..71249c8e62 100644 --- a/src/core/stream.h +++ b/src/core/stream.h @@ -51,6 +51,8 @@ typedef struct QUIC_CONNECTION QUIC_CONNECTION; QUIC_SEND_FLAG_BUFFERED \ ) +#define QUIC_STREAM_PRIORITY_DEFAULT 0x7FFF // Medium priority by default + // // Tracks the data queued up for sending by an application. // @@ -342,6 +344,12 @@ typedef struct QUIC_STREAM { // QUIC_RANGE SparseAckRanges; + // + // The relative priority between the different streams that determines the + // order that queued data will be sent out. + // + uint16_t SendPriority; + // // Recv State // diff --git a/src/inc/msquic.h b/src/inc/msquic.h index d4d2d7b7fc..06c00a42ee 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -667,6 +667,7 @@ typedef struct QUIC_SCHANNEL_CONTEXT_ATTRIBUTE_W { #define QUIC_PARAM_STREAM_ID 0x1C000000 // QUIC_UINT62 #define QUIC_PARAM_STREAM_0RTT_LENGTH 0x1C000001 // uint64_t #define QUIC_PARAM_STREAM_IDEAL_SEND_BUFFER_SIZE 0x1C000002 // uint64_t - bytes +#define QUIC_PARAM_STREAM_PRIORITY 0x1C000003 // uint16_t - 0 (low) to 0xFFFF (high) - 0x7FFF (default) typedef _IRQL_requires_max_(PASSIVE_LEVEL) diff --git a/src/inc/msquic.hpp b/src/inc/msquic.hpp index 6921442f37..b7303405b1 100644 --- a/src/inc/msquic.hpp +++ b/src/inc/msquic.hpp @@ -1105,6 +1105,47 @@ struct MsQuicStream { return MsQuic->StreamReceiveSetEnabled(Handle, IsEnabled ? TRUE : FALSE); } + QUIC_STATUS + GetID(_Out_ QUIC_UINT62* ID) const noexcept { + uint32_t Size = sizeof(*ID); + return + MsQuic->GetParam( + Handle, + QUIC_PARAM_LEVEL_STREAM, + QUIC_PARAM_STREAM_ID, + &Size, + ID); + } + + QUIC_UINT62 ID() const noexcept { + QUIC_UINT62 ID; + GetID(&ID); + return ID; + } + + QUIC_STATUS + SetPriority(_In_ uint16_t Priority) noexcept { + return + MsQuic->SetParam( + Handle, + QUIC_PARAM_LEVEL_STREAM, + QUIC_PARAM_STREAM_PRIORITY, + sizeof(Priority), + &Priority); + } + + QUIC_STATUS + GetPriority(_Out_ uint16_t* Priority) const noexcept { + uint32_t Size = sizeof(*Priority); + return + MsQuic->GetParam( + Handle, + QUIC_PARAM_LEVEL_STREAM, + QUIC_PARAM_STREAM_PRIORITY, + &Size, + Priority); + } + QUIC_STATUS GetInitStatus() const noexcept { return InitStatus; } bool IsValid() const { return QUIC_SUCCEEDED(InitStatus); } MsQuicStream(MsQuicStream& other) = delete; diff --git a/src/manifest/clog.sidecar b/src/manifest/clog.sidecar index 342e582de5..cbd8684674 100644 --- a/src/manifest/clog.sidecar +++ b/src/manifest/clog.sidecar @@ -6720,6 +6720,22 @@ ], "macroName": "QuicTraceLogStreamWarning" }, + "UpdatePriority": { + "ModuleProperites": {}, + "TraceString": "[strm][%p] New send priority = %hu", + "UniqueId": "UpdatePriority", + "splitArgs": [ + { + "DefinationEncoding": "p", + "MacroVariableName": "arg1" + }, + { + "DefinationEncoding": "hu", + "MacroVariableName": "arg3" + } + ], + "macroName": "QuicTraceLogStreamInfo" + }, "IndicateStartComplete": { "ModuleProperites": {}, "TraceString": "[strm][%p] Indicating QUIC_STREAM_EVENT_START_COMPLETE [Status=0x%x ID=%llu Accepted=%hhu]", @@ -12467,6 +12483,10 @@ "UniquenessHash": "21a2e517-42a5-1d18-885f-8b57b79a2fba", "TraceID": "EventSilentDiscard" }, + { + "UniquenessHash": "1b92f995-0f00-00a4-3898-3e5121f9f323", + "TraceID": "UpdatePriority" + }, { "UniquenessHash": "66dd140b-9fd3-eddc-e34c-cb81639e1aca", "TraceID": "IndicateStartComplete" diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index 1cacc9d466..cf13eaf85c 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -382,6 +382,10 @@ void QuicTestNthAllocFail( ); +void +QuicTestStreamPriority( + ); + // // QuicDrill tests // @@ -867,5 +871,9 @@ typedef struct { #define IOCTL_QUIC_RUN_VALIDATE_PARAM_API \ QUIC_CTL_CODE(71, METHOD_BUFFERED, FILE_WRITE_DATA) + // int - Family + +#define IOCTL_QUIC_RUN_STREAM_PRIORITY \ + QUIC_CTL_CODE(72, METHOD_BUFFERED, FILE_WRITE_DATA) -#define QUIC_MAX_IOCTL_FUNC_CODE 71 +#define QUIC_MAX_IOCTL_FUNC_CODE 72 diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index f2c6c74d18..0c4365dbc4 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -1404,6 +1404,15 @@ TEST(Misc, NthAllocFail) { } #endif +TEST(Misc, StreamPriority) { + TestLogger Logger("StreamPriority"); + if (TestingKernelMode) { + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_STREAM_PRIORITY)); + } else { + QuicTestStreamPriority(); + } +} + TEST(Drill, VarIntEncoder) { TestLogger Logger("QuicDrillTestVarIntEncoder"); if (TestingKernelMode) { diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index 77b2c0f678..c57e030c5f 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -441,7 +441,8 @@ size_t QUIC_IOCTL_BUFFER_SIZES[] = sizeof(QUIC_RUN_MTU_DISCOVERY_PARAMS), sizeof(INT32), sizeof(INT32), - 0 + 0, + 0, }; CXPLAT_STATIC_ASSERT( @@ -1078,6 +1079,10 @@ QuicTestCtlEvtIoDeviceControl( QuicTestCtlRun(QuicTestValidateParamApi()); break; + case IOCTL_QUIC_RUN_STREAM_PRIORITY: + QuicTestCtlRun(QuicTestStreamPriority()); + break; + default: Status = STATUS_NOT_IMPLEMENTED; break; diff --git a/src/test/lib/DataTest.cpp b/src/test/lib/DataTest.cpp index cbfd95828f..3be065bef7 100644 --- a/src/test/lib/DataTest.cpp +++ b/src/test/lib/DataTest.cpp @@ -2294,12 +2294,13 @@ QuicTestNthAllocFail( AllocFailScope Scope{}; for (uint32_t i = 100; i > 1; i--) { - TEST_QUIC_SUCCEEDED(MsQuic->SetParam( - nullptr, - QUIC_PARAM_LEVEL_GLOBAL, - QUIC_PARAM_GLOBAL_ALLOC_FAIL_CYCLE, - sizeof(i), - &i)); + TEST_QUIC_SUCCEEDED( + MsQuic->SetParam( + nullptr, + QUIC_PARAM_LEVEL_GLOBAL, + QUIC_PARAM_GLOBAL_ALLOC_FAIL_CYCLE, + sizeof(i), + &i)); CxPlatWatchdog Watchdog(2000); @@ -2334,3 +2335,83 @@ QuicTestNthAllocFail( RecvContext.ServerStreamShutdown.WaitTimeout(10); } } + +struct StreamPriorityTestContext { + QUIC_UINT62 ReceiveEvents[3]; + uint32_t CurrentReceiveCount {0}; + CxPlatEvent AllReceivesComplete; + + static QUIC_STATUS StreamCallback(_In_ MsQuicStream* Stream, _In_opt_ void* Context, _Inout_ QUIC_STREAM_EVENT* Event) { + auto TestContext = (StreamPriorityTestContext*)Context; + if (Event->Type == QUIC_STREAM_EVENT_RECEIVE) { + if (TestContext->CurrentReceiveCount >= ARRAYSIZE(ReceiveEvents)) { + TEST_FAILURE("Too many receive events!"); + } else { + Stream->GetID(&TestContext->ReceiveEvents[TestContext->CurrentReceiveCount++]); + if (TestContext->CurrentReceiveCount == ARRAYSIZE(ReceiveEvents)) { + TestContext->AllReceivesComplete.Set(); + } + } + } + return QUIC_STATUS_SUCCESS; + } + + static QUIC_STATUS ConnCallback(_In_ MsQuicConnection*, _In_opt_ void* Context, _Inout_ QUIC_CONNECTION_EVENT* Event) { + if (Event->Type == QUIC_CONNECTION_EVENT_PEER_STREAM_STARTED) { + new(std::nothrow) MsQuicStream(Event->PEER_STREAM_STARTED.Stream, CleanUpAutoDelete, StreamCallback, Context); + } + return QUIC_STATUS_SUCCESS; + } +}; + +void +QuicTestStreamPriority( + ) +{ + MsQuicRegistration Registration(true); + TEST_QUIC_SUCCEEDED(Registration.GetInitStatus()); + + MsQuicConfiguration ServerConfiguration(Registration, "MsQuicTest", MsQuicSettings().SetPeerUnidiStreamCount(3), ServerSelfSignedCredConfig); + TEST_QUIC_SUCCEEDED(ServerConfiguration.GetInitStatus()); + + MsQuicConfiguration ClientConfiguration(Registration, "MsQuicTest", MsQuicCredentialConfig()); + TEST_QUIC_SUCCEEDED(ClientConfiguration.GetInitStatus()); + + StreamPriorityTestContext Context; + MsQuicAutoAcceptListener Listener(Registration, ServerConfiguration, StreamPriorityTestContext::ConnCallback, &Context); + TEST_QUIC_SUCCEEDED(Listener.GetInitStatus()); + TEST_QUIC_SUCCEEDED(Listener.Start("MsQuicTest")); + QuicAddr ServerLocalAddr; + TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr)); + + MsQuicConnection Connection(Registration); + TEST_QUIC_SUCCEEDED(Connection.GetInitStatus()); + + uint8_t RawBuffer[100]; + QUIC_BUFFER Buffer { sizeof(RawBuffer), RawBuffer }; + + MsQuicStream Stream1(Connection, QUIC_STREAM_OPEN_FLAG_UNIDIRECTIONAL); + TEST_QUIC_SUCCEEDED(Stream1.GetInitStatus()); + TEST_QUIC_SUCCEEDED(Stream1.SetPriority(0xFFFF)); + TEST_QUIC_SUCCEEDED(Stream1.Send(&Buffer, 1, QUIC_SEND_FLAG_START | QUIC_SEND_FLAG_FIN)); + + MsQuicStream Stream2(Connection, QUIC_STREAM_OPEN_FLAG_UNIDIRECTIONAL); + TEST_QUIC_SUCCEEDED(Stream2.GetInitStatus()); + TEST_QUIC_SUCCEEDED(Stream2.SetPriority(0xFFFF)); + TEST_QUIC_SUCCEEDED(Stream2.Send(&Buffer, 1, QUIC_SEND_FLAG_START | QUIC_SEND_FLAG_FIN)); + + MsQuicStream Stream3(Connection, QUIC_STREAM_OPEN_FLAG_UNIDIRECTIONAL); + TEST_QUIC_SUCCEEDED(Stream3.GetInitStatus()); + TEST_QUIC_SUCCEEDED(Stream3.Send(&Buffer, 1, QUIC_SEND_FLAG_START | QUIC_SEND_FLAG_FIN)); + + TEST_QUIC_SUCCEEDED(Stream1.SetPriority(0)); // Change to lowest priority + + TEST_QUIC_SUCCEEDED(Connection.StartLocalhost(ClientConfiguration, ServerLocalAddr)); + TEST_TRUE(Connection.HandshakeCompleteEvent.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(Connection.HandshakeComplete); + + TEST_TRUE(Context.AllReceivesComplete.WaitTimeout(TestWaitTimeout)); + TEST_TRUE(Context.ReceiveEvents[0] == Stream2.ID()); + TEST_TRUE(Context.ReceiveEvents[1] == Stream3.ID()); + TEST_TRUE(Context.ReceiveEvents[2] == Stream1.ID()); +} diff --git a/src/tools/spin/spinquic.cpp b/src/tools/spin/spinquic.cpp index 351c773be0..f820dcdd76 100644 --- a/src/tools/spin/spinquic.cpp +++ b/src/tools/spin/spinquic.cpp @@ -141,6 +141,7 @@ typedef enum { SpinQuicAPICallStreamClose, SpinQuicAPICallSetParamConnection, SpinQuicAPICallGetParamConnection, + SpinQuicAPICallSetParamStream, SpinQuicAPICallGetParamStream, SpinQuicAPICallDatagramSend, SpinQuicAPICallStreamReceiveSetEnabled, @@ -387,7 +388,7 @@ void SpinQuicSetRandomConnectionParam(HQUIC Connection) { SetParamHelper Helper(QUIC_PARAM_LEVEL_CONNECTION); - switch (GetRandom(22) + 1) { + switch (0x14000000 | (GetRandom(22) + 1)) { case QUIC_PARAM_CONN_QUIC_VERSION: // uint32_t // QUIC_VERSION is get-only break; @@ -430,6 +431,9 @@ void SpinQuicSetRandomConnectionParam(HQUIC Connection) case QUIC_PARAM_CONN_RESUMPTION_TICKET: // uint8_t[] // TODO break; + case QUIC_PARAM_CONN_PEER_CERTIFICATE_VALID: // uint8_t (BOOLEAN) + Helper.SetUint8(QUIC_PARAM_CONN_PEER_CERTIFICATE_VALID, (uint8_t)GetRandom(2)); + break; default: break; } @@ -437,14 +441,35 @@ void SpinQuicSetRandomConnectionParam(HQUIC Connection) Helper.Apply(Connection); } +void SpinQuicSetRandomStreamParam(HQUIC Stream) +{ + SetParamHelper Helper(QUIC_PARAM_LEVEL_STREAM); + + switch (0x1C000000 | (GetRandom(4) + 1)) { + case QUIC_PARAM_STREAM_ID: // QUIC_UINT62 + break; // Get Only + case QUIC_PARAM_STREAM_0RTT_LENGTH: // QUIC_ADDR + break; // Get Only + case QUIC_PARAM_STREAM_IDEAL_SEND_BUFFER_SIZE: // QUIC_ADDR + break; // Get Only + case QUIC_PARAM_STREAM_PRIORITY: // uint16_t + Helper.SetUint16(QUIC_PARAM_STREAM_PRIORITY, (uint16_t)GetRandom(UINT16_MAX)); + break; + default: + break; + } + + Helper.Apply(Stream); +} + const uint32_t ParamCounts[] = { QUIC_PARAM_GLOBAL_LOAD_BALACING_MODE + 1, QUIC_PARAM_REGISTRATION_CID_PREFIX + 1, 0, QUIC_PARAM_LISTENER_STATS + 1, - QUIC_PARAM_CONN_DISABLE_1RTT_ENCRYPTION + 1, + QUIC_PARAM_CONN_PEER_CERTIFICATE_VALID + 1, 0, - QUIC_PARAM_STREAM_IDEAL_SEND_BUFFER_SIZE + 1 + QUIC_PARAM_STREAM_PRIORITY + 1 }; #define GET_PARAM_LOOP_COUNT 10 @@ -453,7 +478,7 @@ void SpinQuicGetRandomParam(HQUIC Handle) { for (uint32_t i = 0; i < GET_PARAM_LOOP_COUNT; ++i) { QUIC_PARAM_LEVEL Level = (QUIC_PARAM_LEVEL)GetRandom(5); - uint32_t Param = (uint32_t)GetRandom(ParamCounts[Level] + 1); + uint32_t Param = (uint32_t)GetRandom((ParamCounts[Level] & 0x3FFFFF) + 1); uint8_t OutBuffer[200]; uint32_t OutBufferLength = (uint32_t)GetRandom(sizeof(OutBuffer) + 1); @@ -544,6 +569,8 @@ void Spin(Gbs& Gb, LockableVector& Connections, std::vector* Liste HQUIC Stream; QUIC_STATUS Status = MsQuic.StreamOpen(Connection, (QUIC_STREAM_OPEN_FLAGS)GetRandom(2), SpinQuicHandleStreamEvent, nullptr, &Stream); if (QUIC_SUCCEEDED(Status)) { + SpinQuicGetRandomParam(Stream); + SpinQuicSetRandomStreamParam(Stream); SpinQuicConnection::Get(Connection)->AddStream(Stream); } break; @@ -642,6 +669,28 @@ void Spin(Gbs& Gb, LockableVector& Connections, std::vector* Liste SpinQuicGetRandomParam(Connection); break; } + case SpinQuicAPICallSetParamStream: { + auto Connection = Connections.TryGetRandom(); + BAIL_ON_NULL_CONNECTION(Connection); + auto ctx = SpinQuicConnection::Get(Connection); + { + std::lock_guard Lock(ctx->Lock); + auto Stream = ctx->TryGetStream(); + if (Stream == nullptr) continue; + /* TODO: + + Currently deadlocks because it makes a blocking call to wait + on the QUIC worker thread, but the worker thread tries to + grab the same lock when cleaning up the connections' streams. + + We're going to need some kind of ref counting solution on + the stream handle instead of a lock in order to do this. + + SpinQuicSetRandomStreamParam(Stream); + */ + } + break; + } case SpinQuicAPICallGetParamStream: { auto Connection = Connections.TryGetRandom(); BAIL_ON_NULL_CONNECTION(Connection); @@ -654,7 +703,7 @@ void Spin(Gbs& Gb, LockableVector& Connections, std::vector* Liste Currently deadlocks because it makes a blocking call to wait on the QUIC worker thread, but the worker thread tries to - grab the same log when cleaning up the connections' streams. + grab the same lock when cleaning up the connections' streams. We're going to need some kind of ref counting solution on the stream handle instead of a lock in order to do this.