Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
837e9fa
Implement draft-ietf-quic-qmux-01
masa-koz Apr 26, 2026
c3b44b1
Improve sending code
masa-koz May 5, 2026
d91f9e0
Improve receiving code
masa-koz May 5, 2026
c76eae9
refactoring TLS API
masa-koz May 5, 2026
efd3c82
refactoring TLS API
masa-koz May 5, 2026
889af0e
refactoring TLS API
masa-koz May 5, 2026
4b6b25c
cleanup
masa-koz May 5, 2026
fd56bdf
fix for windows
masa-koz May 5, 2026
0275f94
WIP in schannel
masa-koz May 6, 2026
5e70ee3
schannel for QMux works
masa-koz May 7, 2026
df9098a
fix openssl for latest API change
masa-koz May 7, 2026
a3ef139
handle connect error correctly
masa-koz May 7, 2026
d42a322
fix for linux
masa-koz May 7, 2026
9a451a4
copy a correct address when QMux is used
masa-koz May 7, 2026
45db8b4
use %I64u
masa-koz May 7, 2026
3fcc98e
use PRIu64
masa-koz May 7, 2026
2be39bf
free encode TP
masa-koz May 7, 2026
17b1460
delete unnecessary uninitialization
masa-koz May 7, 2026
41d1485
add missing uninitialization
masa-koz May 7, 2026
ff7b0d8
delete its own initializer
masa-koz May 7, 2026
7ff8bdc
set ALPN correctly
masa-koz May 8, 2026
55d9b9a
rename,etc
masa-koz May 8, 2026
558a56b
WIP in quictls
masa-koz May 8, 2026
bf8adf8
QMux by openssl works
masa-koz May 8, 2026
db160aa
fix for CI
masa-koz May 8, 2026
f06b5c1
fix for CI
masa-koz May 8, 2026
f6a20d0
revert change in CxPlatTlsProcessData
masa-koz May 8, 2026
1ef8b90
clog
masa-koz May 8, 2026
9509354
fix in MsQuicEtw.man
masa-koz May 8, 2026
c01965d
Merge remote-tracking branch 'origin/main' into masa-koz/qmux-01
masa-koz May 8, 2026
e5849b1
support resumption and early data
masa-koz May 10, 2026
8df260a
change for Rust ffi and a nit fix
masa-koz May 10, 2026
7adc417
rename variables, add comment, fix nits
masa-koz May 13, 2026
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
1 change: 1 addition & 0 deletions scripts/clog.inputs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
../src/core/configuration.c
../src/core/partition.c
../src/core/library.c
../src/core/qmux.c
../src/bin/winuser_fuzz/dllmain.c
../src/bin/linux/init.c
../src/bin/winuser/dllmain.c
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ set(SOURCES
packet_builder.c
packet_space.c
path.c
qmux.c
range.c
recv_buffer.c
registration.c
Expand Down
119 changes: 118 additions & 1 deletion src/core/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,122 @@ MsQuicConnectionOpenInPartition(
NewConnection);
}

_IRQL_requires_max_(DISPATCH_LEVEL)
QUIC_STATUS
QUIC_API
QuicConnectionQmuxOpenInPartition(
_In_ _Pre_defensive_ HQUIC RegistrationHandle,
_In_ uint16_t PartitionIndex,
_In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler,
_In_opt_ void* Context,
_In_ BOOLEAN Partitioned,
_Outptr_ _At_(*NewConnection, __drv_allocatesMem(Mem)) _Pre_defensive_
HQUIC *NewConnection
)
{
QUIC_STATUS Status;
QUIC_REGISTRATION* Registration;
QUIC_CONNECTION* Connection = NULL;

QuicTraceEvent(
ApiEnter,
"[ api] Enter %u (%p).",
QUIC_TRACE_API_CONNECTION_OPEN,
RegistrationHandle);

if (!IS_REGISTRATION_HANDLE(RegistrationHandle) ||
PartitionIndex >= MsQuicLib.PartitionCount ||
NewConnection == NULL ||
Handler == NULL) {
Status = QUIC_STATUS_INVALID_PARAMETER;
goto Error;
}

#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.")
Registration = (QUIC_REGISTRATION*)RegistrationHandle;

//
// Just use the current partition for now. Once the connection receives a
// packet the partition can be updated accordingly.
//
Status =
QuicConnQMuxAlloc(
Registration,
&MsQuicLib.Partitions[PartitionIndex],
NULL,
FALSE,
&Connection);
if (QUIC_FAILED(Status)) {
goto Error;
}

//
// Hard partitioning is only supported on a subset of platforms.
//
#if defined(__linux__) && !defined(CXPLAT_USE_IO_URING)
Connection->State.Partitioned = Partitioned;
#else
UNREFERENCED_PARAMETER(Partitioned);
#endif
Connection->ClientCallbackHandler = Handler;
Connection->ClientContext = Context;

*NewConnection = (HQUIC)Connection;
Status = QUIC_STATUS_SUCCESS;

Error:

QuicTraceEvent(
ApiExitStatus,
"[ api] Exit %u",
Status);

return Status;
}

