Skip to content

External Execution Interface #4616

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 46 commits into from
May 7, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
448184f
Initial External Execution Interface
nibanks Oct 16, 2024
442c928
Make .NET and Kernel mode happy
nibanks Oct 16, 2024
e0f9d13
Check function
nibanks Oct 16, 2024
adb9ad9
Incomplete example
nibanks Oct 16, 2024
882e630
Simplify
nibanks Oct 16, 2024
da9e0b2
Fix .net
nibanks Oct 16, 2024
94efc44
Remove leftovers
nibanks Oct 16, 2024
9695592
fixes
nibanks Oct 16, 2024
4554407
wip
nibanks Oct 18, 2024
40d1e84
wip
nibanks Oct 28, 2024
74835cf
docs
nibanks Oct 31, 2024
f73a471
Merge branch 'main' into external-execution
nibanks Dec 5, 2024
b743020
A bit of documentation
nibanks Dec 6, 2024
dd7abe0
c++ formatting is nicer
nibanks Dec 6, 2024
be0855e
Merge branch 'main' into external-execution
nibanks Jan 4, 2025
919ae67
Updates to latest design
nibanks Jan 4, 2025
0e4b73d
Merge branch 'main' into external-execution
nibanks Jan 7, 2025
94b4c3f
wip
nibanks Jan 8, 2025
446a9f3
wip
nibanks Jan 22, 2025
f39e7f8
Merge branch 'main' into external-execution
nibanks Mar 17, 2025
b15ba57
Merge branch 'main' into external-execution
nibanks Mar 18, 2025
4a86d10
Merge branch 'main' into external-execution
nibanks Apr 10, 2025
bd22e7d
Merge branch 'main' into external-execution
nibanks Apr 17, 2025
c5b97f8
WIP
nibanks Apr 17, 2025
d2d209c
Merge branch 'main' into external-execution
nibanks Apr 28, 2025
3264294
Merge branch 'main' into external-execution
nibanks Apr 28, 2025
9603086
wip
nibanks Apr 28, 2025
a06aa81
renames
nibanks Apr 28, 2025
8c7c05b
Fix clog
nibanks Apr 28, 2025
8948a57
Merge branch 'main' into external-execution
nibanks Apr 30, 2025
2e1bf82
Merge branch 'main' into external-execution
nibanks May 6, 2025
74b8cb9
Fix clean up code
nibanks May 6, 2025
9ccc97d
fix builds
nibanks May 6, 2025
4cab2f5
fixes
nibanks May 6, 2025
7c4b651
Merge branch 'main' into external-execution
nibanks May 6, 2025
ad32894
Single thread test app works!
nibanks May 6, 2025
2039771
unreferenced parameters
nibanks May 6, 2025
a44b999
Fix kernel builds
nibanks May 6, 2025
da26362
another try for kernel mode
nibanks May 6, 2025
e5731f4
Trying to fix rust
nibanks May 6, 2025
38feb45
another try
nibanks May 6, 2025
fd4a623
Another try
nibanks May 6, 2025
630aa78
Another try
nibanks May 6, 2025
f387952
forgot one
nibanks May 6, 2025
cfefdf8
oops
nibanks May 6, 2025
2924b64
hack for mac
nibanks May 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/cs/lib/msquic_generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,22 @@ 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_REGISTRATION_CONFIG
{
[NativeTypeName("const char *")]
Expand Down Expand Up @@ -3250,6 +3266,15 @@ internal unsafe partial struct QUIC_API_TABLE

[NativeTypeName("QUIC_CONNECTION_COMP_CERT_FN")]
internal delegate* unmanaged[Cdecl]<QUIC_HANDLE*, byte, QUIC_TLS_ALERT_CODES, int> ConnectionCertificateValidationComplete;

[NativeTypeName("QUIC_EXECUTION_CREATE_FN")]
internal delegate* unmanaged[Cdecl]<QUIC_EXECUTION_CONFIG_FLAGS, uint, QUIC_EXECUTION_CONTEXT_CONFIG*, QUIC_EXECUTION_CONTEXT**, int> ExecutionCreate;

[NativeTypeName("QUIC_EXECUTION_DELETE_FN")]
internal delegate* unmanaged[Cdecl]<uint, QUIC_EXECUTION_CONTEXT**, void> ExecutionDelete;

[NativeTypeName("QUIC_EXECUTION_POLL_FN")]
internal delegate* unmanaged[Cdecl]<QUIC_EXECUTION_CONTEXT*, uint> ExecutionPoll;
}

internal static unsafe partial class MsQuic
Expand Down
37 changes: 10 additions & 27 deletions src/inc/msquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -343,31 +345,9 @@ uint32_t
_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
);
#endif // _KERNEL_MODE

//
// 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
#endif // QUIC_API_ENABLE_PREVIEW_FEATURES

typedef struct QUIC_REGISTRATION_CONFIG { // All fields may be NULL/zero.
const char* AppName;
Expand Down Expand Up @@ -933,9 +913,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.
Expand Down Expand Up @@ -1706,6 +1683,12 @@ 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

#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;

#define QUIC_API_VERSION_1 1 // Not supported any more
Expand Down
12 changes: 10 additions & 2 deletions src/inc/msquic_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 5 additions & 1 deletion src/inc/msquic_winuser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
5 changes: 5 additions & 0 deletions src/tools/execution/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

add_quic_tool(quicexecution execution_windows.cpp)
quic_tool_warnings(quicexecution)
91 changes: 91 additions & 0 deletions src/tools/execution/execution_windows.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*++

Copyright (c) Microsoft Corporation.
Licensed under the MIT License.

Abstract:

Provides simple client MsQuic example that leverages custom execution.

--*/

#define QUIC_API_ENABLE_PREVIEW_FEATURES 1

#include "msquic.hpp"
#include <stdio.h>

void PrintUsage()
{
printf(
"\n"
"quicexec is a simple app that can connect to an HTTP/3 server.\n"
"\n"
"Usage:\n"
"\n"
" quicexec <host or ip>\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;
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 = 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; }

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 (!AllDone) {
uint32_t WaitTime = MsQuic->ExecutionPoll(ExecContext);

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);
}
}
}

} while (false);

MsQuic->ExecutionDelete(1, &ExecContext);
CloseHandle(IOCP);

return 0;
}
Loading