From 448184f827ea7706152a1f34a567c743f94d674f Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 16 Oct 2024 08:49:35 -0400 Subject: [PATCH 1/8] Initial External Execution Interface --- src/inc/msquic.h | 84 +++++++++++++++++++++++++++++++++++++++- src/inc/msquic_posix.h | 20 ++++++++++ src/inc/msquic_winuser.h | 7 ++++ 3 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/inc/msquic.h b/src/inc/msquic.h index d9c25b8933..f81146117a 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -264,15 +264,15 @@ typedef enum QUIC_DATAGRAM_SEND_STATE { #define QUIC_DATAGRAM_SEND_STATE_IS_FINAL(State) \ ((State) >= QUIC_DATAGRAM_SEND_LOST_DISCARDED) +#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES + typedef enum QUIC_EXECUTION_CONFIG_FLAGS { QUIC_EXECUTION_CONFIG_FLAG_NONE = 0x0000, -#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES QUIC_EXECUTION_CONFIG_FLAG_QTIP = 0x0001, QUIC_EXECUTION_CONFIG_FLAG_RIO = 0x0002, QUIC_EXECUTION_CONFIG_FLAG_XDP = 0x0004, QUIC_EXECUTION_CONFIG_FLAG_NO_IDEAL_PROC = 0x0008, QUIC_EXECUTION_CONFIG_FLAG_HIGH_PRIORITY = 0x0010, -#endif } QUIC_EXECUTION_CONFIG_FLAGS; DEFINE_ENUM_FLAG_OPERATORS(QUIC_EXECUTION_CONFIG_FLAGS) @@ -293,6 +293,82 @@ typedef struct QUIC_EXECUTION_CONFIG { #define QUIC_EXECUTION_CONFIG_MIN_SIZE \ (uint32_t)FIELD_OFFSET(QUIC_EXECUTION_CONFIG, ProcessorList) +// +// Execution Context abstraction, which allows the application layer to +// completely control execution of all MsQuic work. +// + +typedef struct QUIC_EXECUTION_CONTEXT_CONFIG { + uint32_t IdealProcessor; + uint32_t PollingIdleTimeoutUs; + QUIC_EVENTQ* EventQ; +} QUIC_EXECUTION_CONTEXT_CONFIG; + +typedef struct QUIC_EXECUTION_CONTEXT QUIC_EXECUTION_CONTEXT; + +// +// This is called create the execution contexts. +// +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +(QUIC_API * QUIC_EXECUTION_CREATE_FN)( + _In_ QUIC_EXECUTION_CONFIG_FLAGS Flags, // Used for datapath type + _In_ uint32_t Count, + _In_reads_(Count) QUIC_EXECUTION_CONTEXT_CONFIG* Configs, + _Out_writes_(Count) QUIC_EXECUTION_CONTEXT** ExecutionContexts + ); + +// +// This is called to delete the execution contexts. +// +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +void +(QUIC_API * QUIC_EXECUTION_DELETE_FN)( + _In_ uint32_t Count, + _In_reads_(Count) QUIC_EXECUTION_CONTEXT** ExecutionContexts + ); + +// +// This is called to allow MsQuic to process any polling work. It returns the +// number of milliseconds until the next scheduled timer expiration. +// +// TODO: Should it return an indication for if we should yield? +// +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +uint32_t +(QUIC_API * QUIC_EXECUTION_POLL_FN)( + _In_ QUIC_EXECUTION_CONTEXT* ExecutionContext + ); + +// +// This is called to allow MsQuic to process any completions that have occurred. +// +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +uint32_t +(QUIC_API * QUIC_EXECUTION_PROCESS_CQE_FN)( + _In_ QUIC_EXECUTION_CONTEXT* ExecutionContext, + _In_reads_(CqeCount) QUIC_CQE* Cqes, + _In_ uint32_t CqeCount + ); + +// +// The table of execution functions. +// +typedef struct QUIC_EXECUTION_TABLE { + + QUIC_EXECUTION_CREATE_FN ExecutionCreate; + QUIC_EXECUTION_DELETE_FN ExecutionDelete; + QUIC_EXECUTION_POLL_FN Poll; + QUIC_EXECUTION_PROCESS_CQE_FN ProcessCqe; + +} QUIC_EXECUTION_TABLE; + +#endif + typedef struct QUIC_REGISTRATION_CONFIG { // All fields may be NULL/zero. const char* AppName; QUIC_EXECUTION_PROFILE ExecutionProfile; @@ -857,6 +933,10 @@ void #endif #define QUIC_PARAM_GLOBAL_TLS_PROVIDER 0x0100000A // QUIC_TLS_PROVIDER #define QUIC_PARAM_GLOBAL_STATELESS_RESET_KEY 0x0100000B // uint8_t[] - Array size is QUIC_STATELESS_RESET_KEY_LENGTH +#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES +#define QUIC_PARAM_GLOBAL_EXECUTION_TABLE 0x0100000C // QUIC_EXECUTION_TABLE +#endif + // // Parameters for Registration. // diff --git a/src/inc/msquic_posix.h b/src/inc/msquic_posix.h index 27393e1233..87e58150fb 100644 --- a/src/inc/msquic_posix.h +++ b/src/inc/msquic_posix.h @@ -515,6 +515,26 @@ QuicAddrToString( return TRUE; } +// +// Event Queue Abstraction +// + +#if __linux__ // epoll + +typedef int QUIC_EVENTQ; +typedef struct epoll_event QUIC_CQE; + +#elif __APPLE__ || __FreeBSD__ // kqueue + +typedef int QUIC_EVENTQ; +typedef struct kevent QUIC_CQE; + +#else + +#error Unsupported Platform + +#endif + #if defined(__cplusplus) } #endif diff --git a/src/inc/msquic_winuser.h b/src/inc/msquic_winuser.h index adc2f2292e..4e0f3bac68 100644 --- a/src/inc/msquic_winuser.h +++ b/src/inc/msquic_winuser.h @@ -373,4 +373,11 @@ QuicAddrToString( #endif // WINAPI_FAMILY != WINAPI_FAMILY_GAMES +// +// Event Queue Abstraction +// + +typedef HANDLE QUIC_EVENTQ; +typedef OVERLAPPED_ENTRY QUIC_CQE; + #endif // _MSQUIC_WINUSER_ From 442c928a53afd5dbc5e0403e4053c327a7c08fd8 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 16 Oct 2024 09:04:36 -0400 Subject: [PATCH 2/8] Make .NET and Kernel mode happy --- src/cs/lib/msquic_generated.cs | 34 ++++++++++++++++++++++++++++++++++ src/inc/msquic.h | 6 +++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs index cf1477ea76..970d85153e 100644 --- a/src/cs/lib/msquic_generated.cs +++ b/src/cs/lib/msquic_generated.cs @@ -234,6 +234,37 @@ internal unsafe partial struct QUIC_EXECUTION_CONFIG internal fixed ushort ProcessorList[1]; } + internal unsafe partial struct QUIC_EXECUTION_CONTEXT_CONFIG + { + [NativeTypeName("uint32_t")] + internal uint IdealProcessor; + + [NativeTypeName("uint32_t")] + internal uint PollingIdleTimeoutUs; + + [NativeTypeName("QUIC_EVENTQ *")] + internal void** EventQ; + } + + internal partial struct QUIC_EXECUTION_CONTEXT + { + } + + internal unsafe partial struct QUIC_EXECUTION_TABLE + { + [NativeTypeName("QUIC_EXECUTION_CREATE_FN")] + internal delegate* unmanaged[Cdecl] ExecutionCreate; + + [NativeTypeName("QUIC_EXECUTION_DELETE_FN")] + internal delegate* unmanaged[Cdecl] ExecutionDelete; + + [NativeTypeName("QUIC_EXECUTION_POLL_FN")] + internal delegate* unmanaged[Cdecl] Poll; + + [NativeTypeName("QUIC_EXECUTION_PROCESS_CQE_FN")] + internal delegate* unmanaged[Cdecl] ProcessCqe; + } + internal unsafe partial struct QUIC_REGISTRATION_CONFIG { [NativeTypeName("const char *")] @@ -3345,6 +3376,9 @@ internal static unsafe partial class MsQuic [NativeTypeName("#define QUIC_PARAM_GLOBAL_STATELESS_RESET_KEY 0x0100000B")] internal const uint QUIC_PARAM_GLOBAL_STATELESS_RESET_KEY = 0x0100000B; + [NativeTypeName("#define QUIC_PARAM_GLOBAL_EXECUTION_TABLE 0x0100000C")] + internal const uint QUIC_PARAM_GLOBAL_EXECUTION_TABLE = 0x0100000C; + [NativeTypeName("#define QUIC_PARAM_CONFIGURATION_SETTINGS 0x03000000")] internal const uint QUIC_PARAM_CONFIGURATION_SETTINGS = 0x03000000; diff --git a/src/inc/msquic.h b/src/inc/msquic.h index f81146117a..f6941ae917 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -293,6 +293,8 @@ typedef struct QUIC_EXECUTION_CONFIG { #define QUIC_EXECUTION_CONFIG_MIN_SIZE \ (uint32_t)FIELD_OFFSET(QUIC_EXECUTION_CONFIG, ProcessorList) +#ifndef _KERNEL_MODE + // // Execution Context abstraction, which allows the application layer to // completely control execution of all MsQuic work. @@ -367,7 +369,9 @@ typedef struct QUIC_EXECUTION_TABLE { } QUIC_EXECUTION_TABLE; -#endif +#endif // _KERNEL_MODE + +#endif // QUIC_API_ENABLE_PREVIEW_FEATURES typedef struct QUIC_REGISTRATION_CONFIG { // All fields may be NULL/zero. const char* AppName; From e0f9d138b7d3e124ddb3d8bac725e74f865795cd Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 16 Oct 2024 09:08:04 -0400 Subject: [PATCH 3/8] Check function --- src/cs/lib/msquic_generated.cs | 3 +++ src/inc/msquic.h | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs index 970d85153e..1399289bbd 100644 --- a/src/cs/lib/msquic_generated.cs +++ b/src/cs/lib/msquic_generated.cs @@ -261,6 +261,9 @@ internal unsafe partial struct QUIC_EXECUTION_TABLE [NativeTypeName("QUIC_EXECUTION_POLL_FN")] internal delegate* unmanaged[Cdecl] Poll; + [NativeTypeName("QUIC_EXECUTION_CHECK_CQE_FN")] + internal delegate* unmanaged[Cdecl]<_OVERLAPPED_ENTRY*, byte> CheckCqe; + [NativeTypeName("QUIC_EXECUTION_PROCESS_CQE_FN")] internal delegate* unmanaged[Cdecl] ProcessCqe; } diff --git a/src/inc/msquic.h b/src/inc/msquic.h index f6941ae917..9eec07c4ef 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -345,6 +345,19 @@ uint32_t _In_ QUIC_EXECUTION_CONTEXT* ExecutionContext ); +// +// This is used to check if a completion event belongs to MsQuic or not. +// +// TODO: This makes certain assumptions for the layout of completion event +// payload. How do we generalize this? +// +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +(QUIC_API * QUIC_EXECUTION_CHECK_CQE_FN)( + _In_ const QUIC_CQE* Cqe + ); + // // This is called to allow MsQuic to process any completions that have occurred. // @@ -365,6 +378,7 @@ typedef struct QUIC_EXECUTION_TABLE { QUIC_EXECUTION_CREATE_FN ExecutionCreate; QUIC_EXECUTION_DELETE_FN ExecutionDelete; QUIC_EXECUTION_POLL_FN Poll; + QUIC_EXECUTION_CHECK_CQE_FN CheckCqe; QUIC_EXECUTION_PROCESS_CQE_FN ProcessCqe; } QUIC_EXECUTION_TABLE; From adb9ad97180b14c5c90d2e546bf6d49ecbe4807f Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 16 Oct 2024 09:50:53 -0400 Subject: [PATCH 4/8] Incomplete example --- src/tools/execution/CMakeLists.txt | 5 + src/tools/execution/execution_windows.cpp | 109 ++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 src/tools/execution/CMakeLists.txt create mode 100644 src/tools/execution/execution_windows.cpp diff --git a/src/tools/execution/CMakeLists.txt b/src/tools/execution/CMakeLists.txt new file mode 100644 index 0000000000..dcc6c2106c --- /dev/null +++ b/src/tools/execution/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +add_quic_tool(quicexecution execution_windows.cpp) +quic_tool_warnings(quicexecution) diff --git a/src/tools/execution/execution_windows.cpp b/src/tools/execution/execution_windows.cpp new file mode 100644 index 0000000000..1eb202ce41 --- /dev/null +++ b/src/tools/execution/execution_windows.cpp @@ -0,0 +1,109 @@ +/*++ + + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. + +Abstract: + + Provides simple client MsQuic example that leverages custom execution. + +--*/ + +#define _CRT_SECURE_NO_WARNINGS 1 +#define QUIC_API_ENABLE_PREVIEW_FEATURES 1 + +#include "msquic.hpp" +#include +#include + +const MsQuicApi* MsQuic; + +void PrintUsage() +{ + printf( + "\n" + "quicexec is a simple app that can connect to an HTTP/3 server.\n" + "\n" + "Usage:\n" + "\n" + " quicexec \n" + ); +} + +int +QUIC_MAIN_EXPORT +main( + _In_ int argc, + _In_reads_(argc) _Null_terminated_ char* argv[] + ) +{ + MsQuicApi _MsQuic; + if (!_MsQuic.IsValid()) { return 1; } + MsQuic = &_MsQuic; + + QUIC_STATUS Status; + QUIC_EXECUTION_TABLE MsQuicExec; + uint32_t MsQuicExecLength = sizeof(MsQuicExec); + if (QUIC_FAILED( + Status = MsQuic->GetParam( + nullptr, + QUIC_PARAM_GLOBAL_EXECUTION_TABLE, + &MsQuicExecLength, + &MsQuicExec))) { + return 1; + } + + HANDLE IOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1); + QUIC_EXECUTION_CONTEXT_CONFIG ExecConfig = { 0, 0, &IOCP }; + QUIC_EXECUTION_CONTEXT* ExecContext = nullptr; + if (QUIC_FAILED( + Status = MsQuicExec.ExecutionCreate( + QUIC_EXECUTION_CONFIG_FLAG_NONE, + 1, + &ExecConfig, + &ExecContext))) { + return 1; + } + + do { + MsQuicRegistration Registration("quicexec"); + MsQuicSettings Settings; + Settings.SetPeerUnidiStreamCount(3); // required for H3 + MsQuicConfiguration Configuration(Registration, "h3", Settings, MsQuicCredentialConfig()); + if (!Configuration.IsValid()) { break; } + + MsQuicConnection Connection(Registration); + if (QUIC_FAILED( + Status = Connection.Start(Configuration, argv[1], 443))) { + break; + } + + while (true) { + uint32_t WaitTime = MsQuicExec.Poll(ExecContext); + + OVERLAPPED_ENTRY Cqes[8]; + ULONG CqeCount = 0; + if (GetQueuedCompletionStatusEx(IOCP, Cqes, ARRAYSIZE(Cqes), &CqeCount, WaitTime, FALSE)) { + for (ULONG i = 0; i < CqeCount; ++i) { + if (MsQuicExec.CheckCqe(Cqes+i)) { + MsQuicExec.ProcessCqe(ExecContext, Cqes+i, 1); + } else { + // We should handle our own completions here. + } + } + } + + if (Connection.HandshakeComplete) { + Connection.Shutdown(0); + } + + // TODO - Stop once the connection is shutdown complete + } + + } while (false); + + MsQuicExec.ExecutionDelete(1, &ExecContext); + CloseHandle(IOCP); + + return 0; +} From 882e6306b2198ba1467e16b16cf0a84d23cd4647 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 16 Oct 2024 11:05:00 -0400 Subject: [PATCH 5/8] Simplify --- src/inc/msquic.h | 34 ++---------- src/inc/msquic_posix.h | 12 ++++- src/inc/msquic_winuser.h | 6 ++- src/tools/execution/execution_windows.cpp | 64 ++++++++--------------- 4 files changed, 42 insertions(+), 74 deletions(-) diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 9eec07c4ef..f3729345f9 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -345,31 +345,6 @@ uint32_t _In_ QUIC_EXECUTION_CONTEXT* ExecutionContext ); -// -// This is used to check if a completion event belongs to MsQuic or not. -// -// TODO: This makes certain assumptions for the layout of completion event -// payload. How do we generalize this? -// -typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -BOOLEAN -(QUIC_API * QUIC_EXECUTION_CHECK_CQE_FN)( - _In_ const QUIC_CQE* Cqe - ); - -// -// This is called to allow MsQuic to process any completions that have occurred. -// -typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -uint32_t -(QUIC_API * QUIC_EXECUTION_PROCESS_CQE_FN)( - _In_ QUIC_EXECUTION_CONTEXT* ExecutionContext, - _In_reads_(CqeCount) QUIC_CQE* Cqes, - _In_ uint32_t CqeCount - ); - // // The table of execution functions. // @@ -378,8 +353,6 @@ typedef struct QUIC_EXECUTION_TABLE { QUIC_EXECUTION_CREATE_FN ExecutionCreate; QUIC_EXECUTION_DELETE_FN ExecutionDelete; QUIC_EXECUTION_POLL_FN Poll; - QUIC_EXECUTION_CHECK_CQE_FN CheckCqe; - QUIC_EXECUTION_PROCESS_CQE_FN ProcessCqe; } QUIC_EXECUTION_TABLE; @@ -951,9 +924,6 @@ void #endif #define QUIC_PARAM_GLOBAL_TLS_PROVIDER 0x0100000A // QUIC_TLS_PROVIDER #define QUIC_PARAM_GLOBAL_STATELESS_RESET_KEY 0x0100000B // uint8_t[] - Array size is QUIC_STATELESS_RESET_KEY_LENGTH -#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES -#define QUIC_PARAM_GLOBAL_EXECUTION_TABLE 0x0100000C // QUIC_EXECUTION_TABLE -#endif // // Parameters for Registration. @@ -1724,6 +1694,10 @@ typedef struct QUIC_API_TABLE { QUIC_CONNECTION_COMP_RESUMPTION_FN ConnectionResumptionTicketValidationComplete; // Available from v2.2 QUIC_CONNECTION_COMP_CERT_FN ConnectionCertificateValidationComplete; // Available from v2.2 + QUIC_EXECUTION_CREATE_FN ExecutionCreate; + QUIC_EXECUTION_DELETE_FN ExecutionDelete; + QUIC_EXECUTION_POLL_FN ExecutionPoll; + } QUIC_API_TABLE; #define QUIC_API_VERSION_1 1 // Not supported any more diff --git a/src/inc/msquic_posix.h b/src/inc/msquic_posix.h index 87e58150fb..eeef69c9b1 100644 --- a/src/inc/msquic_posix.h +++ b/src/inc/msquic_posix.h @@ -522,12 +522,20 @@ QuicAddrToString( #if __linux__ // epoll typedef int QUIC_EVENTQ; -typedef struct epoll_event QUIC_CQE; + +typedef struct QUIC_CQE { + struct epoll_event Event; + void (*Completion)(struct QUIC_CQE *Cqe); +} QUIC_CQE; #elif __APPLE__ || __FreeBSD__ // kqueue typedef int QUIC_EVENTQ; -typedef struct kevent QUIC_CQE; + +typedef struct QUIC_CQE { + struct kevent Event; + void (*Completion)(struct QUIC_CQE *Cqe); +} QUIC_CQE; #else diff --git a/src/inc/msquic_winuser.h b/src/inc/msquic_winuser.h index 4e0f3bac68..0201e4e6d6 100644 --- a/src/inc/msquic_winuser.h +++ b/src/inc/msquic_winuser.h @@ -378,6 +378,10 @@ QuicAddrToString( // typedef HANDLE QUIC_EVENTQ; -typedef OVERLAPPED_ENTRY QUIC_CQE; + +typedef struct QUIC_CQE { + OVERLAPPED_ENTRY Overlapped; + void (*Completion)(struct QUIC_CQE *Cqe); +} QUIC_CQE; #endif // _MSQUIC_WINUSER_ diff --git a/src/tools/execution/execution_windows.cpp b/src/tools/execution/execution_windows.cpp index 1eb202ce41..caead4b8df 100644 --- a/src/tools/execution/execution_windows.cpp +++ b/src/tools/execution/execution_windows.cpp @@ -9,14 +9,10 @@ --*/ -#define _CRT_SECURE_NO_WARNINGS 1 #define QUIC_API_ENABLE_PREVIEW_FEATURES 1 #include "msquic.hpp" #include -#include - -const MsQuicApi* MsQuic; void PrintUsage() { @@ -42,67 +38,53 @@ main( MsQuic = &_MsQuic; QUIC_STATUS Status; - QUIC_EXECUTION_TABLE MsQuicExec; - uint32_t MsQuicExecLength = sizeof(MsQuicExec); - if (QUIC_FAILED( - Status = MsQuic->GetParam( - nullptr, - QUIC_PARAM_GLOBAL_EXECUTION_TABLE, - &MsQuicExecLength, - &MsQuicExec))) { - return 1; - } - HANDLE IOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1); QUIC_EXECUTION_CONTEXT_CONFIG ExecConfig = { 0, 0, &IOCP }; QUIC_EXECUTION_CONTEXT* ExecContext = nullptr; - if (QUIC_FAILED( - Status = MsQuicExec.ExecutionCreate( - QUIC_EXECUTION_CONFIG_FLAG_NONE, - 1, - &ExecConfig, - &ExecContext))) { + if (QUIC_FAILED(Status = MsQuic->ExecutionCreate(QUIC_EXECUTION_CONFIG_FLAG_NONE, 1, &ExecConfig, &ExecContext))) { return 1; } do { + bool AllDone = false; MsQuicRegistration Registration("quicexec"); MsQuicSettings Settings; Settings.SetPeerUnidiStreamCount(3); // required for H3 MsQuicConfiguration Configuration(Registration, "h3", Settings, MsQuicCredentialConfig()); if (!Configuration.IsValid()) { break; } - MsQuicConnection Connection(Registration); + struct ConnectionCallback { + static QUIC_STATUS MsQuicConnectionCallback(_In_ struct MsQuicConnection* Connection, _In_opt_ void* Context, _Inout_ QUIC_CONNECTION_EVENT* Event) { + if (Event->Type == QUIC_CONNECTION_EVENT_CONNECTED) { + Connection->Shutdown(0); + } else if (Event->Type == QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE) { + *((bool*)Context) = true; + } + } + }; + + MsQuicConnection Connection(Registration, CleanUpManual, ConnectionCallback::MsQuicConnectionCallback, &AllDone); if (QUIC_FAILED( Status = Connection.Start(Configuration, argv[1], 443))) { break; } - while (true) { - uint32_t WaitTime = MsQuicExec.Poll(ExecContext); - - OVERLAPPED_ENTRY Cqes[8]; - ULONG CqeCount = 0; - if (GetQueuedCompletionStatusEx(IOCP, Cqes, ARRAYSIZE(Cqes), &CqeCount, WaitTime, FALSE)) { - for (ULONG i = 0; i < CqeCount; ++i) { - if (MsQuicExec.CheckCqe(Cqes+i)) { - MsQuicExec.ProcessCqe(ExecContext, Cqes+i, 1); - } else { - // We should handle our own completions here. - } - } - } + while (!AllDone) { + uint32_t WaitTime = MsQuic->ExecutionPoll(ExecContext); - if (Connection.HandshakeComplete) { - Connection.Shutdown(0); + OVERLAPPED_ENTRY Overlapped[8]; + ULONG OverlappedCount = 0; + if (GetQueuedCompletionStatusEx(IOCP, Overlapped, ARRAYSIZE(Overlapped), &OverlappedCount, WaitTime, FALSE)) { + for (ULONG i = 0; i < OverlappedCount; ++i) { + QUIC_CQE* Cqe = CONTAINING_RECORD(Overlapped[i].lpOverlapped, QUIC_CQE, Overlapped); + Cqe->Completion(Cqe); + } } - - // TODO - Stop once the connection is shutdown complete } } while (false); - MsQuicExec.ExecutionDelete(1, &ExecContext); + MsQuic->ExecutionDelete(1, &ExecContext); CloseHandle(IOCP); return 0; From da9e0b24f15f912f0965bc808344c2f8b71dc3c4 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 16 Oct 2024 11:05:34 -0400 Subject: [PATCH 6/8] Fix .net --- src/cs/lib/msquic_generated.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs index 1399289bbd..7e8e51d0a1 100644 --- a/src/cs/lib/msquic_generated.cs +++ b/src/cs/lib/msquic_generated.cs @@ -260,12 +260,6 @@ internal unsafe partial struct QUIC_EXECUTION_TABLE [NativeTypeName("QUIC_EXECUTION_POLL_FN")] internal delegate* unmanaged[Cdecl] Poll; - - [NativeTypeName("QUIC_EXECUTION_CHECK_CQE_FN")] - internal delegate* unmanaged[Cdecl]<_OVERLAPPED_ENTRY*, byte> CheckCqe; - - [NativeTypeName("QUIC_EXECUTION_PROCESS_CQE_FN")] - internal delegate* unmanaged[Cdecl] ProcessCqe; } internal unsafe partial struct QUIC_REGISTRATION_CONFIG @@ -3284,6 +3278,15 @@ internal unsafe partial struct QUIC_API_TABLE [NativeTypeName("QUIC_CONNECTION_COMP_CERT_FN")] internal delegate* unmanaged[Cdecl] ConnectionCertificateValidationComplete; + + [NativeTypeName("QUIC_EXECUTION_CREATE_FN")] + internal delegate* unmanaged[Cdecl] ExecutionCreate; + + [NativeTypeName("QUIC_EXECUTION_DELETE_FN")] + internal delegate* unmanaged[Cdecl] ExecutionDelete; + + [NativeTypeName("QUIC_EXECUTION_POLL_FN")] + internal delegate* unmanaged[Cdecl] ExecutionPoll; } internal static unsafe partial class MsQuic @@ -3379,9 +3382,6 @@ internal static unsafe partial class MsQuic [NativeTypeName("#define QUIC_PARAM_GLOBAL_STATELESS_RESET_KEY 0x0100000B")] internal const uint QUIC_PARAM_GLOBAL_STATELESS_RESET_KEY = 0x0100000B; - [NativeTypeName("#define QUIC_PARAM_GLOBAL_EXECUTION_TABLE 0x0100000C")] - internal const uint QUIC_PARAM_GLOBAL_EXECUTION_TABLE = 0x0100000C; - [NativeTypeName("#define QUIC_PARAM_CONFIGURATION_SETTINGS 0x03000000")] internal const uint QUIC_PARAM_CONFIGURATION_SETTINGS = 0x03000000; From 94efc4493cb3fc72804d41342ea09b3a697837a3 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 16 Oct 2024 11:06:27 -0400 Subject: [PATCH 7/8] Remove leftovers --- src/cs/lib/msquic_generated.cs | 12 ------------ src/inc/msquic.h | 11 ----------- 2 files changed, 23 deletions(-) diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs index 7e8e51d0a1..9c112f5ab1 100644 --- a/src/cs/lib/msquic_generated.cs +++ b/src/cs/lib/msquic_generated.cs @@ -250,18 +250,6 @@ internal partial struct QUIC_EXECUTION_CONTEXT { } - internal unsafe partial struct QUIC_EXECUTION_TABLE - { - [NativeTypeName("QUIC_EXECUTION_CREATE_FN")] - internal delegate* unmanaged[Cdecl] ExecutionCreate; - - [NativeTypeName("QUIC_EXECUTION_DELETE_FN")] - internal delegate* unmanaged[Cdecl] ExecutionDelete; - - [NativeTypeName("QUIC_EXECUTION_POLL_FN")] - internal delegate* unmanaged[Cdecl] Poll; - } - internal unsafe partial struct QUIC_REGISTRATION_CONFIG { [NativeTypeName("const char *")] diff --git a/src/inc/msquic.h b/src/inc/msquic.h index f3729345f9..940b70c445 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -345,17 +345,6 @@ uint32_t _In_ QUIC_EXECUTION_CONTEXT* ExecutionContext ); -// -// The table of execution functions. -// -typedef struct QUIC_EXECUTION_TABLE { - - QUIC_EXECUTION_CREATE_FN ExecutionCreate; - QUIC_EXECUTION_DELETE_FN ExecutionDelete; - QUIC_EXECUTION_POLL_FN Poll; - -} QUIC_EXECUTION_TABLE; - #endif // _KERNEL_MODE #endif // QUIC_API_ENABLE_PREVIEW_FEATURES From 969559269b4f6c2aafc75e2e8bf29e2ae4d6d4e8 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Wed, 16 Oct 2024 11:07:59 -0400 Subject: [PATCH 8/8] fixes --- src/inc/msquic.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 940b70c445..4fbf31fc54 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -1683,9 +1683,11 @@ typedef struct QUIC_API_TABLE { QUIC_CONNECTION_COMP_RESUMPTION_FN ConnectionResumptionTicketValidationComplete; // Available from v2.2 QUIC_CONNECTION_COMP_CERT_FN ConnectionCertificateValidationComplete; // Available from v2.2 - QUIC_EXECUTION_CREATE_FN ExecutionCreate; - QUIC_EXECUTION_DELETE_FN ExecutionDelete; - QUIC_EXECUTION_POLL_FN ExecutionPoll; +#ifndef _KERNEL_MODE + QUIC_EXECUTION_CREATE_FN ExecutionCreate; // Available from v2.5 + QUIC_EXECUTION_DELETE_FN ExecutionDelete; // Available from v2.5 + QUIC_EXECUTION_POLL_FN ExecutionPoll; // Available from v2.5 +#endif } QUIC_API_TABLE;