_IRQL_requires_max_(DISPATCH_LEVEL)
QUIC_STATUS
QUIC_API
MsQuicConnectionQmuxOpen(
_In_ _Pre_defensive_ HQUIC RegistrationHandle,
_In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler,
_In_opt_ void* Context,
_Outptr_ _At_(*NewConnection, __drv_allocatesMem(Mem)) _Pre_defensive_
HQUIC *NewConnection
)
{
return
QuicConnectionQmuxOpenInPartition(
RegistrationHandle,
QuicLibraryGetCurrentPartition()->Index,
Handler,
Context,
FALSE,
NewConnection);
}

_IRQL_requires_max_(DISPATCH_LEVEL)
QUIC_STATUS
QUIC_API
MsQuicConnectionQmuxOpenInPartition(
_In_ _Pre_defensive_ HQUIC RegistrationHandle,
_In_ uint16_t PartitionIndex,
_In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler,
_In_opt_ void* Context,
_Outptr_ _At_(*NewConnection, __drv_allocatesMem(Mem)) _Pre_defensive_
HQUIC *NewConnection
)
{
return
QuicConnectionQmuxOpenInPartition(
RegistrationHandle,
PartitionIndex,
Handler,
Context,
TRUE,
NewConnection);
}

#pragma warning(push)
#pragma warning(disable:6014) // SAL doesn't understand the free happens on the worker
_IRQL_requires_max_(PASSIVE_LEVEL)
Expand Down Expand Up @@ -620,7 +736,8 @@ MsQuicConnectionSendResumptionTicket(

if (!Connection->State.ResumptionEnabled ||
!Connection->State.Connected ||
!Connection->Crypto.TlsState.HandshakeComplete) {
(!QuicConnIsQMux(Connection) && !Connection->Crypto.TlsState.HandshakeComplete) ||
(QuicConnIsQMux(Connection) && !QuicConnGetQMux(Connection)->TlsState.HandshakeComplete)) {
Status = QUIC_STATUS_INVALID_STATE; // TODO - Support queueing up the ticket to send once connected.
goto Error;
}
Expand Down
34 changes: 34 additions & 0 deletions src/core/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,17 @@ MsQuicListenerOpen(
HQUIC *Listener
);

_IRQL_requires_max_(PASSIVE_LEVEL)
QUIC_STATUS
QUIC_API
MsQuicListenerQmuxOpen(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we will want to avoid these API change.
QMux should be useable by the app transparently, with some initial configuration to enable it, but using the usual APIs for everything else.

We currently have some work that also involve underlying transport configuration and should define how we want this config to look like.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I largely agree with the direction of avoiding API changes and keeping QMux transparent to applications, with only minimal initial configuration.

However, I think there are some cases where we need to decide in advance whether we are using regular QUIC or QMux. In particular, for cryptographic operations, regular QUIC relies on the built-in QUIC crypto mechanisms, whereas QMux would handle these aspects differently within its own layer.

This could become problematic when configuration must be done prior to connection start. For example, settings related to resumption tickets or other crypto-related parameters may depend on whether the underlying transport is standard QUIC or QMux. If that distinction is not known early enough, it may be unclear how or where such configurations should be applied.

So while I agree with keeping the APIs unified, we may need to consider how to handle these pre-start configurations in a way that accounts for the transport differences.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's the challenge. Our current thinking is to add some more configuration at the registration level to decide which underlying transport to use. We are looking for something flexible enough to allow for a variety of underlying transport configurations. But that is early thinking.

_In_ _Pre_defensive_ HQUIC Registration,
_In_ _Pre_defensive_ QUIC_LISTENER_CALLBACK_HANDLER Handler,
_In_opt_ void* Context,
_Outptr_ _At_(*Listener, __drv_allocatesMem(Mem)) _Pre_defensive_
HQUIC *Listener
);

_IRQL_requires_max_(PASSIVE_LEVEL)
void
QUIC_API
Expand Down Expand Up @@ -166,6 +177,29 @@ MsQuicConnectionOpenInPartition(
HQUIC *Connection
);

_IRQL_requires_max_(DISPATCH_LEVEL)
QUIC_STATUS
QUIC_API
MsQuicConnectionQmuxOpen(
_In_ _Pre_defensive_ HQUIC RegistrationHandle,
_In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler,
_In_opt_ void* Context,
_Outptr_ _At_(*NewConnection, __drv_allocatesMem(Mem)) _Pre_defensive_
HQUIC *NewConnection
);

_IRQL_requires_max_(DISPATCH_LEVEL)
QUIC_STATUS
QUIC_API
MsQuicConnectionQmuxOpenInPartition(
_In_ _Pre_defensive_ HQUIC RegistrationHandle,
_In_ uint16_t PartitionIndex,
_In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler,
_In_opt_ void* Context,
_Outptr_ _At_(*NewConnection, __drv_allocatesMem(Mem)) _Pre_defensive_
HQUIC *NewConnection
);

_IRQL_requires_max_(PASSIVE_LEVEL)
void
QUIC_API
Expand Down
Loading