diff --git a/docs/API.md b/docs/API.md index 93c2ffdeef..3dcfc4fab2 100644 --- a/docs/API.md +++ b/docs/API.md @@ -33,9 +33,7 @@ The API supports both server and client applications. All functionality is expos [**Registration**](#registration) – Manages the execution context for all child objects. An app may open multiple registrations but ideally should only open one. -[**Security Configuration**](#security-configuration) – Abstracts the configuration for the TLS component. This primarily consists of a certificate that is used for authentication. The app may create as many of these as necessary. - -[**Session**](#session) – Abstracts several different session-layer concepts: TLS Session Resumption, Application Layer Protocol Negotiation (ALPN) and platform specifics (such as Server Silo and Network Compartment ID on Windows). The app may create as many of these as necessary. +[**Configuration**](#configuration) – Abstracts the configuration for a connection. TODO [**Listener**](#listener) – Server side only, this object provides the interface for an app to accept incoming connections from clients. Once the connection has been accepted, it is independent of the listener. The app may create as many of these as necessary. @@ -88,17 +86,11 @@ Generally, each app only needs a single registration. The registration represent A registration is created by calling [RegistrationOpen](api/RegistrationOpen.md) and deleted by calling [RegistrationClose](api/RegistrationClose.md). -## Security Configuration - -Currently only used on the server side, the security configuration (AKA security config) abstracts a server certificate (and other configuration) used by a [listener](#listener) to accept an incoming connection request. - -A security config is created by calling [SecConfigCreate](api/SecConfigCreate.md) and deleted by calling [SecConfigDelete](api/SecConfigDelete.md). - -## Session +## Configuration -An app must create a session before it can create any listeners or connections. Each session maintains certain transport and platform state common to all child handles. Primarily, this consists of the ALPN string used for the connection handshakes and TLS state used for session resumption. On Windows platforms it also inherits the Silo and Network Compartment ID from the thread that creates it. +TODO -A session is created by calling [SessionOpen](api/SessionOpen.md) and deleted by calling [SessionClose](api/SessionClose.md). [SessionClose](api/SessionClose.md) **will block** on all oustanding connections. Therefore do not call it on any MsQuic event callback, as it will likely create a deadlock. +A configuration is created by calling [ConfigurationOpen](api/ConfigurationOpen.md) and deleted by calling [ConfigurationClose](api/ConfigurationClose.md). ## Listener diff --git a/docs/api/ConfigurationClose.md b/docs/api/ConfigurationClose.md new file mode 100644 index 0000000000..329c7c15d0 --- /dev/null +++ b/docs/api/ConfigurationClose.md @@ -0,0 +1,29 @@ +ConfigurationClose function +====== + +Deletes an existing security configuration. + +# Syntax + +```C +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +void +(QUIC_API * QUIC_CONFIGURATION_CLOSE_FN)( + _In_ _Pre_defensive_ __drv_freesMem(Mem) + HQUIC Configuration + ); +``` + +# Parameters + +**TODO** + +# Remarks + +**TODO** + +# See Also + +[ConfigurationOpen](ConfigurationOpen.md)
+[ConfigurationLoadCredential](ConfigurationLoadCredential.md)
diff --git a/docs/api/ConfigurationLoadCredential.md b/docs/api/ConfigurationLoadCredential.md new file mode 100644 index 0000000000..abd557cf2f --- /dev/null +++ b/docs/api/ConfigurationLoadCredential.md @@ -0,0 +1,29 @@ +ConfigurationLoadCredential function +====== + +Deletes an existing configuration. + +# Syntax + +```C +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +(QUIC_API * QUIC_CONFIGURATION_LOAD_CREDENTIAL_FN)( + _In_ _Pre_defensive_ HQUIC Configuration, + _In_ _Pre_defensive_ const QUIC_CREDENTIAL_CONFIG* CredConfig + ); +``` + +# Parameters + +**TODO** + +# Remarks + +**TODO** + +# See Also + +[ConfigurationOpen](ConfigurationOpen.md)
+[ConfigurationClose](ConfigurationClose.md)
diff --git a/docs/api/ConfigurationOpen.md b/docs/api/ConfigurationOpen.md new file mode 100644 index 0000000000..c04eb78e21 --- /dev/null +++ b/docs/api/ConfigurationOpen.md @@ -0,0 +1,45 @@ +ConfigurationOpen function +====== + +Creates a new configuration. + +# Syntax + +```C +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +(QUIC_API * QUIC_CONFIGURATION_OPEN_FN)( + _In_ _Pre_defensive_ HQUIC Registration, + _In_reads_(AlpnBufferCount) _Pre_defensive_ + const QUIC_BUFFER* const AlpnBuffers, + _In_range_(>, 0) uint32_t AlpnBufferCount, + _In_reads_bytes_opt_(SettingsSize) + const QUIC_SETTINGS* Settings, + _In_ uint32_t SettingsSize, + _In_opt_ void* Context, + _Outptr_ _At_(*Configuration, __drv_allocatesMem(Mem)) _Pre_defensive_ + HQUIC* Configuration + ); +``` + +# Parameters + +`Registration` + +The valid handle to an open registration object. + +**TODO** + +# Return Value + +The function returns a [QUIC_STATUS](QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded. + +# Remarks + +**TODO** + +# See Also + +[ConfigurationClose](ConfigurationClose.md)
+[ConfigurationLoadCredential](ConfigurationLoadCredential.md)
diff --git a/docs/api/ConnectionOpen.md b/docs/api/ConnectionOpen.md index 16c8ffe6a1..d73876c033 100644 --- a/docs/api/ConnectionOpen.md +++ b/docs/api/ConnectionOpen.md @@ -10,7 +10,8 @@ typedef _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS (QUIC_API * QUIC_CONNECTION_OPEN_FN)( - _In_ _Pre_defensive_ HQUIC Session, + _In_ _Pre_defensive_ HQUIC Registration, + _In_ _Pre_defensive_ HQUIC Configuration, _In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler, _In_opt_ void* Context, _Outptr_ _At_(*Connection, __drv_allocatesMem(Mem)) _Pre_defensive_ @@ -20,9 +21,13 @@ QUIC_STATUS # Parameters -`Session` +`Registration` -The valid handle to an open session object. +The valid handle to an open registration object. + +`Configuration` + +The valid handle to an open configuration object. `Handler` diff --git a/docs/api/GetContext.md b/docs/api/GetContext.md index 5bdc32ab01..5af898f84d 100644 --- a/docs/api/GetContext.md +++ b/docs/api/GetContext.md @@ -18,7 +18,7 @@ void* `Handle` -The valid handle to any API object. This includes handles to registration, session, listener, connection and stream objects. +The valid handle to any API object. This includes handles to registration, configuration, listener, connection and stream objects. # Return Value diff --git a/docs/api/GetParam.md b/docs/api/GetParam.md index 8a02b953e3..6722d9b93f 100644 --- a/docs/api/GetParam.md +++ b/docs/api/GetParam.md @@ -25,7 +25,7 @@ QUIC_STATUS `Handle` -The valid handle to any API object. This includes handles to registration, session, listener, connection and stream objects. For `Level` equal to `QUIC_PARAM_LEVEL_GLOBAL`, this parameter must be `NULL`. +The valid handle to any API object. This includes handles to registration, configuration, listener, connection and stream objects. For `Level` equal to `QUIC_PARAM_LEVEL_GLOBAL`, this parameter must be `NULL`. `Level` diff --git a/docs/api/ListenerOpen.md b/docs/api/ListenerOpen.md index a2ce981ed6..0421413d11 100644 --- a/docs/api/ListenerOpen.md +++ b/docs/api/ListenerOpen.md @@ -10,7 +10,7 @@ typedef _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS (QUIC_API * QUIC_LISTENER_OPEN_FN)( - _In_ _Pre_defensive_ HQUIC Session, + _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_ diff --git a/docs/api/ListenerStart.md b/docs/api/ListenerStart.md index 07128762c2..f906f5cf6b 100644 --- a/docs/api/ListenerStart.md +++ b/docs/api/ListenerStart.md @@ -11,6 +11,9 @@ _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS (QUIC_API * QUIC_LISTENER_START_FN)( _In_ _Pre_defensive_ HQUIC Listener, + _In_reads_(AlpnBufferCount) _Pre_defensive_ + const QUIC_BUFFER* const AlpnBuffers, + _In_range_(>, 0) uint32_t AlpnBufferCount, _In_opt_ const QUIC_ADDR* LocalAddress ); ``` diff --git a/docs/api/QUIC_API_TABLE.md b/docs/api/QUIC_API_TABLE.md index dade7a12d0..aefbdc5107 100644 --- a/docs/api/QUIC_API_TABLE.md +++ b/docs/api/QUIC_API_TABLE.md @@ -17,13 +17,12 @@ typedef struct QUIC_API_TABLE { QUIC_REGISTRATION_OPEN_FN RegistrationOpen; QUIC_REGISTRATION_CLOSE_FN RegistrationClose; + QUIC_REGISTRATION_SHUTDOWN_FN RegistrationShutdown; - QUIC_SEC_CONFIG_CREATE_FN SecConfigCreate; - QUIC_SEC_CONFIG_DELETE_FN SecConfigDelete; - - QUIC_SESSION_OPEN_FN SessionOpen; - QUIC_SESSION_CLOSE_FN SessionClose; - QUIC_SESSION_SHUTDOWN_FN SessionShutdown; + QUIC_CONFIGURATION_OPEN_FN ConfigurationOpen; + QUIC_CONFIGURATION_CLOSE_FN ConfigurationClose; + QUIC_CONFIGURATION_LOAD_CREDENTIAL_FN + ConfigurationLoadCredential; QUIC_LISTENER_OPEN_FN ListenerOpen; QUIC_LISTENER_CLOSE_FN ListenerClose; @@ -34,6 +33,7 @@ typedef struct QUIC_API_TABLE { QUIC_CONNECTION_CLOSE_FN ConnectionClose; QUIC_CONNECTION_SHUTDOWN_FN ConnectionShutdown; QUIC_CONNECTION_START_FN ConnectionStart; + QUIC_CONNECTION_SEND_RESUMPTION_FN ConnectionSendResumptionTicket; QUIC_STREAM_OPEN_FN StreamOpen; QUIC_STREAM_CLOSE_FN StreamClose; @@ -78,25 +78,21 @@ See [RegistrationOpen](RegistrationOpen.md) See [RegistrationClose](RegistrationClose.md) -`SecConfigCreate` - -See [SecConfigCreate](SecConfigCreate.md) - -`SecConfigDelete` +`RegistrationShutdown` -See [SecConfigDelete](SecConfigDelete.md) +See [RegistrationShutdown](RegistrationShutdown.md) -`SessionOpen` +`ConfigurationOpen` -See [SessionOpen](SessionOpen.md) +See [ConfigurationOpen](ConfigurationOpen.md) -`SessionClose` +`ConfigurationClose` -See [SessionClose](SessionClose.md) +See [ConfigurationClose](ConfigurationClose.md) -`SessionShutdown` +`ConfigurationLoadCredential` -See [SessionShutdown](SessionShutdown.md) +See [ConfigurationLoadCredential](ConfigurationLoadCredential.md) `ListenerOpen` diff --git a/docs/api/RegistrationClose.md b/docs/api/RegistrationClose.md index ef0c6e17c7..26c828a4b2 100644 --- a/docs/api/RegistrationClose.md +++ b/docs/api/RegistrationClose.md @@ -23,7 +23,7 @@ A registration handle from a previous call to [RegistrationOpen](RegistrationOpe # Remarks -The application **must** close/delete all child security configurations and session objects before closing the registration. This call **will block** on those outstanding objects being cleaned up. Do no call it on any MsQuic event callback, or it will deadlock. +The application **must** close/delete all child configurations and connection objects before closing the registration. This call **will block** on those outstanding objects being cleaned up. Do no call it on any MsQuic event callback, or it will deadlock. # See Also diff --git a/docs/api/SessionShutdown.md b/docs/api/RegistrationShutdown.md similarity index 64% rename from docs/api/SessionShutdown.md rename to docs/api/RegistrationShutdown.md index 6901e20d47..66abc9f5f7 100644 --- a/docs/api/SessionShutdown.md +++ b/docs/api/RegistrationShutdown.md @@ -1,16 +1,16 @@ -SessionShutdown function +RegistrationShutdown function ====== -Starts the shutdown process for all connections in the session. +Starts the shutdown process for all connections in the registration. # Syntax ```C typedef -_IRQL_requires_max_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) void -(QUIC_API * QUIC_SESSION_SHUTDOWN_FN)( - _In_ _Pre_defensive_ HQUIC Session, +(QUIC_API * QUIC_REGISTRATION_SHUTDOWN_FN)( + _In_ _Pre_defensive_ HQUIC Registration, _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, _In_ _Pre_defensive_ QUIC_UINT62 ErrorCode // Application defined error code ); @@ -18,9 +18,9 @@ void # Parameters -`Session` +`Registration` -The valid handle to an open session object. +The valid handle to an open registration object. `Flags` @@ -41,6 +41,6 @@ The 62-bit error code to indicate to the peer as the reason for the shutdown. # See Also -[SessionOpen](SessionOpen.md)
-[SessionClose](SessionClose.md)
+[RegistrationOpen](RegistrationOpen.md)
+[RegistrationClose](RegistrationClose.md)
[ConnectionShutdown](ConnectionShutdown.md)
diff --git a/docs/api/SecConfigCreate.md b/docs/api/SecConfigCreate.md deleted file mode 100644 index a296e00abb..0000000000 --- a/docs/api/SecConfigCreate.md +++ /dev/null @@ -1,67 +0,0 @@ -SecConfigCreate function -====== - -Asynchronously creates a new security configuration. - -# Syntax - -```C -typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -(QUIC_API * QUIC_SEC_CONFIG_CREATE_FN)( - _In_ _Pre_defensive_ HQUIC Registration, - _In_ QUIC_SEC_CONFIG_FLAGS Flags, - _In_opt_ void* Certificate, - _In_opt_z_ const char* Principal, - _In_opt_ void* Context, - _In_ _Pre_defensive_ - QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER CompletionHandler - ); -``` - -# Parameters - -`Registration` - -The valid handle to an open registration object. - -`Flags` - -The flags that control the type of the structure passed into the *Certificate* parameter. - -Value | Meaning ---- | --- -**QUIC_SEC_CONFIG_FLAG_CERTIFICATE_HASH**
0x00000001 | The *Certificate* parameter points to a `QUIC_CERTIFICATE_HASH` struct. -**QUIC_SEC_CONFIG_FLAG_CERTIFICATE_HASH_STORE**
0x00000002 | The *Certificate* parameter points to a `QUIC_CERTIFICATE_HASH_STORE` struct. -**QUIC_SEC_CONFIG_FLAG_CERTIFICATE_CONTEXT**
0x00000004 | The *Certificate* parameter points to a `PCCERT_CONTEXT` (Windows specific) struct. -**QUIC_SEC_CONFIG_FLAG_CERTIFICATE_FILE**
0x00000008 | The *Certificate* parameter points to a `QUIC_CERTIFICATE_FILE` struct. -**QUIC_SEC_CONFIG_FLAG_ENABLE_OCSP**
0x000000010 | This option can be used in conjunction with the above, and enables the Online Certificate Status Protocol (OCSP). - -`Certificate` - -A pointer to a certificate configuration struct whos type is determined by the *Flags* field. - -`Principal` - -An optional pointer, to a null-terminated string that specifies the name of the principal whose credentials the security config will reference. - -`Context` - -The app context pointer to be passed back into the *CompletionHandler*. - -`CompletionHandler` - -A pointer to the app's callback handler to be executed when the security config creation has completed. - -# Return Value - -The function returns a [QUIC_STATUS](QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded. - -# Remarks - -**TODO** - -# See Also - -[SecConfigDelete](SecConfigDelete.md)
diff --git a/docs/api/SecConfigDelete.md b/docs/api/SecConfigDelete.md deleted file mode 100644 index 2be53d0cfb..0000000000 --- a/docs/api/SecConfigDelete.md +++ /dev/null @@ -1,27 +0,0 @@ -SecConfigDelete function -====== - -Deletes an existing security configuration. - -# Syntax - -```C -typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -void -(QUIC_API * QUIC_SEC_CONFIG_DELETE_FN)( - _In_ _Pre_defensive_ QUIC_SEC_CONFIG* SecurityConfig - ); -``` - -# Parameters - -**TODO** - -# Remarks - -**TODO** - -# See Also - -[SecConfigCreate](SecConfigCreate.md)
diff --git a/docs/api/SessionClose.md b/docs/api/SessionClose.md deleted file mode 100644 index 052c197d30..0000000000 --- a/docs/api/SessionClose.md +++ /dev/null @@ -1,31 +0,0 @@ -SessionClose function -====== - -Closes an existing session. - -# Syntax - -```C -typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -void -(QUIC_API * QUIC_SESSION_CLOSE_FN)( - _In_ _Pre_defensive_ __drv_freesMem(Mem) - HQUIC Session - ); -``` - -# Parameters - -`Session` - -The valid handle to an open session object. - -# Remarks - -**TODO** - -# See Also - -[SessionOpen](SessionOpen.md)
-[SessionShutdown](SessionShutdown.md)
diff --git a/docs/api/SessionOpen.md b/docs/api/SessionOpen.md deleted file mode 100644 index 6a8af8fc79..0000000000 --- a/docs/api/SessionOpen.md +++ /dev/null @@ -1,60 +0,0 @@ -SessionOpen function -====== - -Creates a new session. - -# Syntax - -```C -typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -(QUIC_API * QUIC_SESSION_OPEN_FN)( - _In_ _Pre_defensive_ HQUIC Registration, - _In_ uint32_t SettingsSize, - _In_reads_bytes_opt_(SettingsSize) - const QUIC_SETTINGS* Settings, - _In_reads_(AlpnBufferCount) _Pre_defensive_ - const QUIC_BUFFER* const AlpnBuffers, - _In_range_(>, 0) uint32_t AlpnBufferCount, - _In_opt_ void* Context, - _Outptr_ _At_(*Session, __drv_allocatesMem(Mem)) _Pre_defensive_ - HQUIC* Session - ); -``` - -# Parameters - -`Registration` - -The valid handle to an open registration object. - -`AlpnBuffers` - -A contiguous array of QUIC_BUFFERs containing all the Application-Layer Protocol Negotiation (ALPN) buffers. - -`AlpnBufferCount` - -The number of QUIC_BUFFERS in the AlpnBuffers array. - -`Context` - -The app context pointer to be associated with the session object. - -`Connection` - -On success, returns a handle to the newly opened session object. - - -# Return Value - -The function returns a [QUIC_STATUS](../api/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded. - -# Remarks - -**TODO** - -# See Also - -[SessionClose](SessionClose.md)
-[SessionShutdown](SessionShutdown.md)
diff --git a/docs/api/SetContext.md b/docs/api/SetContext.md index ecca458772..d7af73f43e 100644 --- a/docs/api/SetContext.md +++ b/docs/api/SetContext.md @@ -19,7 +19,7 @@ void `Handle` -The valid handle to any API object. This includes handles to registration, session, listener, connection and stream objects. +The valid handle to any API object. This includes handles to registration, configuration, listener, connection and stream objects. `Context` diff --git a/docs/api/SetParam.md b/docs/api/SetParam.md index 3cf5cf947d..606619fe83 100644 --- a/docs/api/SetParam.md +++ b/docs/api/SetParam.md @@ -25,7 +25,7 @@ QUIC_STATUS `Handle` -The valid handle to any API object. This includes handles to registration, session, listener, connection and stream objects. For `Level` equal to `QUIC_PARAM_LEVEL_GLOBAL`, this parameter must be `NULL`. +The valid handle to any API object. This includes handles to registration, configuration, listener, connection and stream objects. For `Level` equal to `QUIC_PARAM_LEVEL_GLOBAL`, this parameter must be `NULL`. `Level` diff --git a/scripts/update-sidecar.ps1 b/scripts/update-sidecar.ps1 new file mode 100644 index 0000000000..ce760f3d5f --- /dev/null +++ b/scripts/update-sidecar.ps1 @@ -0,0 +1,39 @@ +<# + +.SYNOPSIS +This updates/regenerates the CLOG sidecar file. + +.PARAMETER Clean + Deletes the old sidecar file first. + +#> + +param ( + [Parameter(Mandatory = $false)] + [switch]$Clean = $false +) + +Set-StrictMode -Version 'Latest' +$PSDefaultParameterValues['*:ErrorAction'] = 'Stop' + +$RootDir = Split-Path $PSScriptRoot -Parent +$SrcDir = Join-Path $RootDir "src" + +$Files = Get-ChildItem -Path "$SrcDir\*" -Recurse -Include *.c,*.h,*.cpp,*.hpp -File + +$Sidecar = Join-Path $SrcDir "manifest" "clog.sidecar" +$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 | Out-Null +} + +foreach ($File in $Files) { + clog -p windows --scopePrefix "QUIC" -s $Sidecar -c $ConfigFile -i $File --outputDirectory "$OutputDir" + clog -p windows_kernel --scopePrefix "QUIC" -s $Sidecar -c $ConfigFile -i $File --outputDirectory "$OutputDir" + clog -p stubs --scopePrefix "QUIC" -s $Sidecar -c $ConfigFile -i $File --outputDirectory "$OutputDir" + clog -p linux --scopePrefix "QUIC" -s $Sidecar -c $ConfigFile -i $File --outputDirectory "$OutputDir" +} diff --git a/src/bin/winkernel/pgo_x64/msquic.pgd b/src/bin/winkernel/pgo_x64/msquic.pgd index 7a4816d49b..b8290eca94 100644 Binary files a/src/bin/winkernel/pgo_x64/msquic.pgd and b/src/bin/winkernel/pgo_x64/msquic.pgd differ diff --git a/src/bin/winuser/pgo_x64/msquic.pgd b/src/bin/winuser/pgo_x64/msquic.pgd index 7a4816d49b..b8290eca94 100644 Binary files a/src/bin/winuser/pgo_x64/msquic.pgd and b/src/bin/winuser/pgo_x64/msquic.pgd differ diff --git a/src/bin/winuser/pgo_x86/msquic.pgd b/src/bin/winuser/pgo_x86/msquic.pgd index 00162791e1..42189dd6e2 100644 Binary files a/src/bin/winuser/pgo_x86/msquic.pgd and b/src/bin/winuser/pgo_x86/msquic.pgd differ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5c1e86783f..119a99c5a4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES ack_tracker.c api.c binding.c + configuration.c congestion_control.c connection.c crypto.c @@ -26,7 +27,6 @@ set(SOURCES send.c send_buffer.c sent_packet_metadata.c - session.c settings.c stream.c stream_recv.c diff --git a/src/core/api.c b/src/core/api.c index c13300a782..6fb64b00ba 100644 --- a/src/core/api.c +++ b/src/core/api.c @@ -14,9 +14,9 @@ #include "api.c.clog.h" #endif -#define IS_SESSION_HANDLE(Handle) \ +#define IS_REGISTRATION_HANDLE(Handle) \ ( \ - (Handle) != NULL && (Handle)->Type == QUIC_HANDLE_TYPE_SESSION \ + (Handle) != NULL && (Handle)->Type == QUIC_HANDLE_TYPE_REGISTRATION \ ) #define IS_CONN_HANDLE(Handle) \ @@ -34,7 +34,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS QUIC_API MsQuicConnectionOpen( - _In_ _Pre_defensive_ HQUIC SessionHandle, + _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_ @@ -42,16 +42,16 @@ MsQuicConnectionOpen( ) { QUIC_STATUS Status; - QUIC_SESSION* Session; + QUIC_REGISTRATION* Registration; QUIC_CONNECTION* Connection = NULL; QuicTraceEvent( ApiEnter, "[ api] Enter %u (%p).", QUIC_TRACE_API_CONNECTION_OPEN, - SessionHandle); + RegistrationHandle); - if (!IS_SESSION_HANDLE(SessionHandle) || + if (!IS_REGISTRATION_HANDLE(RegistrationHandle) || NewConnection == NULL || Handler == NULL) { Status = QUIC_STATUS_INVALID_PARAMETER; @@ -59,9 +59,9 @@ MsQuicConnectionOpen( } #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") - Session = (QUIC_SESSION*)SessionHandle; + Registration = (QUIC_REGISTRATION*)RegistrationHandle; - if ((Connection = QuicConnAlloc(Session, NULL)) == NULL) { + if ((Connection = QuicConnAlloc(Registration, NULL)) == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; goto Error; } @@ -69,7 +69,7 @@ MsQuicConnectionOpen( Connection->ClientCallbackHandler = Handler; Connection->ClientContext = Context; - QuicRegistrationQueueNewConnection(Session->Registration, Connection); + QuicRegistrationQueueNewConnection(Registration, Connection); *NewConnection = (HQUIC)Connection; Status = QUIC_STATUS_SUCCESS; @@ -238,6 +238,7 @@ QUIC_STATUS QUIC_API MsQuicConnectionStart( _In_ _Pre_defensive_ HQUIC Handle, + _In_ _Pre_defensive_ HQUIC ConfigHandle, _In_ QUIC_ADDRESS_FAMILY Family, _In_reads_opt_z_(QUIC_MAX_SNI_LENGTH) const char* ServerName, @@ -246,6 +247,7 @@ MsQuicConnectionStart( { QUIC_STATUS Status; QUIC_CONNECTION* Connection; + QUIC_CONFIGURATION* Configuration; QUIC_OPERATION* Oper; char* ServerNameCopy = NULL; @@ -257,7 +259,9 @@ MsQuicConnectionStart( QUIC_TRACE_API_CONNECTION_START, Handle); - if (ServerPort == 0) { + if (ConfigHandle == NULL || + ConfigHandle->Type != QUIC_HANDLE_TYPE_CONFIGURATION || + ServerPort == 0) { Status = QUIC_STATUS_INVALID_PARAMETER; goto Error; } @@ -299,6 +303,13 @@ MsQuicConnectionStart( goto Error; } + Configuration = (QUIC_CONFIGURATION*)ConfigHandle; + + if (Configuration->SecurityConfig == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + if (ServerName != NULL) { // // Validate the server name length. @@ -340,7 +351,10 @@ MsQuicConnectionStart( 0); goto Error; } + + QuicConfigurationAddRef(Configuration); Oper->API_CALL.Context->Type = QUIC_API_TYPE_CONN_START; + Oper->API_CALL.Context->CONN_START.Configuration = Configuration; Oper->API_CALL.Context->CONN_START.ServerName = ServerNameCopy; Oper->API_CALL.Context->CONN_START.ServerPort = ServerPort; Oper->API_CALL.Context->CONN_START.Family = Family; @@ -366,6 +380,99 @@ MsQuicConnectionStart( return Status; } +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +QUIC_API +MsQuicConnectionSetConfiguration( + _In_ _Pre_defensive_ HQUIC Handle, + _In_ _Pre_defensive_ HQUIC ConfigHandle + ) +{ + QUIC_STATUS Status; + QUIC_CONNECTION* Connection; + QUIC_CONFIGURATION* Configuration; + QUIC_OPERATION* Oper; + + QUIC_PASSIVE_CODE(); + + QuicTraceEvent( + ApiEnter, + "[ api] Enter %u (%p).", + QUIC_TRACE_API_CONNECTION_SET_CONFIGURATION, + Handle); + + if (ConfigHandle == NULL || + ConfigHandle->Type != QUIC_HANDLE_TYPE_CONFIGURATION) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + + if (IS_CONN_HANDLE(Handle)) { +#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") + Connection = (QUIC_CONNECTION*)Handle; + } else if (IS_STREAM_HANDLE(Handle)) { +#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") + QUIC_STREAM* Stream = (QUIC_STREAM*)Handle; + QUIC_TEL_ASSERT(!Stream->Flags.HandleClosed); + QUIC_TEL_ASSERT(!Stream->Flags.Freed); + Connection = Stream->Connection; + } else { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + + QUIC_CONN_VERIFY(Connection, !Connection->State.Freed); + + if (!QuicConnIsServer(Connection)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + + if (Connection->Configuration != NULL) { + Status = QUIC_STATUS_INVALID_STATE; + goto Error; + } + + Configuration = (QUIC_CONFIGURATION*)ConfigHandle; + + if (Configuration->SecurityConfig == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + + QUIC_CONN_VERIFY(Connection, !Connection->State.HandleClosed); + QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + Oper = QuicOperationAlloc(Connection->Worker, QUIC_OPER_TYPE_API_CALL); + if (Oper == NULL) { + Status = QUIC_STATUS_OUT_OF_MEMORY; + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "CONN_SET_CONFIGURATION operation", + 0); + goto Error; + } + + QuicConfigurationAddRef(Configuration); + Oper->API_CALL.Context->Type = QUIC_API_TYPE_CONN_SET_CONFIGURATION; + Oper->API_CALL.Context->CONN_SET_CONFIGURATION.Configuration = Configuration; + + // + // Queue the operation but don't wait for the completion. + // + QuicConnQueueOper(Connection, Oper); + Status = QUIC_STATUS_PENDING; + +Error: + + QuicTraceEvent( + ApiExitStatus, + "[ api] Exit %u", + Status); + + return Status; +} + _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS QUIC_API @@ -1195,10 +1302,10 @@ MsQuicSetParam( } if (Handle->Type == QUIC_HANDLE_TYPE_REGISTRATION || - Handle->Type == QUIC_HANDLE_TYPE_SESSION || + Handle->Type == QUIC_HANDLE_TYPE_CONFIGURATION || Handle->Type == QUIC_HANDLE_TYPE_LISTENER) { // - // Registration, Session and Listener parameters are processed inline. + // Registration, Configuration and Listener parameters are processed inline. // Status = QuicLibrarySetParam(Handle, Level, Param, BufferLength, Buffer); goto Error; @@ -1306,10 +1413,10 @@ MsQuicGetParam( } if (Handle->Type == QUIC_HANDLE_TYPE_REGISTRATION || - Handle->Type == QUIC_HANDLE_TYPE_SESSION || + Handle->Type == QUIC_HANDLE_TYPE_CONFIGURATION || Handle->Type == QUIC_HANDLE_TYPE_LISTENER) { // - // Registration, Session and Listener parameters are processed inline. + // Registration, Configuration and Listener parameters are processed inline. // Status = QuicLibraryGetParam(Handle, Level, Param, BufferLength, Buffer); goto Error; diff --git a/src/core/api.h b/src/core/api.h index 9ba657d449..083bb5db06 100644 --- a/src/core/api.h +++ b/src/core/api.h @@ -22,64 +22,52 @@ MsQuicRegistrationClose( HQUIC Registration ); -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QUIC_API -MsQuicSecConfigCreate( - _In_ _Pre_defensive_ HQUIC Registration, - _In_ QUIC_SEC_CONFIG_FLAGS Flags, - _In_opt_ void* Certificate, - _In_opt_z_ const char* Principal, - _In_opt_ void* Context, - _In_ _Pre_defensive_ - QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER CompletionHandler - ); - -_IRQL_requires_max_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) void QUIC_API -MsQuicSecConfigDelete( - _In_ _Pre_defensive_ QUIC_SEC_CONFIG* SecurityConfig +MsQuicRegistrationShutdown( + _In_ _Pre_defensive_ HQUIC Registration, + _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, + _In_ _Pre_defensive_ QUIC_UINT62 ErrorCode ); _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS QUIC_API -MsQuicSessionOpen( - _In_ _Pre_defensive_ HQUIC RegistrationContext, - _In_ uint32_t SettingsSize, - _In_reads_bytes_opt_(SettingsSize) - const QUIC_SETTINGS* Settings, +MsQuicConfigurationOpen( + _In_ _Pre_defensive_ HQUIC Registration, _In_reads_(AlpnBufferCount) _Pre_defensive_ const QUIC_BUFFER* const AlpnBuffers, - _In_ uint32_t AlpnBufferCount, + _In_range_(>, 0) uint32_t AlpnBufferCount, + _In_reads_bytes_opt_(SettingsSize) + const QUIC_SETTINGS* Settings, + _In_ uint32_t SettingsSize, _In_opt_ void* Context, - _Outptr_ _At_(*Session, __drv_allocatesMem(Mem)) _Pre_defensive_ - HQUIC *Session + _Outptr_ _At_(*Configuration, __drv_allocatesMem(Mem)) _Pre_defensive_ + HQUIC* Configuration ); _IRQL_requires_max_(PASSIVE_LEVEL) void QUIC_API -MsQuicSessionClose( +MsQuicConfigurationClose( _In_ _Pre_defensive_ __drv_freesMem(Mem) - HQUIC Session + HQUIC Configuration ); _IRQL_requires_max_(PASSIVE_LEVEL) -void +QUIC_STATUS QUIC_API -MsQuicSessionShutdown( - _In_ _Pre_defensive_ HQUIC Session, - _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, - _In_ _Pre_defensive_ QUIC_UINT62 ErrorCode +MsQuicConfigurationLoadCredential( + _In_ _Pre_defensive_ HQUIC Configuration, + _In_ _Pre_defensive_ const QUIC_CREDENTIAL_CONFIG* CredConfig ); _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS QUIC_API MsQuicListenerOpen( - _In_ _Pre_defensive_ HQUIC Session, + _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_ @@ -99,6 +87,9 @@ QUIC_STATUS QUIC_API MsQuicListenerStart( _In_ _Pre_defensive_ HQUIC Handle, + _In_reads_(AlpnBufferCount) _Pre_defensive_ + const QUIC_BUFFER* const AlpnBuffers, + _In_range_(>, 0) uint32_t AlpnBufferCount, _In_opt_ const QUIC_ADDR* LocalAddress ); @@ -113,7 +104,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS QUIC_API MsQuicConnectionOpen( - _In_ _Pre_defensive_ HQUIC Session, + _In_ _Pre_defensive_ HQUIC Registration, _In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler, _In_opt_ void* Context, _Outptr_ _At_(*Connection, __drv_allocatesMem(Mem)) _Pre_defensive_ @@ -142,12 +133,21 @@ QUIC_STATUS QUIC_API MsQuicConnectionStart( _In_ _Pre_defensive_ HQUIC Handle, + _In_ _Pre_defensive_ HQUIC ConfigHandle, _In_ QUIC_ADDRESS_FAMILY Family, _In_reads_opt_z_(QUIC_MAX_SNI_LENGTH) const char* ServerName, _In_ uint16_t ServerPort // Host byte order ); +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +QUIC_API +MsQuicConnectionSetConfiguration( + _In_ _Pre_defensive_ HQUIC Handle, + _In_ _Pre_defensive_ HQUIC ConfigHandle + ); + _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS QUIC_API diff --git a/src/core/binding.c b/src/core/binding.c index 187b043dfd..c25fc3d1f0 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -332,7 +332,7 @@ QuicBindingRegisterListener( continue; } - if (QuicSessionHasAlpnOverlap(NewListener->Session, ExistingListener->Session)) { + if (QuicListenerHasAlpnOverlap(NewListener, ExistingListener)) { QuicTraceLogWarning( BindingListenerAlreadyRegistered, "[bind][%p] Listener (%p) already registered on ALPN", @@ -407,7 +407,7 @@ QuicBindingGetListener( } } - if (QuicSessionMatchesAlpn(ExistingListener->Session, Info)) { + if (QuicListenerMatchesAlpn(ExistingListener, Info)) { if (QuicRundownAcquire(&ExistingListener->Rundown)) { Listener = ExistingListener; } @@ -440,6 +440,60 @@ QuicBindingUnregisterListener( QuicDispatchRwLockReleaseExclusive(&Binding->RwLock); } +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicBindingAcceptConnection( + _In_ QUIC_BINDING* Binding, + _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_NEW_CONNECTION_INFO* Info + ) +{ + // + // Find a listener that matches the incoming connection request, by IP, port + // and ALPN. + // + QUIC_LISTENER* Listener = QuicBindingGetListener(Binding, Info); + if (Listener == NULL) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "No listener found for connection"); + QuicConnTransportError( + Connection, + QUIC_ERROR_CRYPTO_NO_APPLICATION_PROTOCOL); + return; + } + + // + // Save the negotiated ALPN (starting with the length prefix) to be + // used later in building up the TLS response. + // + uint16_t NegotiatedAlpnLength = 1 + Info->NegotiatedAlpn[-1]; + uint8_t* NegotiatedAlpn = QUIC_ALLOC_NONPAGED(NegotiatedAlpnLength); + if (NegotiatedAlpn == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "NegotiatedAlpn", + NegotiatedAlpnLength); + QuicConnTransportError( + Connection, + QUIC_ERROR_INTERNAL_ERROR); + return; + } + QuicCopyMemory(NegotiatedAlpn, Info->NegotiatedAlpn - 1, NegotiatedAlpnLength); + Connection->Crypto.TlsState.NegotiatedAlpn = NegotiatedAlpn; + + // + // Allow for the listener to decide if it wishes to accept the incoming + // connection. + // + QuicListenerAcceptConnection(Listener, Connection, Info); + + QuicRundownRelease(&Listener->Rundown); +} + _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN QuicBindingAddSourceConnectionID( @@ -632,16 +686,16 @@ QuicBindingQueueStatelessOperation( _In_ QUIC_RECV_DATAGRAM* Datagram ) { - if (MsQuicLib.WorkerPool == NULL) { + if (MsQuicLib.StatelessRegistration == NULL) { QuicPacketLogDrop(Binding, QuicDataPathRecvDatagramToRecvPacket(Datagram), - "NULL worker pool"); + "NULL stateless registration"); return FALSE; } - QUIC_WORKER* Worker = QuicLibraryGetWorker(); + QUIC_WORKER* Worker = QuicLibraryGetWorker(Datagram); if (QuicWorkerIsOverloaded(Worker)) { QuicPacketLogDrop(Binding, QuicDataPathRecvDatagramToRecvPacket(Datagram), - "Worker overloaded (stateless oper)"); + "Stateless worker overloaded (stateless oper)"); return FALSE; } @@ -1138,18 +1192,30 @@ QuicBindingCreateConnection( // QuicLookupAddRemoteHash. // - QUIC_CONNECTION* Connection = NULL; QUIC_RECV_PACKET* Packet = QuicDataPathRecvDatagramToRecvPacket(Datagram); + // + // Pick a stateless worker to process the client hello and if successful, + // the connection will later be moved to the correct registration's worker. + // + QUIC_WORKER* Worker = QuicLibraryGetWorker(Datagram); + if (QuicWorkerIsOverloaded(Worker)) { + QuicPacketLogDrop(Binding, Packet, "Stateless worker overloaded"); + return NULL; + } + + QUIC_CONNECTION* Connection = NULL; QUIC_CONNECTION* NewConnection = QuicConnAlloc( - MsQuicLib.UnregisteredSession, + MsQuicLib.StatelessRegistration, Datagram); if (NewConnection == NULL) { QuicPacketLogDrop(Binding, Packet, "Failed to initialize new connection"); return NULL; } + QuicWorkerAssignConnection(Worker, NewConnection); + BOOLEAN BindingRefAdded = FALSE; QUIC_DBG_ASSERT(NewConnection->SourceCids.Next != NULL); QUIC_CID_HASH_ENTRY* SourceCid = @@ -1160,17 +1226,6 @@ QuicBindingCreateConnection( QuicConnAddRef(NewConnection, QUIC_CONN_REF_LOOKUP_RESULT); - // - // Pick a temporary worker to process the client hello and if successful, - // the connection will later be moved to the correct registration's worker. - // - QUIC_WORKER* Worker = QuicLibraryGetWorker(); - if (QuicWorkerIsOverloaded(Worker)) { - QuicPacketLogDrop(Binding, Packet, "Worker overloaded"); - goto Exit; - } - QuicWorkerAssignConnection(Worker, NewConnection); - // // Even though the new connection might not end up being put in this // binding's lookup table, it must be completely set up before it is diff --git a/src/core/binding.h b/src/core/binding.h index c658852eb7..dcc26bf080 100644 --- a/src/core/binding.h +++ b/src/core/binding.h @@ -320,6 +320,17 @@ QuicBindingUnregisterListener( _In_ QUIC_LISTENER* Listener ); +// +// Passes the connection to the binding to (possibly) accept it. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicBindingAcceptConnection( + _In_ QUIC_BINDING* Binding, + _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_NEW_CONNECTION_INFO* Info + ); + // // Attempts to insert the connection's new source CID into the binding's // lookup table. diff --git a/src/core/configuration.c b/src/core/configuration.c new file mode 100644 index 0000000000..5114d59d00 --- /dev/null +++ b/src/core/configuration.c @@ -0,0 +1,486 @@ +/*++ + + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. + +Abstract: + + A configurations is a container for multiple different settings, including + TLS security configuration and QUIC settings. On Windows it also manages + silo and network compartment state. + +--*/ + +#include "precomp.h" +#ifdef QUIC_CLOG +#include "configuration.c.clog.h" +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QUIC_API +MsQuicConfigurationOpen( + _In_ _Pre_defensive_ HQUIC Handle, + _In_reads_(AlpnBufferCount) _Pre_defensive_ + const QUIC_BUFFER* const AlpnBuffers, + _In_range_(>, 0) uint32_t AlpnBufferCount, + _In_reads_bytes_opt_(SettingsSize) + const QUIC_SETTINGS* Settings, + _In_ uint32_t SettingsSize, + _In_opt_ void* Context, + _Outptr_ _At_(*Configuration, __drv_allocatesMem(Mem)) _Pre_defensive_ + HQUIC* NewConfiguration + ) +{ + QUIC_STATUS Status = QUIC_STATUS_INVALID_PARAMETER; + QUIC_REGISTRATION* Registration = (QUIC_REGISTRATION*)Handle; + QUIC_CONFIGURATION* Configuration = NULL; + uint8_t* AlpnList; + uint32_t AlpnListLength; + + QuicTraceEvent( + ApiEnter, + "[ api] Enter %u (%p).", + QUIC_TRACE_API_CONFIGURATION_OPEN, + Handle); + + if (Handle == NULL || + Handle->Type != QUIC_HANDLE_TYPE_REGISTRATION || + AlpnBuffers == NULL || + AlpnBufferCount == 0 || + NewConfiguration == NULL) { + goto Error; + } + + if (Settings != NULL && + SettingsSize < (uint32_t)FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + + AlpnListLength = 0; + for (uint32_t i = 0; i < AlpnBufferCount; ++i) { + if (AlpnBuffers[i].Length == 0 || + AlpnBuffers[i].Length > QUIC_MAX_ALPN_LENGTH) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + AlpnListLength += sizeof(uint8_t) + AlpnBuffers[i].Length; + } + if (AlpnListLength > UINT16_MAX) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + QUIC_ANALYSIS_ASSERT(AlpnListLength <= UINT16_MAX); + + Configuration = QUIC_ALLOC_NONPAGED(sizeof(QUIC_CONFIGURATION) + AlpnListLength); + if (Configuration == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "QUIC_CONFIGURATION" , + sizeof(QUIC_CONFIGURATION)); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Error; + } + + QuicZeroMemory(Configuration, sizeof(QUIC_CONFIGURATION)); + Configuration->Type = QUIC_HANDLE_TYPE_CONFIGURATION; + Configuration->ClientContext = Context; + Configuration->Registration = Registration; + QuicRefInitialize(&Configuration->RefCount); + + Configuration->AlpnListLength = (uint16_t)AlpnListLength; + AlpnList = Configuration->AlpnList; + + for (uint32_t i = 0; i < AlpnBufferCount; ++i) { + AlpnList[0] = (uint8_t)AlpnBuffers[i].Length; + AlpnList++; + + QuicCopyMemory( + AlpnList, + AlpnBuffers[i].Buffer, + AlpnBuffers[i].Length); + AlpnList += AlpnBuffers[i].Length; + } + +#ifdef QUIC_COMPARTMENT_ID + Configuration->CompartmentId = QuicCompartmentIdGetCurrent(); +#endif + + // + // TODO - Optimize the settings code below: + // + // 1. When there is no silo support, the per-app name settings can live in + // the registration. + // + // 2. When there is silo support (Windows kernel mode), then there will be + // a ton of duplication between every single configuration (multiple + // server certificate scenarios), so we should have an intermediate + // object (ref counted) that is per-silo, per-app to handle these. + // + +#ifdef QUIC_SILO + Configuration->Silo = QuicSiloGetCurrentServer(); + QuicSiloAddRef(Configuration->Silo); + if (Configuration->Silo != NULL) { + // + // Only need to load base key if in a silo. Otherwise, the library already + // read in the default silo settings. + // + Status = + QuicStorageOpen( + NULL, + (QUIC_STORAGE_CHANGE_CALLBACK_HANDLER)QuicConfigurationSettingsChanged, + Configuration, + &Configuration->Storage); + if (QUIC_FAILED(Status)) { + QuicTraceLogWarning( + ConfigurationOpenStorageFailed, + "[cnfg][%p] Failed to open settings, 0x%x", + Configuration, + Status); + Status = QUIC_STATUS_SUCCESS; // Non-fatal, as the process may not have access + } + } +#endif + + if (Registration->AppNameLength != 0) { + char SpecificAppKey[UINT8_MAX + sizeof(QUIC_SETTING_APP_KEY)] = QUIC_SETTING_APP_KEY; + QuicCopyMemory( + SpecificAppKey + sizeof(QUIC_SETTING_APP_KEY) - 1, + Registration->AppName, + Registration->AppNameLength); + Status = + QuicStorageOpen( + SpecificAppKey, + (QUIC_STORAGE_CHANGE_CALLBACK_HANDLER)QuicConfigurationSettingsChanged, + Configuration, + &Configuration->AppSpecificStorage); + if (QUIC_FAILED(Status)) { + QuicTraceLogWarning( + ConfigurationOpenAppStorageFailed, + "[cnfg][%p] Failed to open app specific settings, 0x%x", + Configuration, + Status); + Status = QUIC_STATUS_SUCCESS; // Non-fatal, as the process may not have access + } + } + + if (Settings != NULL && Settings->IsSetFlags != 0) { + QUIC_DBG_ASSERT(SettingsSize >= (uint32_t)FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey)); + if (!QuicSettingApply( + &Configuration->Settings, + TRUE, + SettingsSize, + Settings)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + } + + QuicTraceEvent( + ConfigurationCreated, + "[cnfg][%p] Created, Registration=%p", + Configuration, + Registration); + + QuicConfigurationSettingsChanged(Configuration); + + BOOLEAN Result = QuicRundownAcquire(&Registration->Rundown); + QUIC_FRE_ASSERT(Result); + + QuicLockAcquire(&Registration->ConfigLock); + QuicListInsertTail(&Registration->Configurations, &Configuration->Link); + QuicLockRelease(&Registration->ConfigLock); + + *NewConfiguration = (HQUIC)Configuration; + +Error: + + if (QUIC_FAILED(Status) && Configuration != NULL) { + QuicStorageClose(Configuration->AppSpecificStorage); +#ifdef QUIC_SILO + QuicStorageClose(Configuration->Storage); + QuicSiloRelease(Configuration->Silo); +#endif + QUIC_FREE(Configuration); + } + + QuicTraceEvent( + ApiExitStatus, + "[ api] Exit %u", + Status); + + return Status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicConfigurationUninitialize( + _In_ __drv_freesMem(Mem) QUIC_CONFIGURATION* Configuration + ) +{ + QUIC_DBG_ASSERT(Configuration != NULL); + + QuicTraceEvent( + ConfigurationCleanup, + "[cnfg][%p] Cleaning up", + Configuration); + + QuicLockAcquire(&Configuration->Registration->ConfigLock); + QuicListEntryRemove(&Configuration->Link); + QuicLockRelease(&Configuration->Registration->ConfigLock); + + if (Configuration->SecurityConfig != NULL) { + QuicTlsSecConfigDelete(Configuration->SecurityConfig); + } + + QuicStorageClose(Configuration->AppSpecificStorage); +#ifdef QUIC_SILO + QuicStorageClose(Configuration->Storage); + QuicSiloRelease(Configuration->Silo); +#endif + + QuicRundownRelease(&Configuration->Registration->Rundown); + + QuicTraceEvent( + ConfigurationDestroyed, + "[cnfg][%p] Destroyed", + Configuration); + QUIC_FREE(Configuration); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QUIC_API +MsQuicConfigurationClose( + _In_ _Pre_defensive_ __drv_freesMem(Mem) + HQUIC Handle + ) +{ + QuicTraceEvent( + ApiEnter, + "[ api] Enter %u (%p).", + QUIC_TRACE_API_CONFIGURATION_CLOSE, + Handle); + + if (Handle != NULL && Handle->Type == QUIC_HANDLE_TYPE_CONFIGURATION) { +#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") + QuicConfigurationRelease((QUIC_CONFIGURATION*)Handle); + } + + QuicTraceEvent( + ApiExit, + "[ api] Exit"); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +_Function_class_(QUIC_SEC_CONFIG_CREATE_COMPLETE) +void +QUIC_API +MsQuicConfigurationLoadCredentialComplete( + _In_ const QUIC_CREDENTIAL_CONFIG* CredConfig, + _In_opt_ void* Context, + _In_ QUIC_STATUS Status, + _In_opt_ QUIC_SEC_CONFIG* SecurityConfig + ) +{ + QUIC_CONFIGURATION* Configuration = (QUIC_CONFIGURATION*)Context; + + QUIC_DBG_ASSERT(Configuration != NULL); + QUIC_DBG_ASSERT(CredConfig != NULL); + + if (QUIC_SUCCEEDED(Status)) { + QUIC_DBG_ASSERT(SecurityConfig); + Configuration->SecurityConfig = SecurityConfig; + } else { + QUIC_DBG_ASSERT(SecurityConfig == NULL); + } + + if (CredConfig->Flags & QUIC_CREDENTIAL_FLAG_LOAD_ASYNCHRONOUS) { + QUIC_DBG_ASSERT(CredConfig->AsyncHandler != NULL); + CredConfig->AsyncHandler( + (HQUIC)Configuration, + Configuration->ClientContext, + Status); + QuicConfigurationRelease(Configuration); + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QUIC_API +MsQuicConfigurationLoadCredential( + _In_ _Pre_defensive_ HQUIC Handle, + _In_ _Pre_defensive_ const QUIC_CREDENTIAL_CONFIG* CredConfig + ) +{ + QUIC_STATUS Status = QUIC_STATUS_INVALID_PARAMETER; + + QuicTraceEvent( + ApiEnter, + "[ api] Enter %u (%p).", + QUIC_TRACE_API_CONFIGURATION_LOAD_CREDENTIAL, + Handle); + + if (Handle != NULL && + CredConfig != NULL && + Handle->Type == QUIC_HANDLE_TYPE_CONFIGURATION) { + +#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") + QUIC_CONFIGURATION* Configuration = (QUIC_CONFIGURATION*)Handle; + + QuicConfigurationAddRef(Configuration); + + Status = + QuicTlsSecConfigCreate( + CredConfig, + Configuration, + MsQuicConfigurationLoadCredentialComplete); + if (!(CredConfig->Flags & QUIC_CREDENTIAL_FLAG_LOAD_ASYNCHRONOUS) || + QUIC_FAILED(Status)) { + // + // Release ref for synchronous calls or asynchronous failures. + // + QuicConfigurationRelease(Configuration); + } + } + + QuicTraceEvent( + ApiExitStatus, + "[ api] Exit %u", + Status); + + return Status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicConfigurationTraceRundown( + _In_ QUIC_CONFIGURATION* Configuration + ) +{ + QuicTraceEvent( + ConfigurationRundown, + "[cnfg][%p] Rundown, Registration=%p", + Configuration, + Configuration->Registration); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +_Function_class_(QUIC_STORAGE_CHANGE_CALLBACK) +void +QuicConfigurationSettingsChanged( + _Inout_ QUIC_CONFIGURATION* Configuration + ) +{ +#ifdef QUIC_SILO + if (Configuration->Storage != NULL) { + QuicSettingsSetDefault(&Configuration->Settings); + QuicSettingsLoad(&Configuration->Settings, Configuration->Storage); + } else { + QuicSettingsCopy(&Configuration->Settings, &MsQuicLib.Settings); + } +#else + QuicSettingsCopy(&Configuration->Settings, &MsQuicLib.Settings); +#endif + + if (Configuration->AppSpecificStorage != NULL) { + QuicSettingsLoad(&Configuration->Settings, Configuration->AppSpecificStorage); + } + + QuicTraceLogInfo( + ConfigurationSettingsUpdated, + "[cnfg][%p] Settings %p Updated", + Configuration, + &Configuration->Settings); + QuicSettingsDump(&Configuration->Settings); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConfigurationParamGet( + _In_ QUIC_CONFIGURATION* Configuration, + _In_ uint32_t Param, + _Inout_ uint32_t* BufferLength, + _Out_writes_bytes_opt_(*BufferLength) + void* Buffer + ) +{ + QUIC_STATUS Status; + + switch (Param) { + case QUIC_PARAM_CONFIGURATION_SETTINGS: + + if (*BufferLength < sizeof(QUIC_SETTINGS)) { + *BufferLength = sizeof(QUIC_SETTINGS); + Status = QUIC_STATUS_BUFFER_TOO_SMALL; // TODO - Support partial + break; + } + + if (Buffer == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + *BufferLength = sizeof(QUIC_SETTINGS); + QuicCopyMemory(Buffer, &Configuration->Settings, sizeof(QUIC_SETTINGS)); + + Status = QUIC_STATUS_SUCCESS; + break; + + default: + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + return Status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConfigurationParamSet( + _In_ QUIC_CONFIGURATION* Configuration, + _In_ uint32_t Param, + _In_ uint32_t BufferLength, + _In_reads_bytes_(BufferLength) + const void* Buffer + ) +{ + QUIC_STATUS Status; + + switch (Param) { + case QUIC_PARAM_GLOBAL_SETTINGS: + + if (BufferLength != sizeof(QUIC_SETTINGS)) { + Status = QUIC_STATUS_INVALID_PARAMETER; // TODO - Support partial + break; + } + + QuicTraceLogInfo( + ConfigurationSetSettings, + "[cnfg][%p] Setting new settings", + Configuration); + + if (!QuicSettingApply( + &Configuration->Settings, + TRUE, + BufferLength, + (QUIC_SETTINGS*)Buffer)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + QuicSettingsDumpNew(BufferLength, (QUIC_SETTINGS*)Buffer); + + Status = QUIC_STATUS_SUCCESS; + break; + + default: + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + return Status; +} diff --git a/src/core/configuration.h b/src/core/configuration.h new file mode 100644 index 0000000000..8835949873 --- /dev/null +++ b/src/core/configuration.h @@ -0,0 +1,161 @@ +/*++ + + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. + +--*/ + +// +// Represents a set of TLS and QUIC configurations and settings. +// +typedef struct QUIC_CONFIGURATION { + + struct QUIC_HANDLE; + + // + // Parent registration. + // + QUIC_REGISTRATION* Registration; + + // + // Link in the parent registration's Configurations list. + // + QUIC_LIST_ENTRY Link; + + // + // Reference count for tracking lifetime. + // + QUIC_REF_COUNT RefCount; + + // + // The TLS security configurations. + // + QUIC_SEC_CONFIG* SecurityConfig; + +#ifdef QUIC_COMPARTMENT_ID + // + // The network compartment ID. + // + QUIC_COMPARTMENT_ID CompartmentId; +#endif + +#ifdef QUIC_SILO + // + // The silo. + // + QUIC_SILO Silo; + + // + // Handle to persistent storage (registry). + // + QUIC_STORAGE* Storage; // Only necessary if it could be in a different silo. +#endif + QUIC_STORAGE* AppSpecificStorage; + + // + // Configurable (app & registry) settings. + // + QUIC_SETTINGS Settings; + + uint16_t AlpnListLength; + uint8_t AlpnList[0]; + +} QUIC_CONFIGURATION; + +#ifdef QUIC_SILO + +#define QuicConfigurationAttachSilo(Configuration) \ + QUIC_SILO PrevSilo = (Configuration == NULL || Configuration->Silo == NULL) ? \ + QUIC_SILO_INVALID : QuicSiloAttach(Configuration->Silo) + +#define QuicConfigurationDetachSilo() \ + if (PrevSilo != QUIC_SILO_INVALID) {\ + QuicSiloDetatch(PrevSilo); \ + } + +#else + +#define QuicConfigurationAttachSilo(Configuration) +#define QuicConfigurationDetachSilo() + +#endif // #ifdef QUIC_SILO + +// +// Cleans up the configuration memory. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicConfigurationUninitialize( + _In_ __drv_freesMem(Mem) QUIC_CONFIGURATION* Configuration + ); + +// +// Adds a new references to the configuration. +// +inline +void +QuicConfigurationAddRef( + _In_ QUIC_CONFIGURATION* Configuration + ) +{ + QuicRefIncrement(&Configuration->RefCount); +} + +// +// Releases a reference to the configuration and cleans it up if it's the last. +// +inline +void +QuicConfigurationRelease( + _In_ QUIC_CONFIGURATION* Configuration + ) +{ + if (QuicRefDecrement(&Configuration->RefCount)) { + QuicConfigurationUninitialize(Configuration); + } +} + +// +// Tracing rundown for the configuration. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicConfigurationTraceRundown( + _In_ QUIC_CONFIGURATION* Configuration + ); + +// +// Global or local settings were changed. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +_Function_class_(QUIC_STORAGE_CHANGE_CALLBACK) +void +QuicConfigurationSettingsChanged( + _Inout_ QUIC_CONFIGURATION* Configuration + ); + +// +// Gets a configuration parameter. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConfigurationParamGet( + _In_ QUIC_CONFIGURATION* Configuration, + _In_ uint32_t Param, + _Inout_ uint32_t* BufferLength, + _Out_writes_bytes_opt_(*BufferLength) + void* Buffer + ); + +// +// Sets a configuration parameter. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +QUIC_STATUS +QuicConfigurationParamSet( + _In_ QUIC_CONFIGURATION* Configuration, + _In_ uint32_t Param, + _In_ uint32_t BufferLength, + _In_reads_bytes_(BufferLength) + const void* Buffer + ); diff --git a/src/core/congestion_control.c b/src/core/congestion_control.c index 94bdbff4c8..1adab44860 100644 --- a/src/core/congestion_control.c +++ b/src/core/congestion_control.c @@ -160,7 +160,7 @@ QuicCongestionControlGetSendAllowance( // SendAllowance = 0; - } else if (!Connection->State.UsePacing || !Connection->Paths[0].GotFirstRttSample) { + } else if (!Connection->Settings.PacingEnabled || !Connection->Paths[0].GotFirstRttSample) { // // Pacing is disabled or we don't have an RTT sample yet, so just send // everything we can. diff --git a/src/core/connection.c b/src/core/connection.c index 61cd478a70..e64fb415ee 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -42,10 +42,16 @@ typedef struct QUIC_RECEIVE_PROCESSING_STATE { uint16_t PartitionIndex; } QUIC_RECEIVE_PROCESSING_STATE; + _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicConnInitializeCrypto( - _In_ QUIC_CONNECTION* Connection +BOOLEAN +QuicConnApplyNewSettings( + _In_ QUIC_CONNECTION* Connection, + _In_ BOOLEAN OverWrite, + _In_range_(FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey), UINT32_MAX) + uint32_t NewSettingsSize, + _In_reads_bytes_(NewSettingsSize) + const QUIC_SETTINGS* NewSettings ); _IRQL_requires_max_(DISPATCH_LEVEL) @@ -54,7 +60,7 @@ _Must_inspect_result_ _Success_(return != NULL) QUIC_CONNECTION* QuicConnAlloc( - _In_ QUIC_SESSION* Session, + _In_ QUIC_REGISTRATION* Registration, _In_opt_ const QUIC_RECV_DATAGRAM* const Datagram ) { @@ -107,19 +113,21 @@ QuicConnAlloc( #endif Connection->PartitionID = PartitionId; Connection->State.Allocated = TRUE; - Connection->State.UseSendBuffer = QUIC_DEFAULT_SEND_BUFFERING_ENABLE; Connection->State.ShareBinding = IsServer; Connection->Stats.Timing.Start = QuicTimeUs64(); Connection->SourceCidLimit = QUIC_ACTIVE_CONNECTION_ID_LIMIT; Connection->AckDelayExponent = QUIC_ACK_DELAY_EXPONENT; Connection->PeerTransportParams.AckDelayExponent = QUIC_TP_ACK_DELAY_EXPONENT_DEFAULT; Connection->ReceiveQueueTail = &Connection->ReceiveQueue; + Connection->Settings = MsQuicLib.Settings; + Connection->Settings.IsSetFlags = 0; // Just grab the global values, not IsSet flags. QuicDispatchLockInitialize(&Connection->ReceiveQueueLock); QuicListInitializeHead(&Connection->DestCids); QuicStreamSetInitialize(&Connection->Streams); QuicSendBufferInitialize(&Connection->SendBuffer); QuicOperationQueueInitialize(&Connection->OperQ); - QuicSendInitialize(&Connection->Send); + QuicSendInitialize(&Connection->Send, &Connection->Settings); + QuicCongestionControlInitialize(&Connection->CongestionControl, &Connection->Settings); QuicLossDetectionInitialize(&Connection->LossDetection); QuicDatagramInitialize(&Connection->Datagram); QuicRangeInitialize( @@ -148,12 +156,6 @@ QuicConnAlloc( if (IsServer) { - // - // Use global settings until the connection is assigned to a session. - // Then the connection will use the session's settings. - // - QuicConnApplySettings(Connection, &MsQuicLib.Settings); - const QUIC_RECV_PACKET* Packet = QuicDataPathRecvDatagramToRecvPacket(Datagram); @@ -252,7 +254,7 @@ QuicConnAlloc( Connection); } - QuicSessionRegisterConnection(Session, Connection); + QuicConnRegister(Connection, Registration); return Connection; @@ -290,6 +292,7 @@ QuicConnFree( if (Connection->State.ExternalOwner) { QUIC_TEL_ASSERT(Connection->State.HandleClosed); QUIC_TEL_ASSERT(Connection->State.Uninitialized); + QUIC_DBG_ASSERT(!Connection->State.Registered); } QUIC_TEL_ASSERT(Connection->SourceCids.Next == NULL); QUIC_TEL_ASSERT(QuicListIsEmpty(&Connection->Streams.ClosedStreams)); @@ -322,6 +325,17 @@ QuicConnFree( Link); QUIC_FREE(CID); } + if (Connection->State.Registered) { + QuicDispatchLockAcquire(&Connection->Registration->ConnectionLock); + QuicListEntryRemove(&Connection->RegistrationLink); + QuicDispatchLockRelease(&Connection->Registration->ConnectionLock); + Connection->State.Registered = FALSE; + QuicTraceEvent( + ConnUnregistered, + "[conn][%p] Unregistered from %p", + Connection, + Connection->Registration); + } if (Connection->Worker != NULL) { QuicOperationQueueClear(Connection->Worker, &Connection->OperQ); } @@ -343,11 +357,10 @@ QuicConnFree( QuicStreamSetUninitialize(&Connection->Streams); QuicSendBufferUninitialize(&Connection->SendBuffer); QuicDatagramUninitialize(&Connection->Datagram); - QuicSessionUnregisterConnection(Connection); - if (Connection->Registration != NULL) { - QuicRundownRelease(&Connection->Registration->ConnectionRundown); + if (Connection->Configuration != NULL) { + QuicConfigurationRelease(Connection->Configuration); + Connection->Configuration = NULL; } - Connection->State.Freed = TRUE; if (Connection->RemoteServerName != NULL) { QUIC_FREE(Connection->RemoteServerName); } @@ -360,17 +373,20 @@ QuicConnFree( Connection->HandshakeTP); Connection->HandshakeTP = NULL; } - QuicTraceEvent( - ConnDestroyed, - "[conn][%p] Destroyed", - Connection); - if (Connection->State.Started && !Connection->State.Connected) { QuicPerfCounterIncrement(QUIC_PERF_COUNTER_CONN_HANDSHAKE_FAIL); } if (Connection->State.Connected) { QuicPerfCounterDecrement(QUIC_PERF_COUNTER_CONN_CONNECTED); } + if (Connection->Registration != NULL) { + QuicRundownRelease(&Connection->Registration->Rundown); + } + Connection->State.Freed = TRUE; + QuicTraceEvent( + ConnDestroyed, + "[conn][%p] Destroyed", + Connection); QuicPoolFree( &MsQuicLib.PerProc[QuicProcCurrentNumber()].ConnectionPool, Connection); @@ -381,60 +397,6 @@ QuicConnFree( QuicPerfCounterDecrement(QUIC_PERF_COUNTER_CONN_ACTIVE); } -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicConnApplySettings( - _In_ QUIC_CONNECTION* Connection, - _In_ const QUIC_SETTINGS* Settings - ) -{ - Connection->State.UsePacing = Settings->PacingEnabled; - Connection->MaxAckDelayMs = Settings->MaxAckDelayMs; - Connection->Paths[0].SmoothedRtt = MS_TO_US(Settings->InitialRttMs); - Connection->Paths[0].RttVariance = Connection->Paths[0].SmoothedRtt / 2; - Connection->DisconnectTimeoutUs = MS_TO_US(Settings->DisconnectTimeoutMs); - Connection->IdleTimeoutMs = Settings->IdleTimeoutMs; - Connection->HandshakeIdleTimeoutMs = Settings->HandshakeIdleTimeoutMs; - Connection->KeepAliveIntervalMs = Settings->KeepAliveIntervalMs; - Connection->Datagram.ReceiveEnabled = Settings->DatagramReceiveEnabled; - - uint8_t PeerStreamType = - QuicConnIsServer(Connection) ? - STREAM_ID_FLAG_IS_CLIENT : STREAM_ID_FLAG_IS_SERVER; - if (Settings->PeerBidiStreamCount != 0) { - QuicStreamSetUpdateMaxCount( - &Connection->Streams, - PeerStreamType | STREAM_ID_FLAG_IS_BI_DIR, - Settings->PeerBidiStreamCount); - } - if (Settings->PeerUnidiStreamCount != 0) { - QuicStreamSetUpdateMaxCount( - &Connection->Streams, - PeerStreamType | STREAM_ID_FLAG_IS_UNI_DIR, - Settings->PeerUnidiStreamCount); - } - - if (Settings->ServerResumptionLevel > QUIC_SERVER_NO_RESUME && - Connection->HandshakeTP == NULL) { - QUIC_DBG_ASSERT(!Connection->State.Started); - Connection->HandshakeTP = - QuicPoolAlloc(&MsQuicLib.PerProc[QuicProcCurrentNumber()].TransportParamPool); - if (Connection->HandshakeTP == NULL) { - QuicTraceEvent( - AllocFailure, - "Allocation of '%s' failed. (%llu bytes)", - "handshake TP", - sizeof(*Connection->HandshakeTP)); - } else { - QuicZeroMemory(Connection->HandshakeTP, sizeof(*Connection->HandshakeTP)); - Connection->State.ResumptionEnabled = TRUE; - } - } - - QuicSendApplySettings(&Connection->Send, Settings); - QuicCongestionControlInitialize(&Connection->CongestionControl, Settings); -} - _IRQL_requires_max_(PASSIVE_LEVEL) void QuicConnShutdown( @@ -525,7 +487,17 @@ QuicConnCloseHandle( Connection->State.HandleClosed = TRUE; Connection->ClientCallbackHandler = NULL; - QuicSessionUnregisterConnection(Connection); + if (Connection->State.Registered) { + QuicDispatchLockAcquire(&Connection->Registration->ConnectionLock); + QuicListEntryRemove(&Connection->RegistrationLink); + QuicDispatchLockRelease(&Connection->Registration->ConnectionLock); + Connection->State.Registered = FALSE; + QuicTraceEvent( + ConnUnregistered, + "[conn][%p] Unregistered from %p", + Connection, + Connection->Registration); + } QuicTraceEvent( ConnHandleClosed, @@ -533,6 +505,45 @@ QuicConnCloseHandle( Connection); } +_IRQL_requires_max_(DISPATCH_LEVEL) +void +QuicConnRegister( + _Inout_ QUIC_CONNECTION* Connection, + _Inout_ QUIC_REGISTRATION* Registration + ) +{ + if (Connection->Registration != NULL) { + QuicDispatchLockAcquire(&Connection->Registration->ConnectionLock); + QuicListEntryRemove(&Connection->RegistrationLink); + QuicDispatchLockRelease(&Connection->Registration->ConnectionLock); + QuicRundownRelease(&Connection->Registration->Rundown); + + QuicTraceEvent( + ConnUnregistered, + "[conn][%p] Unregistered from %p", + Connection, + Connection->Registration); + } + + Connection->State.Registered = TRUE; + Connection->Registration = Registration; + BOOLEAN Success = QuicRundownAcquire(&Registration->Rundown); + QUIC_DBG_ASSERT(Success); UNREFERENCED_PARAMETER(Success); +#ifdef QuicVerifierEnabledByAddr + Connection->State.IsVerifying = Registration->IsVerifying; +#endif + + QuicDispatchLockAcquire(&Registration->ConnectionLock); + QuicListInsertTail(&Registration->Connections, &Connection->RegistrationLink); + QuicDispatchLockRelease(&Registration->ConnectionLock); + + QuicTraceEvent( + ConnRegistered, + "[conn][%p] Registered with %p", + Connection, + Registration); +} + _IRQL_requires_max_(DISPATCH_LEVEL) void QuicConnQueueTraceRundown( @@ -568,12 +579,18 @@ QuicConnTraceRundownOper( "[conn][%p] Assigned worker: %p", Connection, Connection->Worker); - if (Connection->Session != NULL) { + QUIC_DBG_ASSERT(Connection->Registration); + QuicTraceEvent( + ConnRegistered, + "[conn][%p] Registered with %p", + Connection, + Connection->Registration); + if (Connection->Stats.QuicVersion != 0) { QuicTraceEvent( - ConnRegisterSession, - "[conn][%p] Registered with session: %p", + ConnVersionSet, + "[conn][%p] Version = %u", Connection, - Connection->Session); + Connection->Stats.QuicVersion); } if (Connection->State.Started) { for (uint8_t i = 0; i < Connection->PathsCount; ++i) { @@ -626,7 +643,6 @@ QuicConnTraceRundownOper( } } if (Connection->State.Connected) { - QuicConnOnQuicVersionSet(Connection); QuicTraceEvent( ConnHandshakeComplete, "[conn][%p] Handshake complete", @@ -1415,7 +1431,7 @@ QuicConnTryClose( if (!ClosedRemotely) { if ((Flags & QUIC_CLOSE_APPLICATION) && - Connection->Crypto.TlsState.WriteKey < QUIC_PACKET_KEY_1_RTT) { + QuicCryptoGetNextEncryptLevel(&Connection->Crypto) < QUIC_ENCRYPT_LEVEL_1_RTT) { // // Application close can only happen if we are using 1-RTT keys. // Otherwise we have to send "user_canceled" TLS error code as a @@ -1425,6 +1441,11 @@ QuicConnTryClose( ErrorCode = QUIC_ERROR_CRYPTO_USER_CANCELED; RemoteReasonPhrase = NULL; RemoteReasonPhraseLength = 0; + + QuicTraceLogConnInfo( + CloseUserCanceled, + Connection, + "Connection close using user canceled error"); } } @@ -1689,6 +1710,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS QuicConnStart( _In_ QUIC_CONNECTION* Connection, + _In_ QUIC_CONFIGURATION* Configuration, _In_ QUIC_ADDRESS_FAMILY Family, _In_opt_z_ const char* ServerName, _In_ uint16_t ServerPort // Host byte order @@ -1715,8 +1737,8 @@ QuicConnStart( #ifdef QUIC_COMPARTMENT_ID BOOLEAN RevertCompartmentId = FALSE; QUIC_COMPARTMENT_ID PrevCompartmentId = QuicCompartmentIdGetCurrent(); - if (PrevCompartmentId != Connection->Session->CompartmentId) { - Status = QuicCompartmentIdSetCurrent(Connection->Session->CompartmentId); + if (PrevCompartmentId != Configuration->CompartmentId) { + Status = QuicCompartmentIdSetCurrent(Configuration->CompartmentId); if (QUIC_FAILED(Status)) { QuicTraceEvent( ConnErrorStatus, @@ -1763,7 +1785,9 @@ QuicConnStart( // Status = QuicLibraryGetBinding( - Connection->Session, +#ifdef QUIC_COMPARTMENT_ID + Configuration->CompartmentId, +#endif Connection->State.ShareBinding, FALSE, Connection->State.LocalAddressSet ? &Path->LocalAddress : NULL, @@ -1826,14 +1850,26 @@ QuicConnStart( Connection->RemoteServerName = ServerName; ServerName = NULL; + Status = QuicCryptoInitialize(&Connection->Crypto); + if (QUIC_FAILED(Status)) { + goto Exit; + } + // // Start the handshake. // - Status = QuicConnInitializeCrypto(Connection); + Status = QuicConnSetConfiguration(Connection, Configuration); if (QUIC_FAILED(Status)) { goto Exit; } + if (Connection->Settings.KeepAliveIntervalMs != 0) { + QuicConnTimerSet( + Connection, + QUIC_CONN_TIMER_KEEP_ALIVE, + Connection->Settings.KeepAliveIntervalMs); + } + Exit: if (ServerName != NULL) { @@ -1872,7 +1908,7 @@ QuicConnRestart( // QUIC_PATH* Path = &Connection->Paths[0]; Path->GotFirstRttSample = FALSE; - Path->SmoothedRtt = MS_TO_US(Connection->Session->Settings.InitialRttMs); + Path->SmoothedRtt = MS_TO_US(Connection->Settings.InitialRttMs); Path->RttVariance = Path->SmoothedRtt / 2; } @@ -1896,97 +1932,37 @@ QuicConnSendResumptionTicket( ) { QUIC_STATUS Status; - uint32_t EncodedTransportParametersLength = 0; uint8_t* TicketBuffer = NULL; - uint16_t AlpnLength = *(Connection->Crypto.TlsState.NegotiatedAlpn); - const uint8_t* EncodedHSTP = NULL; + uint32_t TicketLength = 0; + uint8_t AlpnLength = Connection->Crypto.TlsState.NegotiatedAlpn[0]; if (Connection->HandshakeTP == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; goto Error; } - QUIC_TRANSPORT_PARAMETERS HSTPCopy = *Connection->HandshakeTP; - HSTPCopy.Flags = HSTPCopy.Flags & ( - QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | - QUIC_TP_FLAG_INITIAL_MAX_DATA | - QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_LOCAL | - QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | - QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | - QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | - QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI); - - EncodedHSTP = - QuicCryptoTlsEncodeTransportParameters( + Status = + QuicCryptoEncodeServerTicket( Connection, - &HSTPCopy, - &EncodedTransportParametersLength); - if (EncodedHSTP == NULL) { - Status = QUIC_STATUS_OUT_OF_MEMORY; - goto Error; - } - - uint32_t TotalTicketLength = - (uint32_t)(QuicVarIntSize(QUIC_TLS_RESUMPTION_TICKET_VERSION) + - QuicVarIntSize(AlpnLength) + - QuicVarIntSize(EncodedTransportParametersLength) + - QuicVarIntSize(AppDataLength) + - sizeof(QUIC_VERSION_LATEST) + - AlpnLength + - EncodedTransportParametersLength + - AppDataLength); - - TicketBuffer = QUIC_ALLOC_NONPAGED(TotalTicketLength); - if (TicketBuffer == NULL) { - QuicTraceEvent( - AllocFailure, - "Allocation of '%s' failed. (%llu bytes)", - "Server resumption ticket", - TotalTicketLength); - Status = QUIC_STATUS_OUT_OF_MEMORY; + Connection->Stats.QuicVersion, + AppDataLength, + AppResumptionData, + Connection->HandshakeTP, + AlpnLength, + Connection->Crypto.TlsState.NegotiatedAlpn + 1, + &TicketBuffer, + &TicketLength); + if (QUIC_FAILED(Status)) { goto Error; } - // - // Encoded ticket format is as follows: - // Ticket Version (QUIC_VAR_INT) [1..4] - // Quic Version [4] - // Negotiated ALPN length (QUIC_VAR_INT) [1..2] - // Negotiated ALPN [...] - // Transport Parameters length (QUIC_VAR_INT) [1..2] - // Transport Parameters [...] - // App Ticket length (QUIC_VAR_INT) [1..2] - // App Ticket (omitted if length is zero) [...] - // - - _Analysis_assume_(sizeof(*TicketBuffer) >= 8); - uint8_t* TicketCursor = QuicVarIntEncode(QUIC_TLS_RESUMPTION_TICKET_VERSION, TicketBuffer); - *(uint32_t*)TicketCursor = QuicByteSwapUint32(QUIC_VERSION_LATEST); - TicketCursor += sizeof(QUIC_VERSION_LATEST); - TicketCursor = QuicVarIntEncode(AlpnLength, TicketCursor); - QuicCopyMemory(TicketCursor, Connection->Crypto.TlsState.NegotiatedAlpn + 1, AlpnLength); - TicketCursor += AlpnLength; - TicketCursor = QuicVarIntEncode(EncodedTransportParametersLength, TicketCursor); - QuicCopyMemory(TicketCursor, EncodedHSTP, EncodedTransportParametersLength); - TicketCursor += EncodedTransportParametersLength; - TicketCursor = QuicVarIntEncode(AppDataLength, TicketCursor); - if (AppDataLength > 0) { - QuicCopyMemory(TicketCursor, AppResumptionData, AppDataLength); - TicketCursor += AppDataLength; - } - QUIC_DBG_ASSERT(TicketCursor == TicketBuffer + TotalTicketLength); - - Status = QuicCryptoProcessAppData(&Connection->Crypto, TotalTicketLength, TicketBuffer); + Status = QuicCryptoProcessAppData(&Connection->Crypto, TicketLength, TicketBuffer); Error: if (TicketBuffer != NULL) { QUIC_FREE(TicketBuffer); } - if (EncodedHSTP != NULL) { - QUIC_FREE(EncodedHSTP); - } - if (AppResumptionData != NULL) { QUIC_FREE(AppResumptionData); } @@ -2006,86 +1982,31 @@ QuicConnRecvResumptionTicket( BOOLEAN ResumptionAccepted = FALSE; QUIC_TRANSPORT_PARAMETERS ResumedTP; if (QuicConnIsServer(Connection)) { - uint16_t Offset = 0; - QUIC_VAR_INT TicketVersion = 0, AlpnLength = 0, TPLength = 0, AppTicketLength = 0; - if (!QuicVarIntDecode(TicketLength, Ticket, &Offset, &TicketVersion)) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Resumption Ticket version failed to decode"); - goto Error; - } - if (TicketVersion != QUIC_TLS_RESUMPTION_TICKET_VERSION) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Resumption Ticket version unsupported"); - goto Error; - } - - uint32_t QuicVersionHost = QuicByteSwapUint32(*(uint32_t*)(Ticket + Offset)); - if (!QuicIsVersionSupported(QuicVersionHost)) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Resumption Ticket for unsupported QUIC version"); - goto Error; - } - Offset += sizeof(QuicVersionHost); - - if (!QuicVarIntDecode(TicketLength, Ticket, &Offset, &AlpnLength)) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Resumption Ticket ALPN length failed to decode"); - goto Error; - } - if (QuicTlsAlpnFindInList( - Connection->Session->AlpnListLength, Connection->Session->AlpnList, - (uint8_t)AlpnLength, Ticket + Offset) == NULL) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Resumption Ticket ALPN not present in ALPN list"); - goto Error; - } - Offset += (uint16_t)AlpnLength; + const uint8_t* AppData = NULL; + uint32_t AppDataLength = 0; - if (!QuicVarIntDecode(TicketLength, Ticket, &Offset, &TPLength)) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Resumption Ticket TP length failed to decode"); - goto Error; - } - if (!QuicCryptoTlsDecodeTransportParameters( - Connection, - Ticket + Offset, - (uint16_t)TPLength, - &ResumedTP)) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", + QUIC_STATUS Status = + QuicCryptoDecodeServerTicket( Connection, - "Resumption Ticket TParams failed to decode"); + TicketLength, + Ticket, + Connection->Configuration->AlpnList, + Connection->Configuration->AlpnListLength, + &ResumedTP, + &AppData, + &AppDataLength); + if (QUIC_FAILED(Status)) { goto Error; } - Offset += (uint16_t)TPLength; // // Validate resumed TP are <= current settings // if (ResumedTP.ActiveConnectionIdLimit > QUIC_ACTIVE_CONNECTION_ID_LIMIT || ResumedTP.InitialMaxData > Connection->Send.MaxData || - ResumedTP.InitialMaxStreamDataBidiLocal > Connection->Session->Settings.StreamRecvWindowDefault || - ResumedTP.InitialMaxStreamDataBidiRemote > Connection->Session->Settings.StreamRecvWindowDefault || - ResumedTP.InitialMaxStreamDataUni > Connection->Session->Settings.StreamRecvWindowDefault || + ResumedTP.InitialMaxStreamDataBidiLocal > Connection->Settings.StreamRecvWindowDefault || + ResumedTP.InitialMaxStreamDataBidiRemote > Connection->Settings.StreamRecvWindowDefault || + ResumedTP.InitialMaxStreamDataUni > Connection->Settings.StreamRecvWindowDefault || ResumedTP.InitialMaxUniStreams > Connection->Streams.Types[STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_UNI_DIR].MaxTotalStreamCount || ResumedTP.InitialMaxBidiStreams > Connection->Streams.Types[STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_BI_DIR].MaxTotalStreamCount) { // @@ -2100,23 +2021,17 @@ QuicConnRecvResumptionTicket( goto Error; } - if (!QuicVarIntDecode(TicketLength, Ticket, &Offset, &AppTicketLength)) { - QuicTraceEvent( - ConnError, - "[conn][%p] ERROR, %s.", - Connection, - "Resumption Ticket app data length failed to decode"); - goto Error; - } - - QUIC_CONNECTION_EVENT Event = { 0, }; + QUIC_CONNECTION_EVENT Event; Event.Type = QUIC_CONNECTION_EVENT_RESUMED; - Event.RESUMED.ResumptionStateLength = (uint16_t)AppTicketLength; - Event.RESUMED.ResumptionState = (AppTicketLength > 0) ? Ticket + Offset : NULL; + Event.RESUMED.ResumptionStateLength = (uint16_t)AppDataLength; + Event.RESUMED.ResumptionState = (AppDataLength > 0) ? AppData : NULL; + QuicTraceLogConnVerbose( + IndicateResumptionTicketReceived, + Connection, + "Indicating QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED"); ResumptionAccepted = QUIC_SUCCEEDED(QuicConnIndicateEvent(Connection, &Event)); - if (ResumptionAccepted) { QuicTraceEvent( ConnServerResumeTicket, @@ -2130,13 +2045,36 @@ QuicConnRecvResumptionTicket( "Resumption Ticket rejected by server app"); } - QUIC_DBG_ASSERT(Offset + AppTicketLength == TicketLength); } else { - // - // TODO Client-side processing. - // Until then, this shouldn't ever get called. - // - QUIC_FRE_ASSERT(FALSE); + + const uint8_t* ClientTicket = NULL; + uint32_t ClientTicketLength = 0; + + QUIC_DBG_ASSERT(Connection->State.PeerTransportParameterValid); + + if (QUIC_SUCCEEDED( + QuicCryptoEncodeClientTicket( + Connection, + TicketLength, + Ticket, + &Connection->PeerTransportParams, + Connection->Stats.QuicVersion, + &ClientTicket, + &ClientTicketLength))) { + + QUIC_CONNECTION_EVENT Event; + Event.Type = QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED; + Event.RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength = ClientTicketLength; + Event.RESUMPTION_TICKET_RECEIVED.ResumptionTicket = ClientTicket; + QuicTraceLogConnVerbose( + IndicateResumptionTicketReceived, + Connection, + "Indicating QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED"); + (void)QuicConnIndicateEvent(Connection, &Event); + + QUIC_FREE(ClientTicket); + ResumptionAccepted = TRUE; + } } Error: @@ -2179,50 +2117,6 @@ QuicConnCleanupServerResumptionState( } } -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicConnInitializeCrypto( - _In_ QUIC_CONNECTION* Connection - ) -{ - QUIC_STATUS Status; - BOOLEAN CryptoInitialized = FALSE; - - Status = QuicCryptoInitialize(&Connection->Crypto); - if (QUIC_FAILED(Status)) { - goto Error; - } - CryptoInitialized = TRUE; - - if (!QuicConnIsServer(Connection)) { - Status = QuicConnHandshakeConfigure(Connection, NULL); - if (QUIC_FAILED(Status)) { - goto Error; - } - } - - if (Connection->KeepAliveIntervalMs != 0) { - // - // Now that we are starting the connection, start the keep alive timer - // if enabled. - // - QuicConnTimerSet( - Connection, - QUIC_CONN_TIMER_KEEP_ALIVE, - Connection->KeepAliveIntervalMs); - } - -Error: - - if (QUIC_FAILED(Status)) { - if (CryptoInitialized) { - QuicCryptoUninitialize(&Connection->Crypto); - } - } - - return Status; -} - _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS QuicConnGenerateLocalTransportParameters( @@ -2230,7 +2124,7 @@ QuicConnGenerateLocalTransportParameters( _Out_ QUIC_TRANSPORT_PARAMETERS* LocalTP ) { - QUIC_TEL_ASSERT(Connection->Session != NULL); + QUIC_TEL_ASSERT(Connection->Configuration != NULL); QUIC_DBG_ASSERT(Connection->SourceCids.Next != NULL); const QUIC_CID_HASH_ENTRY* SourceCid = @@ -2240,15 +2134,15 @@ QuicConnGenerateLocalTransportParameters( Link); LocalTP->InitialMaxData = Connection->Send.MaxData; - LocalTP->InitialMaxStreamDataBidiLocal = Connection->Session->Settings.StreamRecvWindowDefault; - LocalTP->InitialMaxStreamDataBidiRemote = Connection->Session->Settings.StreamRecvWindowDefault; - LocalTP->InitialMaxStreamDataUni = Connection->Session->Settings.StreamRecvWindowDefault; + LocalTP->InitialMaxStreamDataBidiLocal = Connection->Settings.StreamRecvWindowDefault; + LocalTP->InitialMaxStreamDataBidiRemote = Connection->Settings.StreamRecvWindowDefault; + LocalTP->InitialMaxStreamDataUni = Connection->Settings.StreamRecvWindowDefault; LocalTP->MaxUdpPayloadSize = MaxUdpPayloadSizeFromMTU( QuicDataPathBindingGetLocalMtu( Connection->Paths[0].Binding->DatapathBinding)); LocalTP->MaxAckDelay = - Connection->MaxAckDelayMs + MsQuicLib.TimerResolutionMs; + Connection->Settings.MaxAckDelayMs + MsQuicLib.TimerResolutionMs; LocalTP->ActiveConnectionIdLimit = QUIC_ACTIVE_CONNECTION_ID_LIMIT; LocalTP->Flags = QUIC_TP_FLAG_INITIAL_MAX_DATA | @@ -2259,9 +2153,9 @@ QuicConnGenerateLocalTransportParameters( QUIC_TP_FLAG_MAX_ACK_DELAY | QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT; - if (Connection->IdleTimeoutMs != 0) { + if (Connection->Settings.IdleTimeoutMs != 0) { LocalTP->Flags |= QUIC_TP_FLAG_IDLE_TIMEOUT; - LocalTP->IdleTimeout = Connection->IdleTimeoutMs; + LocalTP->IdleTimeout = Connection->Settings.IdleTimeoutMs; } if (Connection->AckDelayExponent != QUIC_TP_ACK_DELAY_EXPONENT_DEFAULT) { @@ -2301,7 +2195,7 @@ QuicConnGenerateLocalTransportParameters( Connection->Streams.Types[STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_UNI_DIR].MaxTotalStreamCount; } - if (!Connection->Session->Settings.MigrationEnabled) { + if (!Connection->Settings.MigrationEnabled) { LocalTP->Flags |= QUIC_TP_FLAG_DISABLE_ACTIVE_MIGRATION; } @@ -2370,58 +2264,45 @@ QuicConnGenerateLocalTransportParameters( _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS -QuicConnHandshakeConfigure( +QuicConnSetConfiguration( _In_ QUIC_CONNECTION* Connection, - _In_opt_ QUIC_SEC_CONFIG* SecConfig + _In_ QUIC_CONFIGURATION* Configuration ) { + if (Connection->Configuration != NULL || QuicConnIsClosed(Connection)) { + return QUIC_STATUS_INVALID_STATE; + } + QUIC_STATUS Status; QUIC_TRANSPORT_PARAMETERS LocalTP = { 0 }; - QUIC_TEL_ASSERT(Connection->Session != NULL); - QUIC_TEL_ASSERT(SecConfig != NULL || !QuicConnIsServer(Connection)); + QUIC_TEL_ASSERT(Connection->Configuration == NULL); + QUIC_TEL_ASSERT(Configuration != NULL); + QUIC_TEL_ASSERT(Configuration->SecurityConfig != NULL); - if (!QuicConnIsServer(Connection)) { + QuicTraceLogConnInfo( + SetConfiguration, + Connection, + "Configuration set, %p", + Configuration); - uint32_t InitialQuicVersion = QUIC_VERSION_LATEST; - if (Connection->RemoteServerName != NULL && - QuicSessionServerCacheGetState( - Connection->Session, - Connection->RemoteServerName, - &InitialQuicVersion, - &Connection->PeerTransportParams, - &SecConfig)) { + QuicConfigurationAddRef(Configuration); + Connection->Configuration = Configuration; + QuicConnApplyNewSettings( + Connection, + FALSE, + sizeof(Configuration->Settings), + &Configuration->Settings); - QuicTraceLogConnVerbose( - FoundCachedServerState, - Connection, - "Found server cached state"); - QuicConnProcessPeerTransportParameters(Connection, TRUE); - } + if (!QuicConnIsServer(Connection)) { if (Connection->Stats.QuicVersion == 0) { // // Only initialize the version if not already done (by the // application layer). // - Connection->Stats.QuicVersion = InitialQuicVersion; - } - QuicConnOnQuicVersionSet(Connection); - - if (SecConfig == NULL) { - Status = - QuicTlsClientSecConfigCreate( - Connection->ServerCertValidationFlags, - &SecConfig); - if (QUIC_FAILED(Status)) { - QuicTraceEvent( - ConnErrorStatus, - "[conn][%p] ERROR, %u, %s.", - Connection, - Status, - "QuicTlsClientSecConfigCreate"); - goto Error; - } + Connection->Stats.QuicVersion = QUIC_VERSION_LATEST; + QuicConnOnQuicVersionSet(Connection); } QUIC_DBG_ASSERT(!QuicListIsEmpty(&Connection->DestCids)); @@ -2459,16 +2340,13 @@ QuicConnHandshakeConfigure( goto Error; } - if (QuicConnIsServer(Connection)) { - - // - // Persist the transport parameters used during handshake for resumption. - // (if resumption is enabled) - // - if (Connection->HandshakeTP != NULL) { - QUIC_DBG_ASSERT(Connection->State.ResumptionEnabled); - *Connection->HandshakeTP = LocalTP; - } + // + // Persist the transport parameters used during handshake for resumption. + // (if resumption is enabled) + // + if (QuicConnIsServer(Connection) && Connection->HandshakeTP != NULL) { + QUIC_DBG_ASSERT(Connection->State.ResumptionEnabled); + *Connection->HandshakeTP = LocalTP; } Connection->State.Started = TRUE; @@ -2481,9 +2359,8 @@ QuicConnHandshakeConfigure( Status = QuicCryptoInitializeTls( &Connection->Crypto, - SecConfig, + Configuration->SecurityConfig, &LocalTP); - QuicTlsSecConfigRelease(SecConfig); // No longer need local ref. Error: @@ -2630,7 +2507,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) void QuicConnProcessPeerTransportParameters( _In_ QUIC_CONNECTION* Connection, - _In_ BOOLEAN FromCache + _In_ BOOLEAN FromResumptionTicket ) { QuicTraceLogConnInfo( @@ -2648,34 +2525,34 @@ QuicConnProcessPeerTransportParameters( Connection->SourceCidLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_DEFAULT; } - if (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_STATELESS_RESET_TOKEN) { - QUIC_DBG_ASSERT(!QuicListIsEmpty(&Connection->DestCids)); - QUIC_DBG_ASSERT(!QuicConnIsServer(Connection)); - QUIC_CID_QUIC_LIST_ENTRY* DestCid = - QUIC_CONTAINING_RECORD( - Connection->DestCids.Flink, - QUIC_CID_QUIC_LIST_ENTRY, - Link); - QuicCopyMemory( - DestCid->ResetToken, - Connection->PeerTransportParams.StatelessResetToken, - QUIC_STATELESS_RESET_TOKEN_LENGTH); - DestCid->CID.HasResetToken = TRUE; - } + if (!FromResumptionTicket) { + if (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_STATELESS_RESET_TOKEN) { + QUIC_DBG_ASSERT(!QuicListIsEmpty(&Connection->DestCids)); + QUIC_DBG_ASSERT(!QuicConnIsServer(Connection)); + QUIC_CID_QUIC_LIST_ENTRY* DestCid = + QUIC_CONTAINING_RECORD( + Connection->DestCids.Flink, + QUIC_CID_QUIC_LIST_ENTRY, + Link); + QuicCopyMemory( + DestCid->ResetToken, + Connection->PeerTransportParams.StatelessResetToken, + QUIC_STATELESS_RESET_TOKEN_LENGTH); + DestCid->CID.HasResetToken = TRUE; + } - if (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_PREFERRED_ADDRESS) { - /*QuicTraceLogConnInfo( - PeerPreferredAddress, - Connection, - "Peer configured preferred address %!ADDR!", - CLOG_BYTEARRAY(sizeof(Connection->PeerTransportParams.PreferredAddress), &Connection->PeerTransportParams.PreferredAddress));*/ + if (Connection->PeerTransportParams.Flags & QUIC_TP_FLAG_PREFERRED_ADDRESS) { + /*QuicTraceLogConnInfo( + PeerPreferredAddress, + Connection, + "Peer configured preferred address %!ADDR!", + CLOG_BYTEARRAY(sizeof(Connection->PeerTransportParams.PreferredAddress), &Connection->PeerTransportParams.PreferredAddress));*/ - // - // TODO - Implement preferred address feature. - // - } + // + // TODO - Implement preferred address feature. + // + } - if (!FromCache) { // // Version draft-28 and later fully validate all exchanged connection IDs. // Version draft-27 only validates in the Retry scenario. @@ -2698,7 +2575,7 @@ QuicConnProcessPeerTransportParameters( &Connection->Streams, Connection->PeerTransportParams.InitialMaxBidiStreams, Connection->PeerTransportParams.InitialMaxUniStreams, - !FromCache); + !FromResumptionTicket); QuicDatagramOnSendStateChanged(&Connection->Datagram); @@ -5245,11 +5122,12 @@ QuicConnResetIdleTimeout( // IdleTimeoutMs = Connection->PeerTransportParams.IdleTimeout; if (IdleTimeoutMs == 0 || - (Connection->IdleTimeoutMs != 0 && Connection->IdleTimeoutMs < IdleTimeoutMs)) { - IdleTimeoutMs = Connection->IdleTimeoutMs; + (Connection->Settings.IdleTimeoutMs != 0 && + Connection->Settings.IdleTimeoutMs < IdleTimeoutMs)) { + IdleTimeoutMs = Connection->Settings.IdleTimeoutMs; } } else { - IdleTimeoutMs = Connection->HandshakeIdleTimeoutMs; + IdleTimeoutMs = Connection->Settings.HandshakeIdleTimeoutMs; } if (IdleTimeoutMs != 0) { @@ -5271,11 +5149,11 @@ QuicConnResetIdleTimeout( QuicConnTimerCancel(Connection, QUIC_CONN_TIMER_IDLE); } - if (Connection->KeepAliveIntervalMs != 0) { + if (Connection->Settings.KeepAliveIntervalMs != 0) { QuicConnTimerSet( Connection, QUIC_CONN_TIMER_KEEP_ALIVE, - Connection->KeepAliveIntervalMs); + Connection->Settings.KeepAliveIntervalMs); } } @@ -5313,7 +5191,7 @@ QuicConnProcessKeepAliveOperation( QuicConnTimerSet( Connection, QUIC_CONN_TIMER_KEEP_ALIVE, - Connection->KeepAliveIntervalMs); + Connection->Settings.KeepAliveIntervalMs); } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -5399,12 +5277,15 @@ QuicConnParamSet( QUIC_DBG_ASSERT(Connection->Paths[0].Binding); QUIC_DBG_ASSERT(Connection->State.RemoteAddressSet); + QUIC_DBG_ASSERT(Connection->Configuration != NULL); QUIC_BINDING* OldBinding = Connection->Paths[0].Binding; Status = QuicLibraryGetBinding( - Connection->Session, +#ifdef QUIC_COMPARTMENT_ID + Connection->Configuration->CompartmentId, +#endif Connection->State.ShareBinding, FALSE, LocalAddress, @@ -5446,7 +5327,7 @@ QuicConnParamSet( break; } - case QUIC_PARAM_CONN_REMOTE_ADDRESS: { + case QUIC_PARAM_CONN_REMOTE_ADDRESS: if (BufferLength != sizeof(QUIC_ADDR)) { Status = QUIC_STATUS_INVALID_PARAMETER; @@ -5472,61 +5353,45 @@ QuicConnParamSet( Status = QUIC_STATUS_SUCCESS; break; - } - case QUIC_PARAM_CONN_IDLE_TIMEOUT: + case QUIC_PARAM_CONN_SETTINGS: - if (BufferLength != sizeof(Connection->IdleTimeoutMs)) { - Status = QUIC_STATUS_INVALID_PARAMETER; + if (BufferLength != sizeof(QUIC_SETTINGS)) { + Status = QUIC_STATUS_INVALID_PARAMETER; // TODO - Support partial break; } - if (Connection->State.Started) { - Status = QUIC_STATUS_INVALID_STATE; + if (!QuicConnApplyNewSettings( + Connection, + TRUE, + BufferLength, + (QUIC_SETTINGS*)Buffer)) { + Status = QUIC_STATUS_INVALID_PARAMETER; break; } - Connection->IdleTimeoutMs = *(uint64_t*)Buffer; - - QuicTraceLogConnInfo( - UpdateIdleTimeout, - Connection, - "Updated idle timeout to %llu milliseconds", - Connection->IdleTimeoutMs); - Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_PEER_BIDI_STREAM_COUNT: + case QUIC_PARAM_CONN_SHARE_UDP_BINDING: - if (BufferLength != sizeof(uint16_t)) { + if (BufferLength != sizeof(uint8_t)) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } - QuicStreamSetUpdateMaxCount( - &Connection->Streams, - QuicConnIsServer(Connection) ? - STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_BI_DIR : - STREAM_ID_FLAG_IS_SERVER | STREAM_ID_FLAG_IS_BI_DIR, - *(uint16_t*)Buffer); - - Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_PEER_UNIDI_STREAM_COUNT: - - if (BufferLength != sizeof(uint16_t)) { - Status = QUIC_STATUS_INVALID_PARAMETER; + if (Connection->State.Started || QuicConnIsServer(Connection)) { + Status = QUIC_STATUS_INVALID_STATE; break; } - QuicStreamSetUpdateMaxCount( - &Connection->Streams, - QuicConnIsServer(Connection) ? - STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_UNI_DIR : - STREAM_ID_FLAG_IS_SERVER | STREAM_ID_FLAG_IS_UNI_DIR, - *(uint16_t*)Buffer); + Connection->State.ShareBinding = *(uint8_t*)Buffer; + + QuicTraceLogConnInfo( + UpdateShareBinding, + Connection, + "Updated ShareBinding = %hhu", + Connection->State.ShareBinding); Status = QUIC_STATUS_SUCCESS; break; @@ -5573,206 +5438,118 @@ QuicConnParamSet( break; - case QUIC_PARAM_CONN_CERT_VALIDATION_FLAGS: + case QUIC_PARAM_CONN_STREAM_SCHEDULING_SCHEME: { - if (BufferLength != sizeof(Connection->ServerCertValidationFlags)) { + if (BufferLength != sizeof(QUIC_STREAM_SCHEDULING_SCHEME)) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } - if (QuicConnIsServer(Connection) || Connection->State.Started) { - // - // Only allowed on client connections, before the connection starts. - // - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - Connection->ServerCertValidationFlags = *(uint32_t*)Buffer; - - Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_KEEP_ALIVE: + QUIC_STREAM_SCHEDULING_SCHEME Scheme = + *(QUIC_STREAM_SCHEDULING_SCHEME*)Buffer; - if (BufferLength != sizeof(Connection->KeepAliveIntervalMs)) { + if (Scheme >= QUIC_STREAM_SCHEDULING_SCHEME_COUNT) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } - if (Connection->State.Started && - Connection->KeepAliveIntervalMs != 0) { - // - // Cancel any current timer first. - // - QuicConnTimerCancel(Connection, QUIC_CONN_TIMER_KEEP_ALIVE); - } - - Connection->KeepAliveIntervalMs = *(uint32_t*)Buffer; + Connection->State.UseRoundRobinStreamScheduling = + Scheme == QUIC_STREAM_SCHEDULING_SCHEME_ROUND_ROBIN; QuicTraceLogConnInfo( - UpdateKeepAlive, + UpdateStreamSchedulingScheme, Connection, - "Updated keep alive interval to %u milliseconds", - Connection->KeepAliveIntervalMs); - - if (Connection->State.Started && - Connection->KeepAliveIntervalMs != 0) { - QuicConnProcessKeepAliveOperation(Connection); - } + "Updated Stream Scheduling Scheme = %u", + Scheme); Status = QUIC_STATUS_SUCCESS; break; + } - case QUIC_PARAM_CONN_DISCONNECT_TIMEOUT: + case QUIC_PARAM_CONN_DATAGRAM_RECEIVE_ENABLED: - if (BufferLength != sizeof(Connection->DisconnectTimeoutUs)) { + if (BufferLength != sizeof(BOOLEAN)) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } - if (*(uint32_t*)Buffer == 0 || - *(uint32_t*)Buffer > QUIC_MAX_DISCONNECT_TIMEOUT) { - Status = QUIC_STATUS_INVALID_PARAMETER; + if (Connection->State.Started) { + Status = QUIC_STATUS_INVALID_STATE; break; } - Connection->DisconnectTimeoutUs = MS_TO_US(*(uint32_t*)Buffer); + Connection->Datagram.ReceiveEnabled = *(BOOLEAN*)Buffer; + Status = QUIC_STATUS_SUCCESS; - QuicTraceLogConnInfo( - UpdateDisconnectTimeout, + QuicTraceLogConnVerbose( + DatagramReceiveEnableUpdated, Connection, - "Updated disconnect timeout = %u milliseconds", - *(uint32_t*)Buffer); + "Updated datagram receive enabled to %hhu", + Connection->Datagram.ReceiveEnabled); - Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_SEC_CONFIG: { - - if (BufferLength != sizeof(QUIC_SEC_CONFIG*)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - QUIC_SEC_CONFIG* SecConfig = *(QUIC_SEC_CONFIG**)Buffer; + case QUIC_PARAM_CONN_DISABLE_1RTT_ENCRYPTION: - if (SecConfig == NULL) { + if (BufferLength != sizeof(BOOLEAN)) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } - if (!QuicConnIsServer(Connection) || - Connection->State.ListenerAccepted == FALSE || - Connection->Crypto.TLS != NULL) { + if (Connection->State.Started) { Status = QUIC_STATUS_INVALID_STATE; break; } - QuicTraceLogConnInfo( - SetSecurityConfig, - Connection, - "Security config set, %p", - SecConfig); - (void)QuicTlsSecConfigAddRef(SecConfig); - - Status = - QuicConnHandshakeConfigure( - Connection, - SecConfig); - if (QUIC_FAILED(Status)) { - break; - } - - QuicCryptoProcessData(&Connection->Crypto, FALSE); - break; - } - - case QUIC_PARAM_CONN_SEND_BUFFERING: - - if (BufferLength != sizeof(uint8_t)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - Connection->State.UseSendBuffer = *(uint8_t*)Buffer; - - QuicTraceLogConnInfo( - UpdateUseSendBuffer, - Connection, - "Updated UseSendBuffer = %hhu", - Connection->State.UseSendBuffer); - + Connection->State.Disable1RttEncrytion = *(BOOLEAN*)Buffer; Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_SEND_PACING: - - if (BufferLength != sizeof(uint8_t)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - Connection->State.UsePacing = *(uint8_t*)Buffer; - QuicTraceLogConnInfo( - UpdateUsePacing, + QuicTraceLogConnVerbose( + Disable1RttEncrytionUpdated, Connection, - "Updated UsePacing = %hhu", - Connection->State.UsePacing); + "Updated disable 1-RTT encrytption to %hhu", + Connection->State.Disable1RttEncrytion); - Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_SHARE_UDP_BINDING: - - if (BufferLength != sizeof(uint8_t)) { + case QUIC_PARAM_CONN_RESUMPTION_STATE: { + if (BufferLength == 0 || Buffer == NULL) { Status = QUIC_STATUS_INVALID_PARAMETER; break; } - if (Connection->State.Started || QuicConnIsServer(Connection)) { + // + // Must be set before the client connection is started. + // + if (QuicConnIsServer(Connection) || Connection->State.Started) { Status = QUIC_STATUS_INVALID_STATE; break; } - Connection->State.ShareBinding = *(uint8_t*)Buffer; - - QuicTraceLogConnInfo( - UpdateShareBinding, - Connection, - "Updated ShareBinding = %hhu", - Connection->State.ShareBinding); - - Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_STREAM_SCHEDULING_SCHEME: { - - if (BufferLength != sizeof(QUIC_STREAM_SCHEDULING_SCHEME)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - QUIC_STREAM_SCHEDULING_SCHEME Scheme = - *(QUIC_STREAM_SCHEDULING_SCHEME*)Buffer; - - if (Scheme >= QUIC_STREAM_SCHEDULING_SCHEME_COUNT) { - Status = QUIC_STATUS_INVALID_PARAMETER; + Status = + QuicCryptoDecodeClientTicket( + Connection, + (uint16_t)BufferLength, + Buffer, + &Connection->PeerTransportParams, + &Connection->Crypto.ResumptionTicket, + &Connection->Crypto.ResumptionTicketLength, + &Connection->Stats.QuicVersion); + if (QUIC_FAILED(Status)) { break; } - Connection->State.UseRoundRobinStreamScheduling = - Scheme == QUIC_STREAM_SCHEDULING_SCHEME_ROUND_ROBIN; - - QuicTraceLogConnInfo( - UpdateStreamSchedulingScheme, - Connection, - "Updated Stream Scheduling Scheme = %u", - Scheme); + QuicConnOnQuicVersionSet(Connection); + QuicConnProcessPeerTransportParameters(Connection, TRUE); Status = QUIC_STATUS_SUCCESS; break; } + // + // Private + // + case QUIC_PARAM_CONN_FORCE_KEY_UPDATE: if (!Connection->State.Connected || @@ -5825,52 +5602,6 @@ QuicConnParamSet( Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_DATAGRAM_RECEIVE_ENABLED: - - if (BufferLength != sizeof(BOOLEAN)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - if (Connection->State.Started) { - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - Connection->Datagram.ReceiveEnabled = *(BOOLEAN*)Buffer; - Status = QUIC_STATUS_SUCCESS; - - QuicTraceLogConnVerbose( - DatagramReceiveEnableUpdated, - Connection, - "Updated datagram receive enabled to %hhu", - Connection->Datagram.ReceiveEnabled); - - break; - - case QUIC_PARAM_CONN_DISABLE_1RTT_ENCRYPTION: - - if (BufferLength != sizeof(BOOLEAN)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - if (Connection->State.Started) { - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - Connection->State.Disable1RttEncrytion = *(BOOLEAN*)Buffer; - Status = QUIC_STATUS_SUCCESS; - - QuicTraceLogConnVerbose( - Disable1RttEncrytionUpdated, - Connection, - "Updated disable 1-RTT encrytption to %hhu", - Connection->State.Disable1RttEncrytion); - - break; - case QUIC_PARAM_CONN_TEST_TRANSPORT_PARAMETER: if (BufferLength != sizeof(QUIC_PRIVATE_TRANSPORT_PARAMETER)) { @@ -5994,51 +5725,8 @@ QuicConnParamGet( Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_IDLE_TIMEOUT: - - if (*BufferLength < sizeof(Connection->IdleTimeoutMs)) { - *BufferLength = sizeof(Connection->IdleTimeoutMs); - Status = QUIC_STATUS_BUFFER_TOO_SMALL; - break; - } - - if (Buffer == NULL) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - *BufferLength = sizeof(Connection->IdleTimeoutMs); - *(uint64_t*)Buffer = Connection->IdleTimeoutMs; - - Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_PEER_BIDI_STREAM_COUNT: - Type = - QuicConnIsServer(Connection) ? - STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_BI_DIR : - STREAM_ID_FLAG_IS_SERVER | STREAM_ID_FLAG_IS_BI_DIR; - goto Get_Stream_Count; - case QUIC_PARAM_CONN_PEER_UNIDI_STREAM_COUNT: - Type = - QuicConnIsServer(Connection) ? - STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_UNI_DIR : - STREAM_ID_FLAG_IS_SERVER | STREAM_ID_FLAG_IS_UNI_DIR; - goto Get_Stream_Count; - case QUIC_PARAM_CONN_LOCAL_BIDI_STREAM_COUNT: - Type = - QuicConnIsServer(Connection) ? - STREAM_ID_FLAG_IS_SERVER | STREAM_ID_FLAG_IS_BI_DIR : - STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_BI_DIR; - goto Get_Stream_Count; - case QUIC_PARAM_CONN_LOCAL_UNIDI_STREAM_COUNT: - Type = - QuicConnIsServer(Connection) ? - STREAM_ID_FLAG_IS_SERVER | STREAM_ID_FLAG_IS_UNI_DIR : - STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_UNI_DIR; - goto Get_Stream_Count; + case QUIC_PARAM_CONN_IDEAL_PROCESSOR: - Get_Stream_Count: if (*BufferLength < sizeof(uint16_t)) { *BufferLength = sizeof(uint16_t); Status = QUIC_STATUS_BUFFER_TOO_SMALL; @@ -6051,22 +5739,15 @@ QuicConnParamGet( } *BufferLength = sizeof(uint16_t); - *(uint16_t*)Buffer = - QuicStreamSetGetCountAvailable(&Connection->Streams, Type); + *(uint16_t*)Buffer = Connection->Worker->IdealProcessor; Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_CLOSE_REASON_PHRASE: + case QUIC_PARAM_CONN_SETTINGS: - if (Connection->CloseReasonPhrase == NULL) { - Status = QUIC_STATUS_NOT_FOUND; - break; - } - - Length = (uint32_t)strlen(Connection->CloseReasonPhrase) + 1; - if (*BufferLength < Length) { - *BufferLength = Length; + if (*BufferLength < sizeof(QUIC_SETTINGS)) { + *BufferLength = sizeof(QUIC_SETTINGS); Status = QUIC_STATUS_BUFFER_TOO_SMALL; break; } @@ -6076,8 +5757,8 @@ QuicConnParamGet( break; } - *BufferLength = Length; - QuicCopyMemory(Buffer, Connection->CloseReasonPhrase, Length); + *BufferLength = sizeof(QUIC_SETTINGS); + *(QUIC_SETTINGS*)Buffer = Connection->Settings; Status = QUIC_STATUS_SUCCESS; break; @@ -6139,123 +5820,7 @@ QuicConnParamGet( break; } - case QUIC_PARAM_CONN_CERT_VALIDATION_FLAGS: - - if (*BufferLength < sizeof(Connection->ServerCertValidationFlags)) { - *BufferLength = sizeof(Connection->ServerCertValidationFlags); - Status = QUIC_STATUS_BUFFER_TOO_SMALL; - break; - } - - if (Buffer == NULL) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - *BufferLength = sizeof(Connection->ServerCertValidationFlags); - *(uint32_t*)Buffer = Connection->ServerCertValidationFlags; - - Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_KEEP_ALIVE: - - if (*BufferLength < sizeof(Connection->KeepAliveIntervalMs)) { - *BufferLength = sizeof(Connection->KeepAliveIntervalMs); - Status = QUIC_STATUS_BUFFER_TOO_SMALL; - break; - } - - if (Buffer == NULL) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - *BufferLength = sizeof(Connection->KeepAliveIntervalMs); - *(uint32_t*)Buffer = Connection->KeepAliveIntervalMs; - - Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_DISCONNECT_TIMEOUT: - - if (*BufferLength < sizeof(Connection->DisconnectTimeoutUs)) { - *BufferLength = sizeof(Connection->DisconnectTimeoutUs); - Status = QUIC_STATUS_BUFFER_TOO_SMALL; - break; - } - - if (Buffer == NULL) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - *BufferLength = sizeof(uint32_t); - *(uint32_t*)Buffer = US_TO_MS(Connection->DisconnectTimeoutUs); - - Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_RESUMPTION_STATE: { - - if (QuicConnIsServer(Connection)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - if (Connection->RemoteServerName == NULL) { - Status = QUIC_STATUS_INVALID_STATE; - break; - } - - uint32_t RequiredBufferLength = 0; - Status = QuicTlsReadTicket(Connection->Crypto.TLS, &RequiredBufferLength, NULL); - if (Status != QUIC_STATUS_BUFFER_TOO_SMALL) { - QuicTraceLogConnVerbose( - ReadTicketFailure, - Connection, - "QuicTlsReadTicket failed, 0x%x", - Status); - break; - } - - _Analysis_assume_(strlen(Connection->RemoteServerName) <= (size_t)UINT16_MAX); - uint16_t RemoteServerNameLength = (uint16_t)strlen(Connection->RemoteServerName); - - QUIC_SERIALIZED_RESUMPTION_STATE* State = - (QUIC_SERIALIZED_RESUMPTION_STATE*)Buffer; - - RequiredBufferLength += sizeof(QUIC_SERIALIZED_RESUMPTION_STATE); - RequiredBufferLength += RemoteServerNameLength; - - if (*BufferLength < RequiredBufferLength) { - *BufferLength = RequiredBufferLength; - Status = QUIC_STATUS_BUFFER_TOO_SMALL; - break; - } - - if (Buffer == NULL) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - State->QuicVersion = Connection->Stats.QuicVersion; - State->TransportParameters = Connection->PeerTransportParams; - State->ServerNameLength = RemoteServerNameLength; - memcpy(State->Buffer, Connection->RemoteServerName, State->ServerNameLength); - - uint32_t TempBufferLength = *BufferLength - RemoteServerNameLength; - Status = - QuicTlsReadTicket( - Connection->Crypto.TLS, - &TempBufferLength, - State->Buffer + RemoteServerNameLength); - *BufferLength = RequiredBufferLength; - - break; - } - - case QUIC_PARAM_CONN_SEND_BUFFERING: + case QUIC_PARAM_CONN_SHARE_UDP_BINDING: if (*BufferLength < sizeof(uint8_t)) { *BufferLength = sizeof(uint8_t); @@ -6269,15 +5834,28 @@ QuicConnParamGet( } *BufferLength = sizeof(uint8_t); - *(uint8_t*)Buffer = Connection->State.UseSendBuffer; + *(uint8_t*)Buffer = Connection->State.ShareBinding; Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_SEND_PACING: + case QUIC_PARAM_CONN_LOCAL_BIDI_STREAM_COUNT: + Type = + QuicConnIsServer(Connection) ? + STREAM_ID_FLAG_IS_SERVER | STREAM_ID_FLAG_IS_BI_DIR : + STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_BI_DIR; + goto Get_Stream_Count; - if (*BufferLength < sizeof(uint8_t)) { - *BufferLength = sizeof(uint8_t); + case QUIC_PARAM_CONN_LOCAL_UNIDI_STREAM_COUNT: + Type = + QuicConnIsServer(Connection) ? + STREAM_ID_FLAG_IS_SERVER | STREAM_ID_FLAG_IS_UNI_DIR : + STREAM_ID_FLAG_IS_CLIENT | STREAM_ID_FLAG_IS_UNI_DIR; + goto Get_Stream_Count; + + Get_Stream_Count: + if (*BufferLength < sizeof(uint16_t)) { + *BufferLength = sizeof(uint16_t); Status = QUIC_STATUS_BUFFER_TOO_SMALL; break; } @@ -6287,16 +5865,17 @@ QuicConnParamGet( break; } - *BufferLength = sizeof(uint8_t); - *(uint8_t*)Buffer = Connection->State.UsePacing; + *BufferLength = sizeof(uint16_t); + *(uint16_t*)Buffer = + QuicStreamSetGetCountAvailable(&Connection->Streams, Type); Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_SHARE_UDP_BINDING: + case QUIC_PARAM_CONN_MAX_STREAM_IDS: - if (*BufferLength < sizeof(uint8_t)) { - *BufferLength = sizeof(uint8_t); + if (*BufferLength < sizeof(uint64_t) * NUMBER_OF_STREAM_TYPES) { + *BufferLength = sizeof(uint64_t) * NUMBER_OF_STREAM_TYPES; Status = QUIC_STATUS_BUFFER_TOO_SMALL; break; } @@ -6306,35 +5885,22 @@ QuicConnParamGet( break; } - *BufferLength = sizeof(uint8_t); - *(uint8_t*)Buffer = Connection->State.ShareBinding; + *BufferLength = sizeof(uint64_t) * NUMBER_OF_STREAM_TYPES; + QuicStreamSetGetMaxStreamIDs(&Connection->Streams, (uint64_t*)Buffer); Status = QUIC_STATUS_SUCCESS; break; - case QUIC_PARAM_CONN_IDEAL_PROCESSOR: - - if (*BufferLength < sizeof(uint16_t)) { - *BufferLength = sizeof(uint16_t); - Status = QUIC_STATUS_BUFFER_TOO_SMALL; - break; - } + case QUIC_PARAM_CONN_CLOSE_REASON_PHRASE: - if (Buffer == NULL) { - Status = QUIC_STATUS_INVALID_PARAMETER; + if (Connection->CloseReasonPhrase == NULL) { + Status = QUIC_STATUS_NOT_FOUND; break; } - *BufferLength = sizeof(uint16_t); - *(uint16_t*)Buffer = Connection->Worker->IdealProcessor; - - Status = QUIC_STATUS_SUCCESS; - break; - - case QUIC_PARAM_CONN_MAX_STREAM_IDS: - - if (*BufferLength < sizeof(uint64_t) * NUMBER_OF_STREAM_TYPES) { - *BufferLength = sizeof(uint64_t) * NUMBER_OF_STREAM_TYPES; + Length = (uint32_t)strlen(Connection->CloseReasonPhrase) + 1; + if (*BufferLength < Length) { + *BufferLength = Length; Status = QUIC_STATUS_BUFFER_TOO_SMALL; break; } @@ -6344,8 +5910,8 @@ QuicConnParamGet( break; } - *BufferLength = sizeof(uint64_t) * NUMBER_OF_STREAM_TYPES; - QuicStreamSetGetMaxStreamIDs(&Connection->Streams, (uint64_t*)Buffer); + *BufferLength = Length; + QuicCopyMemory(Buffer, Connection->CloseReasonPhrase, Length); Status = QUIC_STATUS_SUCCESS; break; @@ -6436,6 +6002,91 @@ QuicConnParamGet( return Status; } +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicConnApplyNewSettings( + _In_ QUIC_CONNECTION* Connection, + _In_ BOOLEAN OverWrite, + _In_range_(FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey), UINT32_MAX) + uint32_t NewSettingsSize, + _In_reads_bytes_(NewSettingsSize) + const QUIC_SETTINGS* NewSettings + ) +{ + QuicTraceLogConnInfo( + ApplySettings, + Connection, + "Applying new settings"); + + if (!QuicSettingApply( + &Connection->Settings, + OverWrite, + NewSettingsSize, + NewSettings)) { + return FALSE; + } + + if (!Connection->State.Started) { + + Connection->Paths[0].SmoothedRtt = MS_TO_US(Connection->Settings.InitialRttMs); + Connection->Paths[0].RttVariance = Connection->Paths[0].SmoothedRtt / 2; + Connection->Datagram.ReceiveEnabled = Connection->Settings.DatagramReceiveEnabled; + + if (Connection->Settings.ServerResumptionLevel > QUIC_SERVER_NO_RESUME && + Connection->HandshakeTP == NULL) { + QUIC_DBG_ASSERT(!Connection->State.Started); + Connection->HandshakeTP = + QuicPoolAlloc(&MsQuicLib.PerProc[QuicProcCurrentNumber()].TransportParamPool); + if (Connection->HandshakeTP == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "handshake TP", + sizeof(*Connection->HandshakeTP)); + } else { + QuicZeroMemory(Connection->HandshakeTP, sizeof(*Connection->HandshakeTP)); + Connection->State.ResumptionEnabled = TRUE; + } + } + + QuicSendApplyNewSettings(&Connection->Send, &Connection->Settings); + QuicCongestionControlInitialize(&Connection->CongestionControl, &Connection->Settings); + } + + uint8_t PeerStreamType = + QuicConnIsServer(Connection) ? + STREAM_ID_FLAG_IS_CLIENT : STREAM_ID_FLAG_IS_SERVER; + + if (NewSettings->IsSet.PeerBidiStreamCount) { + QuicStreamSetUpdateMaxCount( + &Connection->Streams, + PeerStreamType | STREAM_ID_FLAG_IS_BI_DIR, + Connection->Settings.PeerBidiStreamCount); + } + if (NewSettings->IsSet.PeerUnidiStreamCount) { + QuicStreamSetUpdateMaxCount( + &Connection->Streams, + PeerStreamType | STREAM_ID_FLAG_IS_UNI_DIR, + Connection->Settings.PeerUnidiStreamCount); + } + + if (NewSettings->IsSet.KeepAliveIntervalMs && Connection->State.Started) { + if (Connection->Settings.KeepAliveIntervalMs != 0) { + QuicConnProcessKeepAliveOperation(Connection);; + } else { + QuicConnTimerCancel(Connection, QUIC_CONN_TIMER_KEEP_ALIVE); + } + } + + if (OverWrite) { + QuicSettingsDumpNew(NewSettingsSize, NewSettings); + } else { + QuicSettingsDump(&Connection->Settings); // TODO - Really necessary? + } + + return TRUE; +} + _IRQL_requires_max_(PASSIVE_LEVEL) void QuicConnProcessApiOperation( @@ -6462,12 +6113,20 @@ QuicConnProcessApiOperation( Status = QuicConnStart( Connection, + ApiCtx->CONN_START.Configuration, ApiCtx->CONN_START.Family, ApiCtx->CONN_START.ServerName, ApiCtx->CONN_START.ServerPort); ApiCtx->CONN_START.ServerName = NULL; break; + case QUIC_API_TYPE_CONN_SET_CONFIGURATION: + Status = + QuicConnSetConfiguration( + Connection, + ApiCtx->CONN_SET_CONFIGURATION.Configuration); + break; + case QUIC_API_TYPE_CONN_SEND_RESUMPTION_TICKET: QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); Status = @@ -6590,9 +6249,7 @@ QuicConnDrainOperations( { QUIC_OPERATION* Oper; const uint32_t MaxOperationCount = - (Connection->Session == NULL || Connection->Session->Registration == NULL) ? - MsQuicLib.Settings.MaxOperationsPerDrain : - Connection->Session->Settings.MaxOperationsPerDrain; + Connection->Settings.MaxOperationsPerDrain; uint32_t OperationCount = 0; BOOLEAN HasMoreWorkToDo = TRUE; @@ -6605,7 +6262,7 @@ QuicConnDrainOperations( // QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); QUIC_STATUS Status; - if (QUIC_FAILED(Status = QuicConnInitializeCrypto(Connection))) { + if (QUIC_FAILED(Status = QuicCryptoInitialize(&Connection->Crypto))) { QuicConnFatalError(Connection, Status, "Lazily initialize failure"); } else { Connection->State.Initialized = TRUE; @@ -6613,6 +6270,12 @@ QuicConnDrainOperations( ConnInitializeComplete, "[conn][%p] Initialize complete", Connection); + if (Connection->Settings.KeepAliveIntervalMs != 0) { + QuicConnTimerSet( + Connection, + QUIC_CONN_TIMER_KEEP_ALIVE, + Connection->Settings.KeepAliveIntervalMs); + } } } diff --git a/src/core/connection.h b/src/core/connection.h index 56b07487c2..1db907fe7f 100644 --- a/src/core/connection.h +++ b/src/core/connection.h @@ -45,8 +45,12 @@ typedef union QUIC_CONNECTION_STATE { // Indicates whether packet number encryption is enabled or not for the // connection. // - BOOLEAN HeaderProtectionEnabled : 1; + BOOLEAN HeaderProtectionEnabled : 1; // TODO - Remove since it's not used + // + // Indicates that 1-RTT encryption has been configured/negotiated to be + // disabled. + // BOOLEAN Disable1RttEncrytion : 1; // @@ -57,6 +61,12 @@ typedef union QUIC_CONNECTION_STATE { // BOOLEAN ExternalOwner : 1; + // + // Indicate the connection is currently in the registration's list of + // connections and needs to be removed. + // + BOOLEAN Registered : 1; + // // This flag indicates the client has gotten response from the server. // The response could either be a Retry or server Initial packet. Once @@ -114,16 +124,6 @@ typedef union QUIC_CONNECTION_STATE { // BOOLEAN SendShutdownCompleteNotif : 1; - // - // Indicates whether send requests should be buffered. - // - BOOLEAN UseSendBuffer : 1; - - // - // Indicates whether pacing logic is enabled for sending. - // - BOOLEAN UsePacing : 1; - // // Indicates whether this connection shares bindings with others. // @@ -272,9 +272,9 @@ typedef struct QUIC_CONNECTION { struct QUIC_HANDLE; // - // Link into the session's list of connections. + // Link into the registrations's list of connections. // - QUIC_LIST_ENTRY SessionLink; + QUIC_LIST_ENTRY RegistrationLink; // // Link in the worker's connection queue. @@ -298,9 +298,15 @@ typedef struct QUIC_CONNECTION { QUIC_REGISTRATION* Registration; // - // The top level session this connection is a part of. + // The configuration for this connection. // - QUIC_SESSION* Session; + QUIC_CONFIGURATION* Configuration; + + // + // The settings for this connection. Some values may be inherited from the + // global settings, the configuration setting or explicitly set by the app. + // + QUIC_SETTINGS Settings; // // Number of references to the handle. @@ -324,11 +330,6 @@ typedef struct QUIC_CONNECTION { // QUIC_THREAD_ID WorkerThreadID; - // - // The set of ignore flags for server certificate validation to pass to TLS. - // - uint32_t ServerCertValidationFlags; - // // The server ID for the connection ID. // @@ -379,33 +380,6 @@ typedef struct QUIC_CONNECTION { // uint8_t AckDelayExponent; - // - // Maximum amount of time the connection waits before acknowledging a - // received packet. - // - uint32_t MaxAckDelayMs; - - // - // The idle timeout period (in milliseconds). - // - uint64_t IdleTimeoutMs; - - // - // The handshake idle timeout period (in milliseconds). - // - uint64_t HandshakeIdleTimeoutMs; - - // - // The number of microseconds that must elapse before the connection will be - // considered 'ACK idle' and disconnects. - // - uint32_t DisconnectTimeoutUs; - - // - // The interval (in milliseconds) between keep alives sent locally. - // - uint32_t KeepAliveIntervalMs; - // // The sequence number to use for the next source CID. // @@ -558,6 +532,15 @@ typedef struct QUIC_CONNECTION { } QUIC_CONNECTION; +typedef struct QUIC_SERIALIZED_RESUMPTION_STATE { + + uint32_t QuicVersion; + QUIC_TRANSPORT_PARAMETERS TransportParameters; + uint16_t ServerNameLength; + uint8_t Buffer[0]; // ServerName and TLS Session/Ticket + +} QUIC_SERIALIZED_RESUMPTION_STATE; + // // Estimates the memory usage for a connection object in the handshake state. // TODO - Improve this estimate? @@ -832,7 +815,7 @@ _Must_inspect_result_ _Success_(return != NULL) QUIC_CONNECTION* QuicConnAlloc( - _In_ QUIC_SESSION* Session, + _In_ QUIC_REGISTRATION* Registration, _In_opt_ const QUIC_RECV_DATAGRAM* const Datagram ); @@ -942,6 +925,16 @@ QuicConnRelease( } #pragma warning(pop) +// +// Registers the connection with a registration. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +void +QuicConnRegister( + _Inout_ QUIC_CONNECTION* Connection, + _Inout_ QUIC_REGISTRATION* Registration + ); + // // Tracing rundown for the connection. // @@ -972,16 +965,6 @@ QuicConnDrainOperations( _In_ QUIC_CONNECTION* Connection ); -// -// Applies the settings from the session. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicConnApplySettings( - _In_ QUIC_CONNECTION* Connection, - _In_ const QUIC_SETTINGS* Settings - ); - // // Queues a new operation on the connection and queues the connection on a // worker if necessary. @@ -1191,18 +1174,6 @@ QuicConnOnLocalAddressChanged( _In_ QUIC_CONNECTION* Connection ); -// -// Starts the connection. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicConnStart( - _In_ QUIC_CONNECTION* Connection, - _In_ QUIC_ADDRESS_FAMILY Family, - _In_opt_z_ const char* ServerName, - _In_ uint16_t ServerPort // Host byte order - ); - // // Restarts the connection with the current configuration. // @@ -1225,13 +1196,13 @@ QuicConnProcessPeerTransportParameters( ); // -// Configures the security config. +// Sets the configuration handle. // _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS -QuicConnHandshakeConfigure( +QuicConnSetConfiguration( _In_ QUIC_CONNECTION* Connection, - _In_opt_ QUIC_SEC_CONFIG* SecConfig + _In_ QUIC_CONFIGURATION* Configuration ); // diff --git a/src/core/core.kernel.vcxproj b/src/core/core.kernel.vcxproj index 90bbe25487..2b8e180430 100644 --- a/src/core/core.kernel.vcxproj +++ b/src/core/core.kernel.vcxproj @@ -38,6 +38,7 @@ + @@ -60,7 +61,6 @@ - @@ -74,6 +74,7 @@ + @@ -96,7 +97,6 @@ - diff --git a/src/core/crypto.c b/src/core/crypto.c index a002fee1db..8302f89b15 100644 --- a/src/core/crypto.c +++ b/src/core/crypto.c @@ -25,7 +25,7 @@ QUIC_TLS_PROCESS_COMPLETE_CALLBACK QuicTlsProcessDataCompleteCallback; QUIC_TLS_RECEIVE_TP_CALLBACK QuicConnReceiveTP; -QUIC_TLS_RECEIVE_RESUMPTION_CALLBACK QuicConnRecvResumptionTicket; +QUIC_TLS_RECEIVE_TICKET_CALLBACK QuicConnRecvResumptionTicket; _IRQL_requires_max_(PASSIVE_LEVEL) void @@ -235,6 +235,15 @@ QuicCryptoUninitialize( QuicTlsUninitialize(Crypto->TLS); Crypto->TLS = NULL; } + if (Crypto->ResumptionTicket != NULL) { + QUIC_FREE(Crypto->ResumptionTicket); + Crypto->ResumptionTicket = NULL; + } + if (Crypto->TlsState.NegotiatedAlpn != NULL && + QuicConnIsServer(QuicCryptoGetConnection(Crypto))) { + QUIC_FREE(Crypto->TlsState.NegotiatedAlpn); + Crypto->TlsState.NegotiatedAlpn = NULL; + } if (Crypto->Initialized) { QuicRecvBufferUninitialize(&Crypto->RecvBuffer); QuicRangeUninitialize(&Crypto->SparseAckRanges); @@ -259,20 +268,20 @@ QuicCryptoInitializeTls( QUIC_DBG_ASSERT(Params != NULL); QUIC_DBG_ASSERT(SecConfig != NULL); - QUIC_DBG_ASSERT(Connection->Session != NULL); - QUIC_DBG_ASSERT(Connection->Session->TlsSession != NULL); + QUIC_DBG_ASSERT(Connection->Configuration != NULL); TlsConfig.IsServer = IsServer; - TlsConfig.TlsSession = Connection->Session->TlsSession; if (IsServer) { TlsConfig.AlpnBuffer = Crypto->TlsState.NegotiatedAlpn; TlsConfig.AlpnBufferLength = 1 + Crypto->TlsState.NegotiatedAlpn[0]; } else { - TlsConfig.AlpnBuffer = Connection->Session->AlpnList; - TlsConfig.AlpnBufferLength = Connection->Session->AlpnListLength; + TlsConfig.AlpnBuffer = Connection->Configuration->AlpnList; + TlsConfig.AlpnBufferLength = Connection->Configuration->AlpnListLength; } TlsConfig.SecConfig = SecConfig; TlsConfig.Connection = Connection; + TlsConfig.ResumptionTicketBuffer = Crypto->ResumptionTicket; + TlsConfig.ResumptionTicketLength = Crypto->ResumptionTicketLength; TlsConfig.ProcessCompleteCallback = QuicTlsProcessDataCompleteCallback; TlsConfig.ReceiveTPCallback = QuicConnReceiveTP; TlsConfig.ReceiveResumptionCallback = QuicConnRecvResumptionTicket; @@ -283,7 +292,10 @@ QuicCryptoInitializeTls( TlsConfig.LocalTPBuffer = QuicCryptoTlsEncodeTransportParameters( Connection, + QuicConnIsServer(Connection), Params, + (Connection->State.TestTransportParameterSet ? + &Connection->TestTransportParameter : NULL), &TlsConfig.LocalTPLength); if (TlsConfig.LocalTPBuffer == NULL) { Status = QUIC_STATUS_OUT_OF_MEMORY; @@ -302,9 +314,9 @@ QuicCryptoInitializeTls( goto Error; } - if (!IsServer) { - QuicCryptoProcessData(Crypto, TRUE); - } + Crypto->ResumptionTicket = NULL; // Owned by TLS now. + Crypto->ResumptionTicketLength = 0; + QuicCryptoProcessData(Crypto, !IsServer); Error: @@ -1143,6 +1155,7 @@ QuicConnReceiveTP( { if (!QuicCryptoTlsDecodeTransportParameters( Connection, + !QuicConnIsServer(Connection), TPBuffer, TPLength, &Connection->PeerTransportParams)) { @@ -1371,37 +1384,17 @@ QuicCryptoProcessTlsCompletion( QuicConnGenerateNewSourceCids(Connection, FALSE); - if (!QuicConnIsServer(Connection) && - Connection->RemoteServerName != NULL) { - - QUIC_SEC_CONFIG* SecConfig = QuicTlsGetSecConfig(Crypto->TLS); - - // - // Cache this information for future connections in this - // session to make use of. - // - QUIC_TEL_ASSERT(Connection->Session != NULL); - QuicSessionServerCacheSetState( - Connection->Session, - Connection->RemoteServerName, - Connection->Stats.QuicVersion, - &Connection->PeerTransportParams, - SecConfig); - - QuicTlsSecConfigRelease(SecConfig); - } - QUIC_DBG_ASSERT(Crypto->TlsState.NegotiatedAlpn != NULL); if (!QuicConnIsServer(Connection)) { // // Currently, NegotiatedAlpn points into TLS state memory, which // doesn't live as long as the connection. Update it to point to the - // session state memory instead. + // configuration state memory instead. // Crypto->TlsState.NegotiatedAlpn = QuicTlsAlpnFindInList( - Connection->Session->AlpnListLength, - Connection->Session->AlpnList, + Connection->Configuration->AlpnListLength, + Connection->Configuration->AlpnList, Crypto->TlsState.NegotiatedAlpn[0], Crypto->TlsState.NegotiatedAlpn + 1); QUIC_TEL_ASSERT(Crypto->TlsState.NegotiatedAlpn != NULL); @@ -1432,13 +1425,6 @@ QuicCryptoProcessTlsCompletion( } } - if (ResultFlags & QUIC_TLS_RESULT_TICKET) { - QuicTraceLogConnInfo( - TicketReady, - Connection, - "Ticket ready"); - } - QuicCryptoValidate(Crypto); if (ResultFlags & QUIC_TLS_RESULT_READ_KEY_UPDATED) { @@ -1545,13 +1531,12 @@ QuicCryptoProcessData( goto Error; } - if (BufferOffset == 0 && - QuicConnIsServer(Connection) && - !Connection->State.ExternalOwner) { + if (QuicConnIsServer(Connection) && !Connection->State.ListenerAccepted) { // // Preprocess the TLS ClientHello to find the ALPN (and optionally // SNI) to match the connection to a listener. // + QUIC_DBG_ASSERT(BufferOffset == 0); QUIC_NEW_CONNECTION_INFO Info = {0}; QUIC_STATUS Status = QuicCryptoTlsReadInitial( @@ -1571,72 +1556,24 @@ QuicCryptoProcessData( goto Error; } + QuicRecvBufferDrain(&Crypto->RecvBuffer, 0); + QuicCryptoValidate(Crypto); + Info.QuicVersion = Connection->Stats.QuicVersion; Info.LocalAddress = &Connection->Paths[0].LocalAddress; Info.RemoteAddress = &Connection->Paths[0].RemoteAddress; Info.CryptoBufferLength = Buffer.Length; Info.CryptoBuffer = Buffer.Buffer; - QUIC_CONNECTION_ACCEPT_RESULT AcceptResult = - QUIC_CONNECTION_REJECT_NO_LISTENER; - - QUIC_SEC_CONFIG* SecConfig = NULL; - QUIC_LISTENER* Listener = - QuicBindingGetListener( - Connection->Paths[0].Binding, - &Info); - if (Listener != NULL) { - AcceptResult = - QuicListenerAcceptConnection( - Listener, - Connection, - &Info, - &SecConfig); - QuicRundownRelease(&Listener->Rundown); - } - - if (AcceptResult != QUIC_CONNECTION_ACCEPT) { - QuicTraceEvent( - ConnErrorStatus, - "[conn][%p] ERROR, %u, %s.", - Connection, - AcceptResult, - "Connection rejected"); - if (AcceptResult == QUIC_CONNECTION_REJECT_NO_LISTENER) { - QuicConnTransportError( - Connection, - QUIC_ERROR_CRYPTO_NO_APPLICATION_PROTOCOL); - } else if (AcceptResult == QUIC_CONNECTION_REJECT_BUSY) { - QuicConnTransportError( - Connection, - QUIC_ERROR_CONNECTION_REFUSED); - } else { // QUIC_CONNECTION_REJECT_APP - QuicConnTransportError( - Connection, - QUIC_ERROR_INTERNAL_ERROR); - } - goto Error; - - } - - // - // Save the negotiated ALPN (starting with the length prefix) to be - // used later in building up the TLS response. - // - Crypto->TlsState.NegotiatedAlpn = Info.NegotiatedAlpn - 1; - - if (SecConfig != NULL) { - Status = QuicConnHandshakeConfigure(Connection, SecConfig); - if (QUIC_FAILED(Status)) { - QuicConnTransportError( - Connection, - QUIC_ERROR_CRYPTO_HANDSHAKE_FAILURE); - goto Error; - } - } + QuicBindingAcceptConnection( + Connection->Paths[0].Binding, + Connection, + &Info); + return; } } + QUIC_DBG_ASSERT(Crypto->TLS != NULL); if (Crypto->TLS == NULL) { // // The listener still hasn't given us the security config to initialize @@ -1651,7 +1588,12 @@ QuicCryptoProcessData( QuicCryptoValidate(Crypto); QUIC_TLS_RESULT_FLAGS ResultFlags = - QuicTlsProcessData(Crypto->TLS, QUIC_TLS_CRYPTO_DATA, Buffer.Buffer, &Buffer.Length, &Crypto->TlsState); + QuicTlsProcessData( + Crypto->TLS, + QUIC_TLS_CRYPTO_DATA, + Buffer.Buffer, + &Buffer.Length, + &Crypto->TlsState); QUIC_TEL_ASSERT(!IsClientInitial || ResultFlags != QUIC_TLS_RESULT_PENDING); // TODO - Support async for client Initial? @@ -1839,3 +1781,452 @@ QuicCryptoUpdateKeyPhase( PacketSpace->CurrentKeyPhaseBytesSent = 0; } + +QUIC_STATUS +QuicCryptoEncodeServerTicket( + _In_opt_ QUIC_CONNECTION* Connection, + _In_ uint32_t QuicVersion, + _In_ uint32_t AppDataLength, + _In_reads_bytes_opt_(AppDataLength) + const uint8_t* const AppResumptionData, + _In_ const QUIC_TRANSPORT_PARAMETERS* HandshakeTP, + _In_ uint8_t AlpnLength, + _In_reads_bytes_(AlpnLength) + const uint8_t* const NegotiatedAlpn, + _Outptr_result_buffer_(*TicketLength) + uint8_t** Ticket, + _Out_ uint32_t* TicketLength + ) +{ + QUIC_STATUS Status; + uint32_t EncodedTPLength = 0; + uint8_t* TicketBuffer = NULL; + const uint8_t* EncodedHSTP = NULL; + + *Ticket = NULL; + *TicketLength = 0; + + QUIC_TRANSPORT_PARAMETERS HSTPCopy = *HandshakeTP; + HSTPCopy.Flags &= ( + QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | + QUIC_TP_FLAG_INITIAL_MAX_DATA | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_LOCAL | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI); + + EncodedHSTP = + QuicCryptoTlsEncodeTransportParameters( + Connection, + TRUE, + &HSTPCopy, + NULL, + &EncodedTPLength); + if (EncodedHSTP == NULL) { + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Error; + } + + // + // Adjust TP buffer for TLS header, if present. + // + EncodedTPLength -= QuicTlsTPHeaderSize; + + uint32_t TotalTicketLength = + (uint32_t)(QuicVarIntSize(QUIC_TLS_RESUMPTION_TICKET_VERSION) + + sizeof(QuicVersion) + + QuicVarIntSize(AlpnLength) + + QuicVarIntSize(EncodedTPLength) + + QuicVarIntSize(AppDataLength) + + AlpnLength + + EncodedTPLength + + AppDataLength); + + TicketBuffer = QUIC_ALLOC_NONPAGED(TotalTicketLength); + if (TicketBuffer == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "Server resumption ticket", + TotalTicketLength); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Error; + } + + // + // Encoded ticket format is as follows: + // Ticket Version (QUIC_VAR_INT) [1..4] + // Quic Version (network byte order) [4] + // Negotiated ALPN length (QUIC_VAR_INT) [1..2] + // Transport Parameters length (QUIC_VAR_INT) [1..2] + // App Ticket length (QUIC_VAR_INT) [1..2] + // Negotiated ALPN [...] + // Transport Parameters [...] + // App Ticket (omitted if length is zero) [...] + // + + _Analysis_assume_(sizeof(*TicketBuffer) >= 8); + uint8_t* TicketCursor = QuicVarIntEncode(QUIC_TLS_RESUMPTION_TICKET_VERSION, TicketBuffer); + QuicCopyMemory(TicketCursor, &QuicVersion, sizeof(QuicVersion)); + TicketCursor += sizeof(QuicVersion); + TicketCursor = QuicVarIntEncode(AlpnLength, TicketCursor); + TicketCursor = QuicVarIntEncode(EncodedTPLength, TicketCursor); + TicketCursor = QuicVarIntEncode(AppDataLength, TicketCursor); + QuicCopyMemory(TicketCursor, NegotiatedAlpn, AlpnLength); + TicketCursor += AlpnLength; + QuicCopyMemory(TicketCursor, EncodedHSTP + QuicTlsTPHeaderSize, EncodedTPLength); + TicketCursor += EncodedTPLength; + if (AppDataLength > 0) { + QuicCopyMemory(TicketCursor, AppResumptionData, AppDataLength); + TicketCursor += AppDataLength; + } + QUIC_DBG_ASSERT(TicketCursor == TicketBuffer + TotalTicketLength); + + *Ticket = TicketBuffer; + *TicketLength = TotalTicketLength; + + Status = QUIC_STATUS_SUCCESS; + +Error: + + if (EncodedHSTP != NULL) { + QUIC_FREE(EncodedHSTP); + } + + return Status; +} + +QUIC_STATUS +QuicCryptoDecodeServerTicket( + _In_opt_ QUIC_CONNECTION* Connection, + _In_ uint16_t TicketLength, + _In_reads_bytes_(TicketLength) + const uint8_t* Ticket, + _In_ const uint8_t* AlpnList, + _In_ uint16_t AlpnListLength, + _Out_ QUIC_TRANSPORT_PARAMETERS* DecodedTP, + _Outptr_result_buffer_maybenull_(*AppDataLength) + const uint8_t** AppData, + _Out_ uint32_t* AppDataLength + ) +{ + QUIC_STATUS Status = QUIC_STATUS_INVALID_PARAMETER; + uint16_t Offset = 0; + QUIC_VAR_INT TicketVersion = 0, AlpnLength = 0, TPLength = 0, AppTicketLength = 0; + + *AppData = NULL; + *AppDataLength = 0; + + if (!QuicVarIntDecode(TicketLength, Ticket, &Offset, &TicketVersion)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket version failed to decode"); + goto Error; + } + if (TicketVersion != QUIC_TLS_RESUMPTION_TICKET_VERSION) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket version unsupported"); + goto Error; + } + + uint32_t QuicVersion; + memcpy(&QuicVersion, Ticket + Offset, sizeof(QuicVersion)); + if (!QuicIsVersionSupported(QuicVersion)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket for unsupported QUIC version"); + goto Error; + } + Offset += sizeof(QuicVersion); + + if (!QuicVarIntDecode(TicketLength, Ticket, &Offset, &AlpnLength)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket ALPN length failed to decode"); + goto Error; + } + + if (!QuicVarIntDecode(TicketLength, Ticket, &Offset, &TPLength)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket TP length failed to decode"); + goto Error; + } + + if (!QuicVarIntDecode(TicketLength, Ticket, &Offset, &AppTicketLength)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket app data length failed to decode"); + goto Error; + } + + if (QuicTlsAlpnFindInList(AlpnListLength, AlpnList, (uint8_t)AlpnLength, Ticket + Offset) == NULL) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket ALPN not present in ALPN list"); + goto Error; + } + Offset += (uint16_t)AlpnLength; + + if (!QuicCryptoTlsDecodeTransportParameters( + Connection, + TRUE, // IsServerTP + Ticket + Offset, + (uint16_t)TPLength, + DecodedTP)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket TParams failed to decode"); + goto Error; + } + Offset += (uint16_t)TPLength; + + if (TicketLength == Offset + AppTicketLength) { + Status = QUIC_STATUS_SUCCESS; + *AppDataLength = (uint32_t)AppTicketLength; + if (AppTicketLength > 0) { + *AppData = Ticket + Offset; + } + } else { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket app data length corrupt"); + } + +Error: + return Status; +} + +QUIC_STATUS +QuicCryptoEncodeClientTicket( + _In_opt_ QUIC_CONNECTION* Connection, + _In_ uint32_t TicketLength, + _In_reads_bytes_(TicketLength) + const uint8_t* Ticket, + _In_ const QUIC_TRANSPORT_PARAMETERS* ServerTP, + _In_ uint32_t QuicVersion, + _Outptr_result_buffer_(*ClientTicketLength) + const uint8_t** ClientTicket, + _Out_ uint32_t* ClientTicketLength + ) +{ + QUIC_STATUS Status; + uint32_t EncodedTPLength = 0; + uint8_t* ClientTicketBuffer = NULL; + const uint8_t* EncodedServerTP = NULL; + + *ClientTicket = NULL; + *ClientTicketLength = 0; + + QUIC_TRANSPORT_PARAMETERS ServerTPCopy = *ServerTP; + // + // The client must remember all TPs it can process except for the following + // + ServerTPCopy.Flags &= ~( + QUIC_TP_FLAG_ACK_DELAY_EXPONENT | + QUIC_TP_FLAG_MAX_ACK_DELAY | + QUIC_TP_FLAG_INITIAL_SOURCE_CONNECTION_ID | + QUIC_TP_FLAG_ORIGINAL_DESTINATION_CONNECTION_ID | + QUIC_TP_FLAG_PREFERRED_ADDRESS | + QUIC_TP_FLAG_RETRY_SOURCE_CONNECTION_ID | + QUIC_TP_FLAG_STATELESS_RESET_TOKEN); + + EncodedServerTP = + QuicCryptoTlsEncodeTransportParameters( + Connection, + TRUE, + &ServerTPCopy, + NULL, + &EncodedTPLength); + if (EncodedServerTP == NULL) { + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Error; + } + + // + // Adjust for any TLS header potentially added to the TP buffer + // + EncodedTPLength -= QuicTlsTPHeaderSize; + + uint32_t ClientTicketBufferLength = + (uint32_t)(QuicVarIntSize(QUIC_TLS_RESUMPTION_CLIENT_TICKET_VERSION) + + sizeof(QuicVersion) + + QuicVarIntSize(EncodedTPLength) + + QuicVarIntSize(TicketLength) + + EncodedTPLength + + TicketLength); + + ClientTicketBuffer = QUIC_ALLOC_NONPAGED(ClientTicketBufferLength); + if (ClientTicketBuffer == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "Client resumption ticket", + ClientTicketBufferLength); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Error; + } + + // + // Encoded ticket blob format is as follows: + // Ticket Version (QUIC_VAR_INT) [1..4] + // Negotiated Quic Version (network byte order) [4] + // Transport Parameters length (QUIC_VAR_INT) [1..2] + // Received Ticket length (QUIC_VAR_INT) [1..2] + // Transport Parameters [...] + // Received Ticket (omitted if length is zero) [...] + // + + _Analysis_assume_(sizeof(*ClientTicketBuffer) >= 8); + uint8_t* TicketCursor = QuicVarIntEncode(QUIC_TLS_RESUMPTION_CLIENT_TICKET_VERSION, ClientTicketBuffer); + QuicCopyMemory(TicketCursor, &QuicVersion, sizeof(QuicVersion)); + TicketCursor += sizeof(QuicVersion); + TicketCursor = QuicVarIntEncode(EncodedTPLength, TicketCursor); + TicketCursor = QuicVarIntEncode(TicketLength, TicketCursor); + QuicCopyMemory(TicketCursor, EncodedServerTP + QuicTlsTPHeaderSize, EncodedTPLength); + TicketCursor += EncodedTPLength; + if (TicketLength > 0) { + QuicCopyMemory(TicketCursor, Ticket, TicketLength); + TicketCursor += TicketLength; + } + QUIC_DBG_ASSERT(TicketCursor == ClientTicketBuffer + ClientTicketBufferLength); + + *ClientTicket = ClientTicketBuffer; + *ClientTicketLength = ClientTicketBufferLength; + + Status = QUIC_STATUS_SUCCESS; + +Error: + + if (EncodedServerTP != NULL) { + QUIC_FREE(EncodedServerTP); + } + + return Status; +} + +QUIC_STATUS +QuicCryptoDecodeClientTicket( + _In_opt_ QUIC_CONNECTION* Connection, + _In_ uint16_t ClientTicketLength, + _In_reads_bytes_(ClientTicketLength) + const uint8_t* ClientTicket, + _Out_ QUIC_TRANSPORT_PARAMETERS* DecodedTP, + _Outptr_result_buffer_maybenull_(*ServerTicketLength) + uint8_t** ServerTicket, + _Out_ uint32_t* ServerTicketLength, + _Out_ uint32_t* QuicVersion + ) +{ + QUIC_STATUS Status; + uint16_t Offset = 0; + QUIC_VAR_INT TicketVersion = 0, TPLength = 0, TicketLength = 0; + + *ServerTicket = NULL; + *ServerTicketLength = 0; + *QuicVersion = 0; + + if (!QuicVarIntDecode(ClientTicketLength, ClientTicket, &Offset, &TicketVersion)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Client Ticket version failed to decode"); + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + if (TicketVersion != QUIC_TLS_RESUMPTION_CLIENT_TICKET_VERSION) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Client Ticket version unsupported"); + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + QuicCopyMemory(QuicVersion, ClientTicket + Offset, sizeof(*QuicVersion)); + Offset += sizeof(*QuicVersion); + if (!QuicVarIntDecode(ClientTicketLength, ClientTicket, &Offset, &TPLength)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Client Ticket TP length failed to decode"); + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + if (!QuicVarIntDecode(ClientTicketLength, ClientTicket, &Offset, &TicketLength)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket data length failed to decode"); + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + if (!QuicCryptoTlsDecodeTransportParameters( + Connection, + TRUE, // IsServerTP + ClientTicket + Offset, + (uint16_t)TPLength, + DecodedTP)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Resumption Ticket TParams failed to decode"); + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + Offset += (uint16_t)TPLength; + if (Offset + TicketLength != ClientTicketLength) { + Status = QUIC_STATUS_INVALID_PARAMETER; + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", + Connection, + "Client resumption ticket length is corrupt"); + goto Error; + } + if (TicketLength != 0) { + *ServerTicket = QUIC_ALLOC_NONPAGED((uint32_t)TicketLength); + if (*ServerTicket == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "Resumption ticket copy", + TicketLength); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Error; + } + QuicCopyMemory(*ServerTicket, (uint8_t*)ClientTicket + Offset, (uint16_t)TicketLength); + } + *ServerTicketLength = (uint32_t)TicketLength; + Offset += (uint16_t)TicketLength; + QUIC_DBG_ASSERT(ClientTicketLength == Offset); + + Status = QUIC_STATUS_SUCCESS; + +Error: + return Status; +} diff --git a/src/core/crypto.h b/src/core/crypto.h index a5729f2f6b..23430121e5 100644 --- a/src/core/crypto.h +++ b/src/core/crypto.h @@ -93,6 +93,12 @@ typedef struct QUIC_CRYPTO { // QUIC_RECV_BUFFER RecvBuffer; + // + // Resumption ticket to send to server. + // + uint8_t* ResumptionTicket; + uint32_t ResumptionTicketLength; + } QUIC_CRYPTO; inline @@ -293,3 +299,85 @@ QuicCryptoUpdateKeyPhase ( _In_ QUIC_CONNECTION* Connection, _In_ BOOLEAN LocalUpdate ); + +// +// Encode all state the server needs to resume the connection into a ticket +// ready to be passed to TLS. +// The buffer returned in Ticket needs to be freed with QUIC_FREE(). +// Note: Connection is only used for logging and may be NULL for testing. +// +QUIC_STATUS +QuicCryptoEncodeServerTicket( + _In_opt_ QUIC_CONNECTION* Connection, + _In_ uint32_t QuicVersion, + _In_ uint32_t AppDataLength, + _In_reads_bytes_opt_(AppDataLength) + const uint8_t* const AppResumptionData, + _In_ const QUIC_TRANSPORT_PARAMETERS* HandshakeTP, + _In_ uint8_t AlpnLength, + _In_reads_bytes_(AlpnLength) + const uint8_t* const NegotiatedAlpn, + _Outptr_result_buffer_(*TicketLength) + uint8_t** Ticket, + _Out_ uint32_t* TicketLength + ); + +// +// Decode a previously-generated resumption ticket and extract all data needed +// to resume the connection. +// AppData contains a pointer to the offset within Ticket, so do not free it. +// AppData contain NULL if the server application didn't pass any resumption +// data. +// Note: Connection is only used for logging and may be NULL for testing. +// +QUIC_STATUS +QuicCryptoDecodeServerTicket( + _In_opt_ QUIC_CONNECTION* Connection, + _In_ uint16_t TicketLength, + _In_reads_bytes_(TicketLength) + const uint8_t* Ticket, + _In_ const uint8_t* AlpnList, + _In_ uint16_t AlpnListLength, + _Out_ QUIC_TRANSPORT_PARAMETERS* DecodedTP, + _Outptr_result_buffer_maybenull_(*AppDataLength) + const uint8_t** AppData, + _Out_ uint32_t* AppDataLength + ); + +// +// Encodes necessary data into the client ticket to enable connection resumption. +// The pointer held by ClientTicket needs to be freed by QUIC_FREE(). +// Note: Connection is only used for logging and may be NULL for testing. +// +QUIC_STATUS +QuicCryptoEncodeClientTicket( + _In_opt_ QUIC_CONNECTION* Connection, + _In_ uint32_t TicketLength, + _In_reads_bytes_(TicketLength) + const uint8_t* Ticket, + _In_ const QUIC_TRANSPORT_PARAMETERS* ServerTP, + _In_ uint32_t QuicVersion, + _Outptr_result_buffer_(*ClientTicketLength) + const uint8_t** ClientTicket, + _Out_ uint32_t* ClientTicketLength + ); + +// +// Decodes and returns data necessary to resume a connection from a client ticket. +// The buffer held in ServerTicket must be freed with QUIC_FREE(). +// Note: Connection is only used for logging and my be NULL for testing. +// +QUIC_STATUS +QuicCryptoDecodeClientTicket( + _In_opt_ QUIC_CONNECTION* Connection, + _In_ uint16_t ClientTicketLength, + _In_reads_bytes_(ClientTicketLength) + const uint8_t* ClientTicket, + _Out_ QUIC_TRANSPORT_PARAMETERS* DecodedTP, + _Outptr_result_buffer_maybenull_(*ServerTicketLength) + uint8_t** ServerTicket, + _Out_ uint32_t* ServerTicketLength, + _Out_ uint32_t* QuicVersion + ); + + diff --git a/src/core/crypto_tls.c b/src/core/crypto_tls.c index b502d273c4..4e8d2c7261 100644 --- a/src/core/crypto_tls.c +++ b/src/core/crypto_tls.c @@ -620,8 +620,10 @@ _IRQL_requires_max_(DISPATCH_LEVEL) _Success_(return != NULL) const uint8_t* QuicCryptoTlsEncodeTransportParameters( - _In_ QUIC_CONNECTION* Connection, + _In_opt_ QUIC_CONNECTION* Connection, + _In_ BOOLEAN IsServerTP, _In_ const QUIC_TRANSPORT_PARAMETERS *TransportParams, + _In_opt_ const QUIC_PRIVATE_TRANSPORT_PARAMETER* TestParam, _Out_ uint32_t* TPLen ) { @@ -629,14 +631,18 @@ QuicCryptoTlsEncodeTransportParameters( // Precompute the required size so we can allocate all at once. // + UNREFERENCED_PARAMETER(Connection); + UNREFERENCED_PARAMETER(IsServerTP); + QuicTraceLogConnVerbose( EncodeTPStart, Connection, - "Encoding Transport Parameters"); + "Encoding Transport Parameters (Server = %hhu)", + IsServerTP); size_t RequiredTPLen = 0; if (TransportParams->Flags & QUIC_TP_FLAG_ORIGINAL_DESTINATION_CONNECTION_ID) { - QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + QUIC_DBG_ASSERT(IsServerTP); QUIC_FRE_ASSERT(TransportParams->OriginalDestinationConnectionIDLength <= QUIC_MAX_CONNECTION_ID_LENGTH_V1); RequiredTPLen += TlsTransportParamLength( @@ -650,7 +656,7 @@ QuicCryptoTlsEncodeTransportParameters( QuicVarIntSize(TransportParams->IdleTimeout)); } if (TransportParams->Flags & QUIC_TP_FLAG_STATELESS_RESET_TOKEN) { - QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + QUIC_DBG_ASSERT(IsServerTP); RequiredTPLen += TlsTransportParamLength( QUIC_TP_ID_STATELESS_RESET_TOKEN, @@ -717,7 +723,7 @@ QuicCryptoTlsEncodeTransportParameters( 0); } if (TransportParams->Flags & QUIC_TP_FLAG_PREFERRED_ADDRESS) { - QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + QUIC_DBG_ASSERT(IsServerTP); QUIC_FRE_ASSERT(FALSE); // TODO - Implement } if (TransportParams->Flags & QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT) { @@ -734,7 +740,7 @@ QuicCryptoTlsEncodeTransportParameters( TransportParams->InitialSourceConnectionIDLength); } if (TransportParams->Flags & QUIC_TP_FLAG_RETRY_SOURCE_CONNECTION_ID) { - QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + QUIC_DBG_ASSERT(IsServerTP); QUIC_FRE_ASSERT(TransportParams->RetrySourceConnectionIDLength <= QUIC_MAX_CONNECTION_ID_LENGTH_V1); RequiredTPLen += TlsTransportParamLength( @@ -753,11 +759,11 @@ QuicCryptoTlsEncodeTransportParameters( QUIC_TP_ID_DISABLE_1RTT_ENCRYPTION, 0); } - if (Connection->State.TestTransportParameterSet) { + if (TestParam != NULL) { RequiredTPLen += TlsTransportParamLength( - Connection->TestTransportParameter.Type, - Connection->TestTransportParameter.Length); + TestParam->Type, + TestParam->Length); } QUIC_TEL_ASSERT(RequiredTPLen <= UINT16_MAX); @@ -789,7 +795,7 @@ QuicCryptoTlsEncodeTransportParameters( // if (TransportParams->Flags & QUIC_TP_FLAG_ORIGINAL_DESTINATION_CONNECTION_ID) { - QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + QUIC_DBG_ASSERT(IsServerTP); TPBuf = TlsWriteTransportParam( QUIC_TP_ID_ORIGINAL_DESTINATION_CONNECTION_ID, @@ -816,7 +822,7 @@ QuicCryptoTlsEncodeTransportParameters( TransportParams->IdleTimeout); } if (TransportParams->Flags & QUIC_TP_FLAG_STATELESS_RESET_TOKEN) { - QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + QUIC_DBG_ASSERT(IsServerTP); TPBuf = TlsWriteTransportParam( QUIC_TP_ID_STATELESS_RESET_TOKEN, @@ -943,7 +949,7 @@ QuicCryptoTlsEncodeTransportParameters( "TP: Disable Active Migration"); } if (TransportParams->Flags & QUIC_TP_FLAG_PREFERRED_ADDRESS) { - QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + QUIC_DBG_ASSERT(IsServerTP); QUIC_FRE_ASSERT(FALSE); // TODO - Implement QuicTraceLogConnVerbose( EncodeTPPreferredAddress, @@ -978,7 +984,7 @@ QuicCryptoTlsEncodeTransportParameters( TransportParams->InitialSourceConnectionIDLength).Buffer); } if (TransportParams->Flags & QUIC_TP_FLAG_RETRY_SOURCE_CONNECTION_ID) { - QUIC_DBG_ASSERT(QuicConnIsServer(Connection)); + QUIC_DBG_ASSERT(IsServerTP); TPBuf = TlsWriteTransportParam( QUIC_TP_ID_RETRY_SOURCE_CONNECTION_ID, @@ -1016,19 +1022,19 @@ QuicCryptoTlsEncodeTransportParameters( Connection, "TP: Disable 1-RTT Encryption"); } - if (Connection->State.TestTransportParameterSet) { + if (TestParam != NULL) { TPBuf = TlsWriteTransportParam( - Connection->TestTransportParameter.Type, - Connection->TestTransportParameter.Length, - Connection->TestTransportParameter.Buffer, + TestParam->Type, + TestParam->Length, + TestParam->Buffer, TPBuf); QuicTraceLogConnVerbose( EncodeTPTest, Connection, "TP: TEST TP (Type %hu, Length %hu)", - Connection->TestTransportParameter.Type, - Connection->TestTransportParameter.Length); + TestParam->Type, + TestParam->Length); } size_t FinalTPLength = (TPBuf - (TPBufBase + QuicTlsTPHeaderSize)); @@ -1056,7 +1062,8 @@ _IRQL_requires_max_(DISPATCH_LEVEL) _Success_(return != FALSE) BOOLEAN QuicCryptoTlsDecodeTransportParameters( - _In_ QUIC_CONNECTION* Connection, + _In_opt_ QUIC_CONNECTION* Connection, + _In_ BOOLEAN IsServerTP, _In_reads_(TPLen) const uint8_t* TPBuf, _In_ uint16_t TPLen, @@ -1067,6 +1074,8 @@ QuicCryptoTlsDecodeTransportParameters( uint64_t ParamsPresent = 0; uint16_t Offset = 0; + UNREFERENCED_PARAMETER(Connection); + QuicZeroMemory(TransportParams, sizeof(QUIC_TRANSPORT_PARAMETERS)); TransportParams->MaxUdpPayloadSize = QUIC_TP_MAX_PACKET_SIZE_DEFAULT; TransportParams->AckDelayExponent = QUIC_TP_ACK_DELAY_EXPONENT_DEFAULT; @@ -1076,7 +1085,8 @@ QuicCryptoTlsDecodeTransportParameters( QuicTraceLogConnVerbose( DecodeTPStart, Connection, - "Decoding Peer Transport Parameters (%hu bytes)", + "Decoding Transport Parameters (Server = %hhu) (%hu bytes)", + IsServerTP, TPLen); while (Offset < TPLen) { @@ -1139,7 +1149,7 @@ QuicCryptoTlsDecodeTransportParameters( Length, "Invalid length of QUIC_TP_ID_ORIGINAL_DESTINATION_CONNECTION_ID"); goto Exit; - } else if (QuicConnIsServer(Connection)) { + } else if (!IsServerTP) { QuicTraceEvent( ConnError, "[conn][%p] ERROR, %s.", @@ -1189,7 +1199,7 @@ QuicCryptoTlsDecodeTransportParameters( Length, "Invalid length of QUIC_TP_ID_STATELESS_RESET_TOKEN"); goto Exit; - } else if (QuicConnIsServer(Connection)) { + } else if (!IsServerTP) { QuicTraceEvent( ConnError, "[conn][%p] ERROR, %s.", @@ -1447,7 +1457,7 @@ QuicCryptoTlsDecodeTransportParameters( break; case QUIC_TP_ID_PREFERRED_ADDRESS: - if (QuicConnIsServer(Connection)) { + if (!IsServerTP) { QuicTraceEvent( ConnError, "[conn][%p] ERROR, %s.", @@ -1522,7 +1532,7 @@ QuicCryptoTlsDecodeTransportParameters( Length, "Invalid length of QUIC_TP_ID_RETRY_SOURCE_CONNECTION_ID"); goto Exit; - } else if (QuicConnIsServer(Connection)) { + } else if (!IsServerTP) { QuicTraceEvent( ConnError, "[conn][%p] ERROR, %s.", diff --git a/src/core/inline.c b/src/core/inline.c index 50f841c41e..993fb0de3a 100644 --- a/src/core/inline.c +++ b/src/core/inline.c @@ -657,3 +657,13 @@ int64_t QuicTimeEpochMs64( void ); + +void +QuicConfigurationAddRef( + _In_ QUIC_CONFIGURATION* Configuration + ); + +void +QuicConfigurationRelease( + _In_ QUIC_CONFIGURATION* Configuration + ); diff --git a/src/core/library.c b/src/core/library.c index 84f5781960..d80d77e754 100644 --- a/src/core/library.c +++ b/src/core/library.c @@ -123,23 +123,11 @@ QuicLibrarySumPerfCountersExternal( } _IRQL_requires_max_(PASSIVE_LEVEL) -_Function_class_(QUIC_STORAGE_CHANGE_CALLBACK) void -MsQuicLibraryReadSettings( - _In_opt_ void* Context +MsQuicLibraryOnSettingsChanged( + _In_ BOOLEAN UpdateRegistrations ) { - QuicSettingsSetDefault(&MsQuicLib.Settings); - if (MsQuicLib.Storage != NULL) { - QuicSettingsLoad(&MsQuicLib.Settings, MsQuicLib.Storage); - } - - QuicTraceLogInfo( - LibrarySettingsUpdated, - "[ lib] Settings %p Updated", - &MsQuicLib.Settings); - QuicSettingsDump(&MsQuicLib.Settings); - if (!MsQuicLib.InUse) { // // Load balancing settings can only change before the library is @@ -149,7 +137,6 @@ MsQuicLibraryReadSettings( QuicLibApplyLoadBalancingSetting(); } - BOOLEAN UpdateRegistrations = (Context != NULL); if (UpdateRegistrations) { QuicLockAcquire(&MsQuicLib.Lock); @@ -164,6 +151,27 @@ MsQuicLibraryReadSettings( } } +_IRQL_requires_max_(PASSIVE_LEVEL) +_Function_class_(QUIC_STORAGE_CHANGE_CALLBACK) +void +MsQuicLibraryReadSettings( + _In_opt_ void* Context + ) +{ + QuicSettingsSetDefault(&MsQuicLib.Settings); + if (MsQuicLib.Storage != NULL) { + QuicSettingsLoad(&MsQuicLib.Settings, MsQuicLib.Storage); + } + + QuicTraceLogInfo( + LibrarySettingsUpdated, + "[ lib] Settings %p Updated", + &MsQuicLib.Settings); + QuicSettingsDump(&MsQuicLib.Settings); + + MsQuicLibraryOnSettingsChanged(Context != NULL); +} + _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS MsQuicLibraryInitialize( @@ -172,6 +180,7 @@ MsQuicLibraryInitialize( { QUIC_STATUS Status = QUIC_STATUS_SUCCESS; BOOLEAN PlatformInitialized = FALSE; + uint32_t DefaultMaxPartitionCount = QUIC_MAX_PARTITION_COUNT; Status = QuicPlatformInitialize(); if (QUIC_FAILED(Status)) { @@ -209,12 +218,22 @@ MsQuicLibraryInitialize( // // TODO: Add support for CPU hot swap/add. // - MsQuicLib.ProcessorCount = (uint16_t) QuicProcActiveCount(); - QUIC_FRE_ASSERT(MsQuicLib.ProcessorCount > 0); - MsQuicLib.PartitionCount = (uint16_t)min(MsQuicLib.ProcessorCount, UINT16_MAX-1); - if (MsQuicLib.PartitionCount > (uint32_t)MsQuicLib.Settings.MaxPartitionCount) { - MsQuicLib.PartitionCount = (uint32_t)MsQuicLib.Settings.MaxPartitionCount; + + if (MsQuicLib.Storage != NULL) { + uint32_t DefaultMaxPartitionCountLen = sizeof(DefaultMaxPartitionCount); + QuicStorageReadValue( + MsQuicLib.Storage, + QUIC_SETTING_MAX_PARTITION_COUNT, + (uint8_t*)&DefaultMaxPartitionCount, + &DefaultMaxPartitionCountLen); + if (DefaultMaxPartitionCount > QUIC_MAX_PARTITION_COUNT) { + DefaultMaxPartitionCount = QUIC_MAX_PARTITION_COUNT; + } } + MsQuicLib.ProcessorCount = (uint16_t)QuicProcActiveCount(); + QUIC_FRE_ASSERT(MsQuicLib.ProcessorCount > 0); + MsQuicLib.PartitionCount = (uint16_t)min(MsQuicLib.ProcessorCount, DefaultMaxPartitionCount); + MsQuicCalculatePartitionMask(); MsQuicLib.PerProc = @@ -317,35 +336,36 @@ MsQuicLibraryUninitialize( ) { // - // If you hit this assert, MsQuic API is trying to be unloaded without - // first closing all registrations. + // Clean up the data path first, which can continue to cause new connections + // to get created. // - QUIC_TEL_ASSERT(QuicListIsEmpty(&MsQuicLib.Registrations)); - - if (MsQuicLib.Storage != NULL) { - QuicStorageClose(MsQuicLib.Storage); - MsQuicLib.Storage = NULL; - } + QuicDataPathUninitialize(MsQuicLib.Datapath); + MsQuicLib.Datapath = NULL; // - // Clean up all the leftover, unregistered server connections. + // The library's stateless registration for processing half-opened + // connections needs to be cleaned up next, as it's the last thing that can + // be holding on to connection objects. // - if (MsQuicLib.UnregisteredSession != NULL) { - MsQuicSessionClose((HQUIC)MsQuicLib.UnregisteredSession); - MsQuicLib.UnregisteredSession = NULL; + if (MsQuicLib.StatelessRegistration != NULL) { + MsQuicRegistrationShutdown( + (HQUIC)MsQuicLib.StatelessRegistration, + QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT, + 0); + MsQuicRegistrationClose( + (HQUIC)MsQuicLib.StatelessRegistration); + MsQuicLib.StatelessRegistration = NULL; } - QuicDataPathUninitialize(MsQuicLib.Datapath); - MsQuicLib.Datapath = NULL; - // - // The library's worker pool for processing half-opened connections - // needs to be cleaned up first, as it's the last thing that can be - // holding on to connection objects. + // If you hit this assert, MsQuic API is trying to be unloaded without + // first closing all registrations. // - if (MsQuicLib.WorkerPool != NULL) { - QuicWorkerPoolUninitialize(MsQuicLib.WorkerPool); - MsQuicLib.WorkerPool = NULL; + QUIC_TEL_ASSERT(QuicListIsEmpty(&MsQuicLib.Registrations)); + + if (MsQuicLib.Storage != NULL) { + QuicStorageClose(MsQuicLib.Storage); + MsQuicLib.Storage = NULL; } #if DEBUG @@ -621,6 +641,33 @@ QuicLibrarySetGlobalParam( Status = QUIC_STATUS_SUCCESS; break; + } + + case QUIC_PARAM_GLOBAL_SETTINGS: + + if (BufferLength != sizeof(QUIC_SETTINGS)) { + Status = QUIC_STATUS_INVALID_PARAMETER; // TODO - Support partial + break; + } + + QuicTraceLogInfo( + LibrarySetSettings, + "[ lib] Setting new settings"); + + if (!QuicSettingApply( + &MsQuicLib.Settings, + TRUE, + BufferLength, + (QUIC_SETTINGS*)Buffer)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + QuicSettingsDumpNew(BufferLength, (QUIC_SETTINGS*)Buffer); + MsQuicLibraryOnSettingsChanged(TRUE); + + Status = QUIC_STATUS_SUCCESS; + break; #if QUIC_TEST_DATAPATH_HOOKS_ENABLED case QUIC_PARAM_GLOBAL_TEST_DATAPATH_HOOKS: @@ -638,7 +685,6 @@ QuicLibrarySetGlobalParam( Status = QUIC_STATUS_SUCCESS; break; #endif - } default: Status = QUIC_STATUS_INVALID_PARAMETER; @@ -748,6 +794,25 @@ QuicLibraryGetGlobalParam( break; } + case QUIC_PARAM_GLOBAL_SETTINGS: + + if (*BufferLength < sizeof(QUIC_SETTINGS)) { + *BufferLength = sizeof(QUIC_SETTINGS); + Status = QUIC_STATUS_BUFFER_TOO_SMALL; // TODO - Support partial + break; + } + + if (Buffer == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + *BufferLength = sizeof(QUIC_SETTINGS); + QuicCopyMemory(Buffer, &MsQuicLib.Settings, sizeof(QUIC_SETTINGS)); + + Status = QUIC_STATUS_SUCCESS; + break; + default: Status = QUIC_STATUS_INVALID_PARAMETER; break; @@ -769,7 +834,7 @@ QuicLibrarySetParam( { QUIC_STATUS Status; QUIC_REGISTRATION* Registration; - QUIC_SESSION* Session; + QUIC_CONFIGURATION* Configuration; QUIC_LISTENER* Listener; QUIC_CONNECTION* Connection; QUIC_STREAM* Stream; @@ -780,18 +845,18 @@ QuicLibrarySetParam( Stream = NULL; Connection = NULL; Listener = NULL; - Session = NULL; + Configuration = NULL; #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") Registration = (QUIC_REGISTRATION*)Handle; break; - case QUIC_HANDLE_TYPE_SESSION: + case QUIC_HANDLE_TYPE_CONFIGURATION: Stream = NULL; Connection = NULL; Listener = NULL; #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") - Session = (QUIC_SESSION*)Handle; - Registration = Session->Registration; + Configuration = (QUIC_CONFIGURATION*)Handle; + Registration = Configuration->Registration; break; case QUIC_HANDLE_TYPE_LISTENER: @@ -799,8 +864,8 @@ QuicLibrarySetParam( Connection = NULL; #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") Listener = (QUIC_LISTENER*)Handle; - Session = Listener->Session; - Registration = Session->Registration; + Configuration = NULL; + Registration = Listener->Registration; break; case QUIC_HANDLE_TYPE_CONNECTION_CLIENT: @@ -809,9 +874,8 @@ QuicLibrarySetParam( Listener = NULL; #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") Connection = (QUIC_CONNECTION*)Handle; - Session = Connection->Session; - QUIC_DBG_ASSERT(Session != NULL); - Registration = Session->Registration; + Configuration = Connection->Configuration; + Registration = Connection->Registration; break; case QUIC_HANDLE_TYPE_STREAM: @@ -819,9 +883,8 @@ QuicLibrarySetParam( #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") Stream = (QUIC_STREAM*)Handle; Connection = Stream->Connection; - Session = Connection->Session; - QUIC_DBG_ASSERT(Session != NULL); - Registration = Session->Registration; + Configuration = Connection->Configuration; + Registration = Connection->Registration; break; default: @@ -840,11 +903,11 @@ QuicLibrarySetParam( } break; - case QUIC_PARAM_LEVEL_SESSION: - if (Session == NULL) { + case QUIC_PARAM_LEVEL_CONFIGURATION: + if (Configuration == NULL) { Status = QUIC_STATUS_INVALID_PARAMETER; } else { - Status = QuicSessionParamSet(Session, Param, BufferLength, Buffer); + Status = QuicConfigurationParamSet(Configuration, Param, BufferLength, Buffer); } break; @@ -903,7 +966,7 @@ QuicLibraryGetParam( { QUIC_STATUS Status; QUIC_REGISTRATION* Registration; - QUIC_SESSION* Session; + QUIC_CONFIGURATION* Configuration; QUIC_LISTENER* Listener; QUIC_CONNECTION* Connection; QUIC_STREAM* Stream; @@ -916,18 +979,18 @@ QuicLibraryGetParam( Stream = NULL; Connection = NULL; Listener = NULL; - Session = NULL; + Configuration = NULL; #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") Registration = (QUIC_REGISTRATION*)Handle; break; - case QUIC_HANDLE_TYPE_SESSION: + case QUIC_HANDLE_TYPE_CONFIGURATION: Stream = NULL; Connection = NULL; Listener = NULL; #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") - Session = (QUIC_SESSION*)Handle; - Registration = Session->Registration; + Configuration = (QUIC_CONFIGURATION*)Handle; + Registration = Configuration->Registration; break; case QUIC_HANDLE_TYPE_LISTENER: @@ -935,8 +998,8 @@ QuicLibraryGetParam( Connection = NULL; #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") Listener = (QUIC_LISTENER*)Handle; - Session = Listener->Session; - Registration = Session->Registration; + Configuration = NULL; + Registration = Listener->Registration; break; case QUIC_HANDLE_TYPE_CONNECTION_CLIENT: @@ -945,9 +1008,8 @@ QuicLibraryGetParam( Listener = NULL; #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") Connection = (QUIC_CONNECTION*)Handle; - Session = Connection->Session; - QUIC_TEL_ASSERT(Session != NULL); - Registration = Session->Registration; + Configuration = Connection->Configuration; + Registration = Connection->Registration; break; case QUIC_HANDLE_TYPE_STREAM: @@ -955,9 +1017,8 @@ QuicLibraryGetParam( #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") Stream = (QUIC_STREAM*)Handle; Connection = Stream->Connection; - Session = Connection->Session; - QUIC_TEL_ASSERT(Session != NULL); - Registration = Session->Registration; + Configuration = Connection->Configuration; + Registration = Connection->Registration; break; default: @@ -976,11 +1037,11 @@ QuicLibraryGetParam( } break; - case QUIC_PARAM_LEVEL_SESSION: - if (Session == NULL) { + case QUIC_PARAM_LEVEL_CONFIGURATION: + if (Configuration == NULL) { Status = QUIC_STATUS_INVALID_PARAMETER; } else { - Status = QuicSessionParamGet(Session, Param, BufferLength, Buffer); + Status = QuicConfigurationParamGet(Configuration, Param, BufferLength, Buffer); } break; @@ -1067,13 +1128,11 @@ MsQuicOpen( Api->RegistrationOpen = MsQuicRegistrationOpen; Api->RegistrationClose = MsQuicRegistrationClose; + Api->RegistrationShutdown = MsQuicRegistrationShutdown; - Api->SecConfigCreate = MsQuicSecConfigCreate; - Api->SecConfigDelete = MsQuicSecConfigDelete; - - Api->SessionOpen = MsQuicSessionOpen; - Api->SessionClose = MsQuicSessionClose; - Api->SessionShutdown = MsQuicSessionShutdown; + Api->ConfigurationOpen = MsQuicConfigurationOpen; + Api->ConfigurationClose = MsQuicConfigurationClose; + Api->ConfigurationLoadCredential = MsQuicConfigurationLoadCredential; Api->ListenerOpen = MsQuicListenerOpen; Api->ListenerClose = MsQuicListenerClose; @@ -1084,6 +1143,7 @@ MsQuicOpen( Api->ConnectionClose = MsQuicConnectionClose; Api->ConnectionShutdown = MsQuicConnectionShutdown; Api->ConnectionStart = MsQuicConnectionStart; + Api->ConnectionSetConfiguration = MsQuicConnectionSetConfiguration; Api->ConnectionSendResumptionTicket = MsQuicConnectionSendResumptionTicket; Api->StreamOpen = MsQuicStreamOpen; @@ -1184,7 +1244,9 @@ QuicLibraryLookupBinding( _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS QuicLibraryGetBinding( - _In_ QUIC_SESSION* Session, +#ifdef QUIC_COMPARTMENT_ID + _In_ QUIC_COMPARTMENT_ID CompartmentId, +#endif _In_ BOOLEAN ShareBinding, _In_ BOOLEAN ServerOwned, _In_opt_ const QUIC_ADDR * LocalAddress, @@ -1192,7 +1254,6 @@ QuicLibraryGetBinding( _Out_ QUIC_BINDING** NewBinding ) { - UNREFERENCED_PARAMETER(Session); QUIC_STATUS Status = QUIC_STATUS_NOT_FOUND; QUIC_BINDING* Binding; QUIC_ADDR NewLocalAddress; @@ -1214,7 +1275,7 @@ QuicLibraryGetBinding( Binding = QuicLibraryLookupBinding( #ifdef QUIC_COMPARTMENT_ID - Session->CompartmentId, + CompartmentId, #endif LocalAddress, RemoteAddress); @@ -1252,7 +1313,7 @@ QuicLibraryGetBinding( Status = QuicBindingInitialize( #ifdef QUIC_COMPARTMENT_ID - Session->CompartmentId, + CompartmentId, #endif ShareBinding, ServerOwned, @@ -1283,7 +1344,7 @@ QuicLibraryGetBinding( Binding = QuicLibraryLookupBinding( #ifdef QUIC_COMPARTMENT_ID - Session->CompartmentId, + CompartmentId, #endif &NewLocalAddress, NULL); @@ -1387,36 +1448,24 @@ QuicLibraryOnListenerRegistered( QuicLockAcquire(&MsQuicLib.Lock); - if (MsQuicLib.WorkerPool == NULL) { + if (MsQuicLib.StatelessRegistration == NULL) { // - // Lazily initialize server specific state, such as worker threads and - // the unregistered connection session. + // Lazily initialize server specific state. // QuicTraceEvent( - LibraryWorkerPoolInit, - "[ lib] Shared worker pool initializing"); + LibraryServerInit, + "[ lib] Shared server state initializing"); - QUIC_DBG_ASSERT(MsQuicLib.UnregisteredSession == NULL); - if (QUIC_FAILED( - QuicSessionAlloc( - NULL, - NULL, - NULL, - 0, - &MsQuicLib.UnregisteredSession))) { - Success = FALSE; - goto Fail; - } + const QUIC_REGISTRATION_CONFIG Config = { + "Stateless", + QUIC_EXECUTION_PROFILE_TYPE_INTERNAL + }; if (QUIC_FAILED( - QuicWorkerPoolInitialize( - NULL, - 0, - max(1, MsQuicLib.PartitionCount / 4), - &MsQuicLib.WorkerPool))) { + MsQuicRegistrationOpen( + &Config, + (HQUIC*)&MsQuicLib.StatelessRegistration))) { Success = FALSE; - MsQuicSessionClose((HQUIC)MsQuicLib.UnregisteredSession); - MsQuicLib.UnregisteredSession = NULL; goto Fail; } } @@ -1432,13 +1481,13 @@ _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_WORKER* QUIC_NO_SANITIZE("implicit-conversion") QuicLibraryGetWorker( - void + _In_ const _In_ QUIC_RECV_DATAGRAM* Datagram ) { - QUIC_DBG_ASSERT(MsQuicLib.WorkerPool != NULL); + QUIC_DBG_ASSERT(MsQuicLib.StatelessRegistration != NULL); return - &MsQuicLib.WorkerPool->Workers[ - MsQuicLib.NextWorkerIndex++ % MsQuicLib.WorkerPool->WorkerCount]; + &MsQuicLib.StatelessRegistration->WorkerPool->Workers[ + Datagram->PartitionIndex % MsQuicLib.PartitionCount]; } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -1460,6 +1509,10 @@ QuicTraceRundown( MsQuicLib.PartitionCount, QuicDataPathGetSupportedFeatures(MsQuicLib.Datapath)); + if (MsQuicLib.StatelessRegistration) { + QuicRegistrationTraceRundown(MsQuicLib.StatelessRegistration); + } + for (QUIC_LIST_ENTRY* Link = MsQuicLib.Registrations.Flink; Link != &MsQuicLib.Registrations; Link = Link->Flink) { diff --git a/src/core/library.h b/src/core/library.h index 2e97a8b9d3..36eb5c953c 100644 --- a/src/core/library.h +++ b/src/core/library.h @@ -11,7 +11,7 @@ typedef enum QUIC_HANDLE_TYPE { QUIC_HANDLE_TYPE_REGISTRATION, - QUIC_HANDLE_TYPE_SESSION, + QUIC_HANDLE_TYPE_CONFIGURATION, QUIC_HANDLE_TYPE_LISTENER, QUIC_HANDLE_TYPE_CONNECTION_CLIENT, QUIC_HANDLE_TYPE_CONNECTION_SERVER, @@ -136,11 +136,6 @@ typedef struct QUIC_LIBRARY { long ConnectionCount; #endif - // - // Next worker to use in the pool. - // - uint8_t NextWorkerIndex; - // // Estimated timer resolution for the platform. // @@ -188,13 +183,7 @@ typedef struct QUIC_LIBRARY { // // Contains all (server) connections currently not in an app's registration. // - QUIC_SESSION* UnregisteredSession; - - // - // Set of workers that manage processing client Initial packets on the - // server side. - // - QUIC_WORKER_POOL* WorkerPool; + QUIC_REGISTRATION* StatelessRegistration; // // Per-processor storage. Count of `PartitionCount`. @@ -428,7 +417,9 @@ QuicLibraryGetParam( _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS QuicLibraryGetBinding( - _In_ QUIC_SESSION* Session, +#ifdef QUIC_COMPARTMENT_ID + _In_ QUIC_COMPARTMENT_ID CompartmentId, +#endif _In_ BOOLEAN ShareBinding, _In_ BOOLEAN ServerOwned, _In_opt_ const QUIC_ADDR * LocalAddress, @@ -473,7 +464,7 @@ QuicLibraryOnListenerRegistered( _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_WORKER* QuicLibraryGetWorker( - void + _In_ const _In_ QUIC_RECV_DATAGRAM* Datagram ); // diff --git a/src/core/listener.c b/src/core/listener.c index 143784d506..6bb23a67ec 100644 --- a/src/core/listener.c +++ b/src/core/listener.c @@ -18,7 +18,7 @@ _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS QUIC_API MsQuicListenerOpen( - _In_ _Pre_defensive_ HQUIC SessionHandle, + _In_ _Pre_defensive_ HQUIC RegistrationHandle, _In_ _Pre_defensive_ QUIC_LISTENER_CALLBACK_HANDLER Handler, _In_opt_ void* Context, _Outptr_ _At_(*NewListener, __drv_allocatesMem(Mem)) _Pre_defensive_ @@ -26,24 +26,24 @@ MsQuicListenerOpen( ) { QUIC_STATUS Status; - QUIC_SESSION* Session; + QUIC_REGISTRATION* Registration; QUIC_LISTENER* Listener = NULL; QuicTraceEvent( ApiEnter, "[ api] Enter %u (%p).", QUIC_TRACE_API_LISTENER_OPEN, - SessionHandle); + RegistrationHandle); - if (SessionHandle == NULL || - SessionHandle->Type != QUIC_HANDLE_TYPE_SESSION || + if (RegistrationHandle == NULL || + RegistrationHandle->Type != QUIC_HANDLE_TYPE_REGISTRATION || NewListener == NULL || Handler == NULL) { Status = QUIC_STATUS_INVALID_PARAMETER; goto Error; } - Session = (QUIC_SESSION*)SessionHandle; + Registration = (QUIC_REGISTRATION*)RegistrationHandle; Listener = QUIC_ALLOC_NONPAGED(sizeof(QUIC_LISTENER)); if (Listener == NULL) { @@ -58,19 +58,24 @@ MsQuicListenerOpen( QuicZeroMemory(Listener, sizeof(QUIC_LISTENER)); Listener->Type = QUIC_HANDLE_TYPE_LISTENER; - Listener->Session = Session; + Listener->Registration = Registration; Listener->ClientCallbackHandler = Handler; Listener->ClientContext = Context; QuicRundownInitializeDisabled(&Listener->Rundown); -#pragma prefast(suppress: __WARNING_6031, "Will always succeed.") - QuicRundownAcquire(&Session->Rundown); +#ifdef QUIC_SILO + Listener->Silo = QuicSiloGetCurrentServer(); + QuicSiloAddRef(Listener->Silo); +#endif + + BOOLEAN Result = QuicRundownAcquire(&Registration->Rundown); + QUIC_DBG_ASSERT(Result); UNREFERENCED_PARAMETER(Result); QuicTraceEvent( ListenerCreated, - "[list][%p] Created, Session=%p", + "[list][%p] Created, Registration=%p", Listener, - Listener->Session); + Listener->Registration); *NewListener = (HQUIC)Listener; Status = QUIC_STATUS_SUCCESS; @@ -117,7 +122,7 @@ MsQuicListenerClose( #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") QUIC_LISTENER* Listener = (QUIC_LISTENER*)Handle; - QUIC_SESSION* Session = Listener->Session; + QUIC_REGISTRATION* Registration = Listener->Registration; // // Make sure the listener has unregistered from the binding. @@ -131,8 +136,13 @@ MsQuicListenerClose( "[list][%p] Destroyed", Listener); +#ifdef QUIC_SILO + QuicSiloRelease(Listener->Silo); +#endif + + QUIC_DBG_ASSERT(Listener->AlpnList == NULL); QUIC_FREE(Listener); - QuicRundownRelease(&Session->Rundown); + QuicRundownRelease(&Registration->Rundown); QuicTraceEvent( ApiExit, @@ -144,11 +154,16 @@ QUIC_STATUS QUIC_API MsQuicListenerStart( _In_ _Pre_defensive_ HQUIC Handle, + _In_reads_(AlpnBufferCount) _Pre_defensive_ + const QUIC_BUFFER* const AlpnBuffers, + _In_range_(>, 0) uint32_t AlpnBufferCount, _In_opt_ const QUIC_ADDR * LocalAddress ) { QUIC_STATUS Status; QUIC_LISTENER* Listener; + uint8_t* AlpnList; + uint32_t AlpnListLength; BOOLEAN PortUnspecified; QUIC_ADDR BindingLocalAddress = {0}; @@ -159,10 +174,27 @@ MsQuicListenerStart( Handle); if (Handle == NULL || - Handle->Type != QUIC_HANDLE_TYPE_LISTENER) { + Handle->Type != QUIC_HANDLE_TYPE_LISTENER || + AlpnBuffers == NULL || + AlpnBufferCount == 0) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Exit; + } + + AlpnListLength = 0; + for (uint32_t i = 0; i < AlpnBufferCount; ++i) { + if (AlpnBuffers[i].Length == 0 || + AlpnBuffers[i].Length > QUIC_MAX_ALPN_LENGTH) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Exit; + } + AlpnListLength += sizeof(uint8_t) + AlpnBuffers[i].Length; + } + if (AlpnListLength > UINT16_MAX) { Status = QUIC_STATUS_INVALID_PARAMETER; goto Exit; } + QUIC_ANALYSIS_ASSERT(AlpnListLength <= UINT16_MAX); if (LocalAddress && !QuicAddrIsValid(LocalAddress)) { Status = QUIC_STATUS_INVALID_PARAMETER; @@ -178,6 +210,31 @@ MsQuicListenerStart( goto Exit; } + AlpnList = QUIC_ALLOC_NONPAGED(AlpnListLength); + if (AlpnList == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "AlpnList" , + AlpnListLength); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Exit; + } + + Listener->AlpnList = AlpnList; + Listener->AlpnListLength = (uint16_t)AlpnListLength; + + for (uint32_t i = 0; i < AlpnBufferCount; ++i) { + AlpnList[0] = (uint8_t)AlpnBuffers[i].Length; + AlpnList++; + + QuicCopyMemory( + AlpnList, + AlpnBuffers[i].Buffer, + AlpnBuffers[i].Length); + AlpnList += AlpnBuffers[i].Length; + } + if (LocalAddress != NULL) { QuicCopyMemory(&Listener->LocalAddress, LocalAddress, sizeof(QUIC_ADDR)); Listener->WildCard = QuicAddrIsWildCard(LocalAddress); @@ -202,7 +259,9 @@ MsQuicListenerStart( QUIC_TEL_ASSERT(Listener->Binding == NULL); Status = QuicLibraryGetBinding( - Listener->Session, +#ifdef QUIC_COMPARTMENT_ID + QuicCompartmentIdGetCurrent(), +#endif TRUE, // Listeners always share the binding. TRUE, &BindingLocalAddress, @@ -254,6 +313,11 @@ MsQuicListenerStart( QuicLibraryReleaseBinding(Listener->Binding); Listener->Binding = NULL; } + if (Listener->AlpnList != NULL) { + QUIC_FREE(Listener->AlpnList); + Listener->AlpnList = NULL; + } + Listener->AlpnListLength = 0; } Exit: @@ -288,6 +352,12 @@ MsQuicListenerStop( Listener->Binding = NULL; QuicRundownReleaseAndWait(&Listener->Rundown); + + if (Listener->AlpnList != NULL) { + QUIC_FREE(Listener->AlpnList); + Listener->AlpnList = NULL; + } + QuicTraceEvent( ListenerStopped, "[list][%p] Stopped", @@ -308,9 +378,9 @@ QuicListenerTraceRundown( { QuicTraceEvent( ListenerRundown, - "[list][%p] Rundown, Session=%p", + "[list][%p] Rundown, Registration=%p", Listener, - Listener->Session); + Listener->Registration); if (Listener->Binding != NULL) { QuicTraceEvent( ListenerStarted, @@ -336,13 +406,83 @@ QuicListenerIndicateEvent( Event); } +_IRQL_requires_max_(DISPATCH_LEVEL) +const uint8_t* +QuicListenerFindAlpnInList( + _In_ const QUIC_LISTENER* Listener, + _In_ uint16_t OtherAlpnListLength, + _In_reads_(OtherAlpnListLength) + const uint8_t* OtherAlpnList + ) +{ + const uint8_t* AlpnList = Listener->AlpnList; + uint16_t AlpnListLength = Listener->AlpnListLength; + + // + // We want to respect the server's ALPN preference order (i.e. Listener) and + // not the client's. So we loop over every ALPN in the listener and then see + // if there is a match in the client's list. + // + + while (AlpnListLength != 0) { + QUIC_ANALYSIS_ASSUME(AlpnList[0] + 1 <= AlpnListLength); + const uint8_t* Result = + QuicTlsAlpnFindInList( + OtherAlpnListLength, + OtherAlpnList, + AlpnList[0], + AlpnList + 1); + if (Result != NULL) { + // + // Return AlpnList instead of Result, since Result points into what + // might be a temporary buffer. + // + return AlpnList; + } + AlpnListLength -= AlpnList[0] + 1; + AlpnList += AlpnList[0] + 1; + } + + return NULL; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicListenerHasAlpnOverlap( + _In_ const QUIC_LISTENER* Listener1, + _In_ const QUIC_LISTENER* Listener2 + ) +{ + return + QuicListenerFindAlpnInList( + Listener1, + Listener2->AlpnListLength, + Listener2->AlpnList) != NULL; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicListenerMatchesAlpn( + _In_ const QUIC_LISTENER* Listener, + _In_ QUIC_NEW_CONNECTION_INFO* Info + ) +{ + const uint8_t* Alpn = + QuicListenerFindAlpnInList(Listener, Info->ClientAlpnListLength, Info->ClientAlpnList); + if (Alpn != NULL) { + Info->NegotiatedAlpnLength = Alpn[0]; // The length prefixed to the ALPN buffer. + Info->NegotiatedAlpn = Alpn + 1; + return TRUE; + } + return FALSE; +} + _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS +BOOLEAN QuicListenerClaimConnection( _In_ QUIC_LISTENER* Listener, _In_ QUIC_CONNECTION* Connection, - _In_ const QUIC_NEW_CONNECTION_INFO* Info, - _Out_ QUIC_SEC_CONFIG** SecConfig + _In_ const QUIC_NEW_CONNECTION_INFO* Info ) { QUIC_DBG_ASSERT(Listener != NULL); @@ -351,134 +491,89 @@ QuicListenerClaimConnection( // // Internally, the connection matches the listener. Update the associated // connection state. Next, call up to the application layer to accept the - // connection and return the server certificate. + // connection and return the server configuration. // - QuicSessionRegisterConnection(Listener->Session, Connection); + Connection->State.ListenerAccepted = TRUE; QUIC_LISTENER_EVENT Event; Event.Type = QUIC_LISTENER_EVENT_NEW_CONNECTION; Event.NEW_CONNECTION.Info = Info; Event.NEW_CONNECTION.Connection = (HQUIC)Connection; - Event.NEW_CONNECTION.SecurityConfig = NULL; - QuicSessionAttachSilo(Listener->Session); + QuicListenerAttachSilo(Listener); QuicTraceLogVerbose( ListenerIndicateNewConnection, "[list][%p] Indicating NEW_CONNECTION", Listener); + QUIC_STATUS Status = QuicListenerIndicateEvent(Listener, &Event); - QuicSessionDetachSilo(); + QuicListenerDetachSilo(); - if (Status == QUIC_STATUS_PENDING) { - QuicTraceLogVerbose( - ListenerNewConnectionPending, - "[list][%p] App indicate pending NEW_CONNECTION", - Listener); - QUIC_DBG_ASSERT(Event.NEW_CONNECTION.SecurityConfig == NULL); - *SecConfig = NULL; - } else if (QUIC_FAILED(Status)) { + if (QUIC_FAILED(Status)) { QuicTraceEvent( ListenerErrorStatus, "[list][%p] ERROR, %u, %s.", Listener, Status, "NEW_CONNECTION callback"); - goto Exit; - } else if (Event.NEW_CONNECTION.SecurityConfig == NULL) { - QuicTraceEvent( - ListenerError, - "[list][%p] ERROR, %s.", - Listener, - "NEW_CONNECTION callback didn't set SecConfig"); - Status = QUIC_STATUS_INVALID_PARAMETER; - goto Exit; - } else { - QuicTraceLogVerbose( - ListenerNewConnectionAccepted, - "[list][%p] App accepted NEW_CONNECTION", - Listener); - *SecConfig = Event.NEW_CONNECTION.SecurityConfig; + QuicConnTransportError( + Connection, + QUIC_ERROR_CONNECTION_REFUSED); + return FALSE; } // - // The application layer has accepted the connection and provided a - // server certificate. + // The application layer has accepted the connection and provided a server + // certificate. // QUIC_FRE_ASSERTMSG( Connection->ClientCallbackHandler != NULL, "App MUST set callback handler!"); Connection->State.ExternalOwner = TRUE; - Connection->State.ListenerAccepted = TRUE; - - if (!QuicConnGenerateNewSourceCid(Connection, TRUE)) { - Event.NEW_CONNECTION.SecurityConfig = NULL; - Status = QUIC_STATUS_OUT_OF_MEMORY; - goto Exit; - } - - if (Event.NEW_CONNECTION.SecurityConfig != NULL) { - (void)QuicTlsSecConfigAddRef(Event.NEW_CONNECTION.SecurityConfig); - } Connection->State.UpdateWorker = TRUE; -Exit: - - if (Status != QUIC_STATUS_PENDING && QUIC_FAILED(Status)) { - QuicSessionUnregisterConnection(Connection); - QuicPerfCounterIncrement(QUIC_PERF_COUNTER_CONN_APP_REJECT); - } - - return Status; + return TRUE; } _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CONNECTION_ACCEPT_RESULT +void QuicListenerAcceptConnection( _In_ QUIC_LISTENER* Listener, _In_ QUIC_CONNECTION* Connection, - _In_ const QUIC_NEW_CONNECTION_INFO* Info, - _Out_ QUIC_SEC_CONFIG** SecConfig + _In_ const QUIC_NEW_CONNECTION_INFO* Info ) { - QUIC_CONNECTION_ACCEPT_RESULT AcceptResult = - QuicRegistrationAcceptConnection( - Listener->Session->Registration, - Connection); - if (AcceptResult != QUIC_CONNECTION_ACCEPT) { - goto Error; - } - - QUIC_STATUS Status = - QuicListenerClaimConnection( - Listener, + if (!QuicRegistrationAcceptConnection( + Listener->Registration, + Connection)) { + QuicTraceEvent( + ConnError, + "[conn][%p] ERROR, %s.", Connection, - Info, - SecConfig); - if (Status != QUIC_STATUS_PENDING) { - if (QUIC_FAILED(Status)) { - QUIC_TEL_ASSERTMSG(*SecConfig == NULL, "App failed AND provided a sec config?"); - goto Error; - } else if (*SecConfig == NULL) { - QuicTraceLogConnVerbose( - NoSecurityConfigAvailable, - Connection, - "No security config was provided by the app."); - goto Error; - } + "Connection rejected by registration (overloaded)"); + QuicConnTransportError( + Connection, + QUIC_ERROR_CONNECTION_REFUSED); + Listener->TotalRejectedConnections++; + return; } - Listener->TotalAcceptedConnections++; - return QUIC_CONNECTION_ACCEPT; + QuicConnRegister(Connection, Listener->Registration); + if (!QuicConnGenerateNewSourceCid(Connection, TRUE)) { + return; + } -Error: + if (!QuicListenerClaimConnection(Listener, Connection, Info)) { + Listener->TotalRejectedConnections++; + QuicPerfCounterIncrement(QUIC_PERF_COUNTER_CONN_APP_REJECT); + return; + } - *SecConfig = NULL; - Listener->TotalRejectedConnections++; - return QUIC_CONNECTION_REJECT_APP; + Listener->TotalAcceptedConnections++; } _IRQL_requires_max_(PASSIVE_LEVEL) diff --git a/src/core/listener.h b/src/core/listener.h index e8c394f41e..a543fb5e8d 100644 --- a/src/core/listener.h +++ b/src/core/listener.h @@ -23,9 +23,16 @@ typedef struct QUIC_LISTENER { QUIC_LIST_ENTRY Link; // - // The top level session. + // The top level registration. // - QUIC_SESSION* Session; + QUIC_REGISTRATION* Registration; + +#ifdef QUIC_SILO + // + // The silo. + // + QUIC_SILO Silo; +#endif // // Rundown for unregistering from a binding. @@ -53,8 +60,34 @@ typedef struct QUIC_LISTENER { uint64_t TotalAcceptedConnections; uint64_t TotalRejectedConnections; + // + // The application layer protocol negotiation buffers. Encoded in the TLS + // extension format. + // + uint16_t AlpnListLength; + _Field_size_(AlpnListLength) + uint8_t* AlpnList; + } QUIC_LISTENER; +#ifdef QUIC_SILO + +#define QuicListenerAttachSilo(Listener) \ + QUIC_SILO PrevSilo = Listener->Silo == NULL ? \ + QUIC_SILO_INVALID : QuicSiloAttach(Listener->Silo) + +#define QuicListenerDetachSilo() \ + if (PrevSilo != QUIC_SILO_INVALID) {\ + QuicSiloDetatch(PrevSilo); \ + } + +#else + +#define QuicListenerAttachSilo(Listener) +#define QuicListenerDetachSilo() + +#endif // #ifdef QUIC_SILO + // // Tracing rundown for the binding. // @@ -65,25 +98,35 @@ QuicListenerTraceRundown( ); // -// Indicates an event to the application layer. +// Returns TRUE if the two listeners have an overlapping ALPN. // -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicListenerIndicateEvent( - _In_ QUIC_LISTENER* Listener, - _Inout_ QUIC_LISTENER_EVENT* Event +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicListenerHasAlpnOverlap( + _In_ const QUIC_LISTENER* Listener1, + _In_ const QUIC_LISTENER* Listener2 + ); + +// +// Returns TRUE if the listener has a matching ALPN. Also updates the new +// connection info with the matching ALPN. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +QuicListenerMatchesAlpn( + _In_ const QUIC_LISTENER* Listener, + _In_ QUIC_NEW_CONNECTION_INFO* Info ); // // Passes the connection to the listener to (possibly) accept it. // _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CONNECTION_ACCEPT_RESULT +void QuicListenerAcceptConnection( _In_ QUIC_LISTENER* Listener, _In_ QUIC_CONNECTION* Connection, - _In_ const QUIC_NEW_CONNECTION_INFO* Info, - _Out_ QUIC_SEC_CONFIG** SecConfig + _In_ const QUIC_NEW_CONNECTION_INFO* Info ); // diff --git a/src/core/loss_detection.c b/src/core/loss_detection.c index 1eb6ab57e8..0e92da67cf 100644 --- a/src/core/loss_detection.c +++ b/src/core/loss_detection.c @@ -227,8 +227,8 @@ QuicLossDetectionComputeProbeTimeout( 4 * Path->RttVariance + (uint32_t)MS_TO_US(Connection->PeerTransportParams.MaxAckDelay); Pto *= Count; - if (Pto < MsQuicLib.Settings.MaxWorkerQueueDelayUs) { - Pto = MsQuicLib.Settings.MaxWorkerQueueDelayUs; + if (Pto < Connection->Settings.MaxWorkerQueueDelayUs) { + Pto = Connection->Settings.MaxWorkerQueueDelayUs; } return Pto; } @@ -349,7 +349,7 @@ QuicLossDetectionUpdateTimer( MaxDelay = QuicTimeDiff32( TimeNow, - OldestPacket->SentTime + Connection->DisconnectTimeoutUs); + OldestPacket->SentTime + MS_TO_US(Connection->Settings.DisconnectTimeoutMs)); } else { MaxDelay = (UINT32_MAX >> 1) - 1; } @@ -720,10 +720,10 @@ QuicLossDetectionRetransmitFrames( QUIC_PATH* Path = QuicConnGetPathByID(Connection, Packet->PathId); if (Path != NULL && !Path->IsPeerValidated) { uint32_t TimeNow = QuicTimeUs32(); - QUIC_DBG_ASSERT(Connection->Session != NULL); + QUIC_DBG_ASSERT(Connection->Configuration != NULL); uint32_t ValidationTimeout = max(QuicLossDetectionComputeProbeTimeout(LossDetection, Path, 3), - 6 * MS_TO_US(Connection->Session->Settings.InitialRttMs)); + 6 * MS_TO_US(Connection->Settings.InitialRttMs)); if (QuicTimeDiff32(Path->PathValidationStartTime, TimeNow) > ValidationTimeout) { QuicTraceLogConnInfo( PathValidationTimeout, @@ -1547,7 +1547,7 @@ QuicLossDetectionProcessTimerOperation( if (OldestPacket != NULL && QuicTimeDiff32(OldestPacket->SentTime, TimeNow) >= - Connection->DisconnectTimeoutUs) { + MS_TO_US(Connection->Settings.DisconnectTimeoutMs)) { // // OldestPacket has been in the SentPackets list for at least // DisconnectTimeoutUs without an ACK for either OldestPacket or for any diff --git a/src/core/operation.c b/src/core/operation.c index a4dab83caa..963dcbc699 100644 --- a/src/core/operation.c +++ b/src/core/operation.c @@ -93,9 +93,12 @@ QuicOperationFree( if (Oper->Type == QUIC_OPER_TYPE_API_CALL) { QUIC_API_CONTEXT* ApiCtx = Oper->API_CALL.Context; if (ApiCtx->Type == QUIC_API_TYPE_CONN_START) { + QuicConfigurationRelease(ApiCtx->CONN_START.Configuration); if (ApiCtx->CONN_START.ServerName != NULL) { QUIC_FREE(ApiCtx->CONN_START.ServerName); } + } else if (ApiCtx->Type == QUIC_API_TYPE_CONN_SET_CONFIGURATION) { + QuicConfigurationRelease(ApiCtx->CONN_SET_CONFIGURATION.Configuration); } else if (ApiCtx->Type == QUIC_API_TYPE_CONN_SEND_RESUMPTION_TICKET) { if (ApiCtx->CONN_SEND_RESUMPTION_TICKET.ResumptionAppData != NULL) { QUIC_DBG_ASSERT(ApiCtx->CONN_SEND_RESUMPTION_TICKET.AppDataLength != 0); diff --git a/src/core/operation.h b/src/core/operation.h index de7f16f202..e2d71fe57a 100644 --- a/src/core/operation.h +++ b/src/core/operation.h @@ -46,6 +46,7 @@ typedef enum QUIC_API_TYPE { QUIC_API_TYPE_CONN_CLOSE, QUIC_API_TYPE_CONN_SHUTDOWN, QUIC_API_TYPE_CONN_START, + QUIC_API_TYPE_CONN_SET_CONFIGURATION, QUIC_API_TYPE_CONN_SEND_RESUMPTION_TICKET, QUIC_API_TYPE_STRM_CLOSE, @@ -96,11 +97,15 @@ typedef struct QUIC_API_CONTEXT { QUIC_VAR_INT ErrorCode; } CONN_SHUTDOWN; struct { + QUIC_CONFIGURATION* Configuration; _Null_terminated_ const char* ServerName; uint16_t ServerPort; QUIC_ADDRESS_FAMILY Family; } CONN_START; + struct { + QUIC_CONFIGURATION* Configuration; + } CONN_SET_CONFIGURATION; struct { QUIC_SEND_RESUMPTION_FLAGS Flags; uint8_t* ResumptionAppData; diff --git a/src/core/packet_builder.c b/src/core/packet_builder.c index 648e52bf2e..69301682de 100644 --- a/src/core/packet_builder.c +++ b/src/core/packet_builder.c @@ -781,7 +781,7 @@ QuicPacketBuilderFinalize( // if (Builder->PacketType == SEND_PACKET_SHORT_HEADER_TYPE && PacketSpace->CurrentKeyPhaseBytesSent + QUIC_MAX_MTU >= - Connection->Session->Settings.MaxBytesPerKey && + Connection->Settings.MaxBytesPerKey && !PacketSpace->AwaitingKeyPhaseConfirmation && Connection->State.HandshakeConfirmed) { diff --git a/src/core/path.c b/src/core/path.c index 2408b8e9de..6e4ae35c37 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -29,11 +29,7 @@ QuicPathInitialize( Path->ID = Connection->NextPathId++; // TODO - Check for duplicates after wrap around? Path->MinRtt = UINT32_MAX; Path->Mtu = QUIC_DEFAULT_PATH_MTU; - if (Connection->Session != NULL) { - Path->SmoothedRtt = MS_TO_US(Connection->Session->Settings.InitialRttMs); - } else { - Path->SmoothedRtt = MS_TO_US(QUIC_INITIAL_RTT); - } + Path->SmoothedRtt = MS_TO_US(Connection->Settings.InitialRttMs); Path->RttVariance = Path->SmoothedRtt / 2; QuicTraceLogConnInfo( diff --git a/src/core/precomp.h b/src/core/precomp.h index 58bae0e03a..579937556d 100644 --- a/src/core/precomp.h +++ b/src/core/precomp.h @@ -50,7 +50,7 @@ extern "C" { #include "binding.h" #include "api.h" #include "registration.h" -#include "session.h" +#include "configuration.h" #include "range.h" #include "recv_buffer.h" #include "send_buffer.h" diff --git a/src/core/quicdef.h b/src/core/quicdef.h index aaf380f2bd..d61837cd69 100644 --- a/src/core/quicdef.h +++ b/src/core/quicdef.h @@ -10,7 +10,7 @@ typedef struct QUIC_OPERATION QUIC_OPERATION; typedef struct QUIC_WORKER QUIC_WORKER; typedef struct QUIC_WORKER_POOL QUIC_WORKER_POOL; typedef struct QUIC_REGISTRATION QUIC_REGISTRATION; -typedef struct QUIC_SESSION QUIC_SESSION; +typedef struct QUIC_CONFIGURATION QUIC_CONFIGURATION; typedef struct QUIC_LISTENER QUIC_LISTENER; typedef struct QUIC_CONNECTION QUIC_CONNECTION; typedef struct QUIC_STREAM QUIC_STREAM; @@ -409,6 +409,12 @@ QUIC_STATIC_ASSERT( // #define QUIC_TLS_RESUMPTION_TICKET_VERSION 1 +// +// Version of the blob for client resumption tickets. +// This needs to be incremented for each change in order or count of fields. +// +#define QUIC_TLS_RESUMPTION_CLIENT_TICKET_VERSION 1 + // // The AEAD Integrity limit for maximum failed decryption packets over the // lifetime of a connection. Set to the lowest limit, which is for @@ -429,6 +435,7 @@ QUIC_STATIC_ASSERT( #define QUIC_SETTING_MAX_STATELESS_OPERATIONS "MaxStatelessOperations" #define QUIC_SETTING_MAX_OPERATIONS_PER_DRAIN "MaxOperationsPerDrain" +#define QUIC_SETTING_SEND_BUFFERING_DEFAULT "SendBufferingDefault" #define QUIC_SETTING_SEND_PACING_DEFAULT "SendPacingDefault" #define QUIC_SETTING_MIGRATION_ENABLED "MigrationEnabled" #define QUIC_SETTING_DATAGRAM_RECEIVE_ENABLED "DatagramReceiveEnabled" diff --git a/src/core/registration.c b/src/core/registration.c index ceff08d5fe..6ac5395e11 100644 --- a/src/core/registration.c +++ b/src/core/registration.c @@ -69,10 +69,11 @@ MsQuicRegistrationOpen( Registration->ExecProfile = Config == NULL ? QUIC_EXECUTION_PROFILE_LOW_LATENCY : Config->ExecutionProfile; Registration->CidPrefixLength = 0; Registration->CidPrefix = NULL; - QuicLockInitialize(&Registration->Lock); - QuicListInitializeHead(&Registration->Sessions); - QuicRundownInitialize(&Registration->SecConfigRundown); - QuicRundownInitialize(&Registration->ConnectionRundown); + QuicLockInitialize(&Registration->ConfigLock); + QuicListInitializeHead(&Registration->Configurations); + QuicDispatchLockInitialize(&Registration->ConnectionLock); + QuicListInitializeHead(&Registration->Connections); + QuicRundownInitialize(&Registration->Rundown); Registration->AppNameLength = (uint8_t)(AppNameLength + 1); if (AppNameLength != 0) { QuicCopyMemory(Registration->AppName, Config->AppName, AppNameLength + 1); @@ -143,9 +144,11 @@ MsQuicRegistrationOpen( } #endif - QuicLockAcquire(&MsQuicLib.Lock); - QuicListInsertTail(&MsQuicLib.Registrations, &Registration->Link); - QuicLockRelease(&MsQuicLib.Lock); + if (Registration->ExecProfile != QUIC_EXECUTION_PROFILE_TYPE_INTERNAL) { + QuicLockAcquire(&MsQuicLib.Lock); + QuicListInsertTail(&MsQuicLib.Registrations, &Registration->Link); + QuicLockRelease(&MsQuicLib.Lock); + } *NewRegistration = (HQUIC)Registration; Registration = NULL; @@ -153,9 +156,9 @@ MsQuicRegistrationOpen( Error: if (Registration != NULL) { - QuicRundownUninitialize(&Registration->SecConfigRundown); - QuicRundownUninitialize(&Registration->ConnectionRundown); - QuicLockUninitialize(&Registration->Lock); + QuicRundownUninitialize(&Registration->Rundown); + QuicDispatchLockUninitialize(&Registration->ConnectionLock); + QuicLockUninitialize(&Registration->ConfigLock); QUIC_FREE(Registration); } @@ -190,24 +193,18 @@ MsQuicRegistrationClose( "[ reg][%p] Cleaning up", Registration); - // - // If you hit this assert, you are trying to clean up a registration without - // first cleaning up all the child sessions first. - // - QUIC_REG_VERIFY(Registration, QuicListIsEmpty(&Registration->Sessions)); - - QuicLockAcquire(&MsQuicLib.Lock); - QuicListEntryRemove(&Registration->Link); - QuicLockRelease(&MsQuicLib.Lock); + if (Registration->ExecProfile != QUIC_EXECUTION_PROFILE_TYPE_INTERNAL) { + QuicLockAcquire(&MsQuicLib.Lock); + QuicListEntryRemove(&Registration->Link); + QuicLockRelease(&MsQuicLib.Lock); + } - QuicRundownReleaseAndWait(&Registration->ConnectionRundown); + QuicRundownReleaseAndWait(&Registration->Rundown); QuicWorkerPoolUninitialize(Registration->WorkerPool); - QuicRundownReleaseAndWait(&Registration->SecConfigRundown); - - QuicRundownUninitialize(&Registration->SecConfigRundown); - QuicRundownUninitialize(&Registration->ConnectionRundown); - QuicLockUninitialize(&Registration->Lock); + QuicRundownUninitialize(&Registration->Rundown); + QuicDispatchLockUninitialize(&Registration->ConnectionLock); + QuicLockUninitialize(&Registration->ConfigLock); if (Registration->CidPrefix != NULL) { QUIC_FREE(Registration->CidPrefix); @@ -221,115 +218,119 @@ MsQuicRegistrationClose( } } -_IRQL_requires_max_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) void -QuicRegistrationTraceRundown( - _In_ QUIC_REGISTRATION* Registration +QUIC_API +MsQuicRegistrationShutdown( + _In_ _Pre_defensive_ HQUIC Handle, + _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, + _In_ _Pre_defensive_ QUIC_UINT62 ErrorCode ) { + QUIC_DBG_ASSERT(Handle != NULL); + QUIC_DBG_ASSERT(Handle->Type == QUIC_HANDLE_TYPE_REGISTRATION); + + if (ErrorCode > QUIC_UINT62_MAX) { + return; + } + QuicTraceEvent( - RegistrationRundown, - "[ reg][%p] Rundown, AppName=%s", - Registration, - Registration->AppName); + ApiEnter, + "[ api] Enter %u (%p).", + QUIC_TRACE_API_REGISTRATION_SHUTDOWN, + Handle); - QuicLockAcquire(&Registration->Lock); + if (Handle && Handle->Type == QUIC_HANDLE_TYPE_REGISTRATION) { +#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") + QUIC_REGISTRATION* Registration = (QUIC_REGISTRATION*)Handle; - for (QUIC_LIST_ENTRY* Link = Registration->Sessions.Flink; - Link != &Registration->Sessions; - Link = Link->Flink) { - QuicSessionTraceRundown( - QUIC_CONTAINING_RECORD(Link, QUIC_SESSION, Link)); - } + QuicDispatchLockAcquire(&Registration->ConnectionLock); - QuicLockRelease(&Registration->Lock); -} + QUIC_LIST_ENTRY* Entry = Registration->Connections.Flink; + while (Entry != &Registration->Connections) { -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicRegistrationSettingsChanged( - _Inout_ QUIC_REGISTRATION* Registration - ) -{ - QuicLockAcquire(&Registration->Lock); + QUIC_CONNECTION* Connection = + QUIC_CONTAINING_RECORD(Entry, QUIC_CONNECTION, RegistrationLink); - for (QUIC_LIST_ENTRY* Link = Registration->Sessions.Flink; - Link != &Registration->Sessions; - Link = Link->Flink) { - QuicSessionSettingsChanged( - QUIC_CONTAINING_RECORD(Link, QUIC_SESSION, Link)); + if (InterlockedCompareExchange16( + (short*)&Connection->BackUpOperUsed, 1, 0) == 0) { + + QUIC_OPERATION* Oper = &Connection->BackUpOper; + Oper->FreeAfterProcess = FALSE; + Oper->Type = QUIC_OPER_TYPE_API_CALL; + Oper->API_CALL.Context = &Connection->BackupApiContext; + Oper->API_CALL.Context->Type = QUIC_API_TYPE_CONN_SHUTDOWN; + Oper->API_CALL.Context->CONN_SHUTDOWN.Flags = Flags; + Oper->API_CALL.Context->CONN_SHUTDOWN.ErrorCode = ErrorCode; + QuicConnQueueHighestPriorityOper(Connection, Oper); + } + + Entry = Entry->Flink; + } + + QuicDispatchLockRelease(&Registration->ConnectionLock); } - QuicLockRelease(&Registration->Lock); + QuicTraceEvent( + ApiExit, + "[ api] Exit"); } _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QUIC_API -MsQuicSecConfigCreate( - _In_ _Pre_defensive_ HQUIC Handle, - _In_ QUIC_SEC_CONFIG_FLAGS Flags, - _In_opt_ void* Certificate, - _In_opt_z_ const char* Principal, - _In_opt_ void* Context, - _In_ _Pre_defensive_ QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER CompletionHandler +void +QuicRegistrationTraceRundown( + _In_ QUIC_REGISTRATION* Registration ) { - QUIC_STATUS Status = QUIC_STATUS_INVALID_PARAMETER; - QuicTraceEvent( - ApiEnter, - "[ api] Enter %u (%p).", - QUIC_TRACE_API_SEC_CONFIG_CREATE, - Handle); + RegistrationRundown, + "[ reg][%p] Rundown, AppName=%s", + Registration, + Registration->AppName); - if (Handle != NULL && - Handle->Type == QUIC_HANDLE_TYPE_REGISTRATION && - CompletionHandler != NULL) { + QuicLockAcquire(&Registration->ConfigLock); - QUIC_REGISTRATION* Registration = (QUIC_REGISTRATION*)Handle; - Status = - QuicTlsServerSecConfigCreate( - &Registration->SecConfigRundown, - Flags, - Certificate, - Principal, - Context, - CompletionHandler); + for (QUIC_LIST_ENTRY* Link = Registration->Configurations.Flink; + Link != &Registration->Configurations; + Link = Link->Flink) { + QuicConfigurationTraceRundown( + QUIC_CONTAINING_RECORD(Link, QUIC_CONFIGURATION, Link)); } - QuicTraceEvent( - ApiExitStatus, - "[ api] Exit %u", - Status); + QuicLockRelease(&Registration->ConfigLock); - return Status; + QuicDispatchLockAcquire(&Registration->ConnectionLock); + + for (QUIC_LIST_ENTRY* Link = Registration->Connections.Flink; + Link != &Registration->Connections; + Link = Link->Flink) { + QuicConnQueueTraceRundown( + QUIC_CONTAINING_RECORD(Link, QUIC_CONNECTION, RegistrationLink)); + } + + QuicDispatchLockRelease(&Registration->ConnectionLock); } _IRQL_requires_max_(PASSIVE_LEVEL) void -QUIC_API -MsQuicSecConfigDelete( - _In_ _Pre_defensive_ QUIC_SEC_CONFIG* SecurityConfig +QuicRegistrationSettingsChanged( + _Inout_ QUIC_REGISTRATION* Registration ) { - QuicTraceEvent( - ApiEnter, - "[ api] Enter %u (%p).", - QUIC_TRACE_API_SEC_CONFIG_DELETE, - SecurityConfig); + QuicLockAcquire(&Registration->ConfigLock); - if (SecurityConfig != NULL) { - QuicTlsSecConfigRelease(SecurityConfig); + for (QUIC_LIST_ENTRY* Link = Registration->Configurations.Flink; + Link != &Registration->Configurations; + Link = Link->Flink) { + QuicConfigurationSettingsChanged( + QUIC_CONTAINING_RECORD(Link, QUIC_CONFIGURATION, Link)); } - QuicTraceEvent( - ApiExit, - "[ api] Exit"); + QuicLockRelease(&Registration->ConfigLock); } _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CONNECTION_ACCEPT_RESULT +BOOLEAN QuicRegistrationAcceptConnection( _In_ QUIC_REGISTRATION* Registration, _In_ QUIC_CONNECTION* Connection @@ -349,11 +350,7 @@ QuicRegistrationAcceptConnection( // TODO - Look for other worker instead if the proposed worker is overloaded? // - if (QuicWorkerIsOverloaded(&Registration->WorkerPool->Workers[Index])) { - return QUIC_CONNECTION_REJECT_BUSY; - } else { - return QUIC_CONNECTION_ACCEPT; - } + return !QuicWorkerIsOverloaded(&Registration->WorkerPool->Workers[Index]); } _IRQL_requires_max_(PASSIVE_LEVEL) diff --git a/src/core/registration.h b/src/core/registration.h index 6dc9d2c34a..72007683a5 100644 --- a/src/core/registration.h +++ b/src/core/registration.h @@ -5,6 +5,12 @@ --*/ +// +// Special internal type to indicate registration created for global listener +// processing. +// +#define QUIC_EXECUTION_PROFILE_TYPE_INTERNAL ((QUIC_EXECUTION_PROFILE)0xFF) + // // Different outcomes for a new incoming connection. // @@ -63,24 +69,29 @@ typedef struct QUIC_REGISTRATION { QUIC_WORKER_POOL* WorkerPool; // - // Protects access to the Sessions list. + // Protects access to the Configurations list. + // + QUIC_LOCK ConfigLock; + + // + // List of all configurations for this registration. // - QUIC_LOCK Lock; + QUIC_LIST_ENTRY Configurations; // - // List of all sessions for this registration. + // Protects access to the Connections list. // - QUIC_LIST_ENTRY Sessions; + QUIC_DISPATCH_LOCK ConnectionLock; // - // Rundown for all connections + // List of all connections for this registration. // - QUIC_RUNDOWN_REF ConnectionRundown; + QUIC_LIST_ENTRY Connections; // - // Rundown for all outstanding security configs. + // Rundown for all child objects. // - QUIC_RUNDOWN_REF SecConfigRundown; + QUIC_RUNDOWN_REF Rundown; // // Name of the application layer. @@ -123,7 +134,7 @@ QuicRegistrationSettingsChanged( // or not. // _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_CONNECTION_ACCEPT_RESULT +BOOLEAN QuicRegistrationAcceptConnection( _In_ QUIC_REGISTRATION* Registration, _In_ QUIC_CONNECTION* Connection diff --git a/src/core/send.c b/src/core/send.c index 9f84a7b241..054f7905ff 100644 --- a/src/core/send.c +++ b/src/core/send.c @@ -28,10 +28,12 @@ _IRQL_requires_max_(PASSIVE_LEVEL) void QuicSendInitialize( - _Inout_ QUIC_SEND* Send + _Inout_ QUIC_SEND* Send, + _In_ const QUIC_SETTINGS* Settings ) { QuicListInitializeHead(&Send->SendStreams); + Send->MaxData = Settings->ConnFlowControlWindow; } _IRQL_requires_max_(PASSIVE_LEVEL) @@ -67,7 +69,7 @@ QuicSendUninitialize( _IRQL_requires_max_(PASSIVE_LEVEL) void -QuicSendApplySettings( +QuicSendApplyNewSettings( _Inout_ QUIC_SEND* Send, _In_ const QUIC_SETTINGS* Settings ) @@ -1190,11 +1192,11 @@ QuicSendStartDelayedAckTimer( StartAckDelayTimer, Connection, "Starting ACK_DELAY timer for %u ms", - Connection->MaxAckDelayMs); + Connection->Settings.MaxAckDelayMs); QuicConnTimerSet( Connection, QUIC_CONN_TIMER_ACK_DELAY, - Connection->MaxAckDelayMs); // TODO - Use smaller timeout when handshake data is outstanding. + Connection->Settings.MaxAckDelayMs); // TODO - Use smaller timeout when handshake data is outstanding. Send->DelayedAckTimerActive = TRUE; } } diff --git a/src/core/send.h b/src/core/send.h index 6d081df93a..64b9098f71 100644 --- a/src/core/send.h +++ b/src/core/send.h @@ -239,7 +239,8 @@ typedef struct QUIC_SEND { _IRQL_requires_max_(PASSIVE_LEVEL) void QuicSendInitialize( - _Inout_ QUIC_SEND* Send + _Inout_ QUIC_SEND* Send, + _In_ const QUIC_SETTINGS* Settings ); _IRQL_requires_max_(PASSIVE_LEVEL) @@ -260,7 +261,7 @@ QuicSendValidate( _IRQL_requires_max_(PASSIVE_LEVEL) void -QuicSendApplySettings( +QuicSendApplyNewSettings( _Inout_ QUIC_SEND* Send, _In_ const QUIC_SETTINGS* Settings ); diff --git a/src/core/send_buffer.c b/src/core/send_buffer.c index 6656a09caa..97f37ae889 100644 --- a/src/core/send_buffer.c +++ b/src/core/send_buffer.c @@ -146,7 +146,7 @@ QuicSendBufferFill( QUIC_SEND_REQUEST* Req; QUIC_LIST_ENTRY* Entry; - QUIC_DBG_ASSERT(Connection->State.UseSendBuffer); + QUIC_DBG_ASSERT(Connection->Settings.SendBufferingEnabled); Entry = Connection->Send.SendStreams.Flink; while (QuicSendBufferHasSpace(&Connection->SendBuffer) && Entry != &(Connection->Send.SendStreams)) { @@ -251,7 +251,7 @@ QuicSendBufferConnectionAdjust( } QuicHashtableEnumerateEnd(Connection->Streams.StreamTable, &Enumerator); - if (Connection->State.UseSendBuffer) { + if (Connection->Settings.SendBufferingEnabled) { QuicSendBufferFill(Connection); } } diff --git a/src/core/session.c b/src/core/session.c deleted file mode 100644 index ee8bd69e3c..0000000000 --- a/src/core/session.c +++ /dev/null @@ -1,841 +0,0 @@ -/*++ - - Copyright (c) Microsoft Corporation. - Licensed under the MIT License. - -Abstract: - - A "session" manages TLS session state, which is used for session - resumption across connections. On Windows it also manages silo - and network compartment state. - ---*/ - -#include "precomp.h" -#ifdef QUIC_CLOG -#include "session.c.clog.h" -#endif - -_IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS -QuicSessionAlloc( - _In_opt_ QUIC_REGISTRATION* Registration, - _In_opt_ void* Context, - _When_(AlpnBufferCount > 0, _In_reads_(AlpnBufferCount)) - _When_(AlpnBufferCount == 0, _In_opt_) - const QUIC_BUFFER* const AlpnBuffers, - _In_ uint32_t AlpnBufferCount, - _Outptr_ _At_(*NewSession, __drv_allocatesMem(Mem)) - QUIC_SESSION** NewSession - ) -{ - uint32_t AlpnListLength = 0; - for (uint32_t i = 0; i < AlpnBufferCount; ++i) { - if (AlpnBuffers[i].Length == 0 || - AlpnBuffers[i].Length > QUIC_MAX_ALPN_LENGTH) { - return QUIC_STATUS_INVALID_PARAMETER; - } - AlpnListLength += sizeof(uint8_t) + AlpnBuffers[i].Length; - } - if (AlpnListLength > UINT16_MAX) { - return QUIC_STATUS_INVALID_PARAMETER; - } - QUIC_ANALYSIS_ASSERT(AlpnListLength <= UINT16_MAX); - - QUIC_SESSION* Session = QUIC_ALLOC_NONPAGED(sizeof(QUIC_SESSION) + AlpnListLength); - if (Session == NULL) { - QuicTraceEvent( - AllocFailure, - "Allocation of '%s' failed. (%llu bytes)", - "session" , - sizeof(QUIC_SESSION) + AlpnListLength); - return QUIC_STATUS_OUT_OF_MEMORY; - } - - QuicZeroMemory(Session, sizeof(QUIC_SESSION)); - Session->Type = QUIC_HANDLE_TYPE_SESSION; - Session->ClientContext = Context; - Session->AlpnListLength = (uint16_t)AlpnListLength; - - uint8_t* AlpnList = Session->AlpnList; - for (uint32_t i = 0; i < AlpnBufferCount; ++i) { - AlpnList[0] = (uint8_t)AlpnBuffers[i].Length; - AlpnList++; - - QuicCopyMemory( - AlpnList, - AlpnBuffers[i].Buffer, - AlpnBuffers[i].Length); - AlpnList += AlpnBuffers[i].Length; - } - - if (Registration != NULL) { - Session->Registration = Registration; - -#ifdef QUIC_SILO - Session->Silo = QuicSiloGetCurrentServer(); - QuicSiloAddRef(Session->Silo); -#endif - -#ifdef QUIC_COMPARTMENT_ID - Session->CompartmentId = QuicCompartmentIdGetCurrent(); -#endif - } - - QuicTraceEvent( - SessionCreated, - "[sess][%p] Created, Registration=%p, Alpn=%s", - Session, - Session->Registration, - ""); // TODO - Buffer and length - - QuicRundownInitialize(&Session->Rundown); - QuicRwLockInitialize(&Session->ServerCacheLock); - QuicDispatchLockInitialize(&Session->ConnectionsLock); - QuicListInitializeHead(&Session->Connections); - - *NewSession = Session; - - return QUIC_STATUS_SUCCESS; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -MsQuicSessionFree( - _In_ _Pre_defensive_ __drv_freesMem(Mem) - QUIC_SESSION* Session - ) -{ - // - // If you hit this assert, you are trying to clean up a session without - // first cleaning up all the child connections first. - // - QUIC_TEL_ASSERT(QuicListIsEmpty(&Session->Connections)); - QuicRundownUninitialize(&Session->Rundown); - - if (Session->Registration != NULL) { - QuicTlsSessionUninitialize(Session->TlsSession); - - // - // Enumerate and free all entries in the table. - // - QUIC_HASHTABLE_ENTRY* Entry; - QUIC_HASHTABLE_ENUMERATOR Enumerator; - QuicHashtableEnumerateBegin(&Session->ServerCache, &Enumerator); - while (TRUE) { - Entry = QuicHashtableEnumerateNext(&Session->ServerCache, &Enumerator); - if (Entry == NULL) { - QuicHashtableEnumerateEnd(&Session->ServerCache, &Enumerator); - break; - } - QuicHashtableRemove(&Session->ServerCache, Entry, NULL); - - // - // Release the security config stored in this cache. - // - QUIC_SERVER_CACHE* Temp = QUIC_CONTAINING_RECORD(Entry, QUIC_SERVER_CACHE, Entry); - if (Temp->SecConfig != NULL) { - QuicTlsSecConfigRelease(Temp->SecConfig); - } - - QUIC_FREE(Entry); - } - QuicHashtableUninitialize(&Session->ServerCache); - - QuicStorageClose(Session->AppSpecificStorage); -#ifdef QUIC_SILO - QuicStorageClose(Session->Storage); - QuicSiloRelease(Session->Silo); -#endif - } - - QuicDispatchLockUninitialize(&Session->ConnectionsLock); - QuicRwLockUninitialize(&Session->ServerCacheLock); - QuicTraceEvent( - SessionDestroyed, - "[sess][%p] Destroyed", - Session); - QUIC_FREE(Session); -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QUIC_API -MsQuicSessionOpen( - _In_ _Pre_defensive_ HQUIC RegistrationContext, - _In_ uint32_t SettingsSize, - _In_reads_bytes_opt_(SettingsSize) - const QUIC_SETTINGS* Settings, - _In_reads_(AlpnBufferCount) _Pre_defensive_ - const QUIC_BUFFER* const AlpnBuffers, - _In_range_(>, 0) uint32_t AlpnBufferCount, - _In_opt_ void* Context, - _Outptr_ _At_(*NewSession, __drv_allocatesMem(Mem)) _Pre_defensive_ - HQUIC *NewSession - ) -{ - QUIC_STATUS Status; - QUIC_SESSION* Session = NULL; - - QuicTraceEvent( - ApiEnter, - "[ api] Enter %u (%p).", - QUIC_TRACE_API_SESSION_OPEN, - RegistrationContext); - - if (RegistrationContext == NULL || - RegistrationContext->Type != QUIC_HANDLE_TYPE_REGISTRATION || - NewSession == NULL || - AlpnBufferCount == 0 || - AlpnBuffers == NULL) { - Status = QUIC_STATUS_INVALID_PARAMETER; - goto Error; - } - - if (Settings != NULL && - SettingsSize < (uint32_t)FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - goto Error; - } - - Status = - QuicSessionAlloc( - (QUIC_REGISTRATION*)RegistrationContext, - Context, - AlpnBuffers, - AlpnBufferCount, - &Session); - if (QUIC_FAILED(Status)) { - goto Error; - } - - if (!QuicHashtableInitializeEx(&Session->ServerCache, QUIC_HASH_MIN_SIZE)) { - QuicTraceEvent( - SessionError, - "[sess][%p] ERROR, %s.", - Session, - "Server cache initialize"); - Status = QUIC_STATUS_OUT_OF_MEMORY; - goto Error; - } - - Status = QuicTlsSessionInitialize(&Session->TlsSession); - if (QUIC_FAILED(Status)) { - QuicTraceEvent( - SessionErrorStatus, - "[sess][%p] ERROR, %u, %s.", - Session, - Status, - "QuicTlsSessionInitialize"); - QuicHashtableUninitialize(&Session->ServerCache); - goto Error; - } - -#ifdef QUIC_SILO - if (Session->Silo != NULL) { - // - // Only need to load base key if in a silo. Otherwise, the library already - // read in the default silo settings. - // - Status = - QuicStorageOpen( - NULL, - (QUIC_STORAGE_CHANGE_CALLBACK_HANDLER)QuicSessionSettingsChanged, - Session, - &Session->Storage); - if (QUIC_FAILED(Status)) { - QuicTraceLogWarning( - SessionOpenStorageFailed, - "[sess][%p] Failed to open settings, 0x%x", - Session, - Status); - Status = QUIC_STATUS_SUCCESS; // Non-fatal, as the process may not have access - } - } -#endif - - if (Session->Registration->AppNameLength != 0) { - char SpecificAppKey[UINT8_MAX + sizeof(QUIC_SETTING_APP_KEY)] = QUIC_SETTING_APP_KEY; - QuicCopyMemory( - SpecificAppKey + sizeof(QUIC_SETTING_APP_KEY) - 1, - Session->Registration->AppName, - Session->Registration->AppNameLength); - Status = - QuicStorageOpen( - SpecificAppKey, - (QUIC_STORAGE_CHANGE_CALLBACK_HANDLER)QuicSessionSettingsChanged, - Session, - &Session->AppSpecificStorage); - if (QUIC_FAILED(Status)) { - QuicTraceLogWarning( - SessionOpenAppStorageFailed, - "[sess][%p] Failed to open app specific settings, 0x%x", - Session, - Status); - Status = QUIC_STATUS_SUCCESS; // Non-fatal, as the process may not have access - } - } - - if (Settings != NULL && Settings->IsSetFlags != 0) { - QUIC_DBG_ASSERT(SettingsSize >= (uint32_t)FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey)); - if (!QuicSettingApply(&Session->Settings, SettingsSize, Settings)) { - Status = QUIC_STATUS_INVALID_PARAMETER; - goto Error; - } - } - - QuicSessionSettingsChanged(Session); - - QuicLockAcquire(&Session->Registration->Lock); - QuicListInsertTail(&Session->Registration->Sessions, &Session->Link); - QuicLockRelease(&Session->Registration->Lock); - - *NewSession = (HQUIC)Session; - Session = NULL; - -Error: - - if (Session != NULL) { - MsQuicSessionFree(Session); - } - - QuicTraceEvent( - ApiExitStatus, - "[ api] Exit %u", - Status); - - return Status; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QUIC_API -MsQuicSessionClose( - _In_ _Pre_defensive_ __drv_freesMem(Mem) - HQUIC Handle - ) -{ - if (Handle == NULL) { - return; - } - - QUIC_TEL_ASSERT(Handle->Type == QUIC_HANDLE_TYPE_SESSION); - _Analysis_assume_(Handle->Type == QUIC_HANDLE_TYPE_SESSION); - if (Handle->Type != QUIC_HANDLE_TYPE_SESSION) { - return; - } - - QuicTraceEvent( - ApiEnter, - "[ api] Enter %u (%p).", - QUIC_TRACE_API_SESSION_CLOSE, - Handle); - -#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") - QUIC_SESSION* Session = (QUIC_SESSION*)Handle; - - QuicTraceEvent( - SessionCleanup, - "[sess][%p] Cleaning up", - Session); - - if (Session->Registration != NULL) { - QuicLockAcquire(&Session->Registration->Lock); - QuicListEntryRemove(&Session->Link); - QuicLockRelease(&Session->Registration->Lock); - } else { - // - // This is the global unregistered session. All connections need to be - // immediately cleaned up. Use shutdown to ensure this all gets placed - // on the worker queue. - // - MsQuicSessionShutdown(Handle, QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT, 0); - } - - QuicRundownReleaseAndWait(&Session->Rundown); - MsQuicSessionFree(Session); - - QuicTraceEvent( - ApiExit, - "[ api] Exit"); -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QUIC_API -MsQuicSessionShutdown( - _In_ _Pre_defensive_ HQUIC Handle, - _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, - _In_ _Pre_defensive_ QUIC_UINT62 ErrorCode - ) -{ - QUIC_DBG_ASSERT(Handle != NULL); - QUIC_DBG_ASSERT(Handle->Type == QUIC_HANDLE_TYPE_SESSION); - - if (ErrorCode > QUIC_UINT62_MAX) { - return; - } - - QuicTraceEvent( - ApiEnter, - "[ api] Enter %u (%p).", - QUIC_TRACE_API_SESSION_SHUTDOWN, - Handle); - - if (Handle && Handle->Type == QUIC_HANDLE_TYPE_SESSION) { -#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") - QUIC_SESSION* Session = (QUIC_SESSION*)Handle; - - QuicTraceEvent( - SessionShutdown, - "[sess][%p] Shutting down connections, Flags=%u, ErrorCode=%llu", - Session, - Flags, - ErrorCode); - - QuicDispatchLockAcquire(&Session->ConnectionsLock); - - QUIC_LIST_ENTRY* Entry = Session->Connections.Flink; - while (Entry != &Session->Connections) { - - QUIC_CONNECTION* Connection = - QUIC_CONTAINING_RECORD(Entry, QUIC_CONNECTION, SessionLink); - - if (InterlockedCompareExchange16( - (short*)&Connection->BackUpOperUsed, 1, 0) == 0) { - - QUIC_OPERATION* Oper = &Connection->BackUpOper; - Oper->FreeAfterProcess = FALSE; - Oper->Type = QUIC_OPER_TYPE_API_CALL; - Oper->API_CALL.Context = &Connection->BackupApiContext; - Oper->API_CALL.Context->Type = QUIC_API_TYPE_CONN_SHUTDOWN; - Oper->API_CALL.Context->CONN_SHUTDOWN.Flags = Flags; - Oper->API_CALL.Context->CONN_SHUTDOWN.ErrorCode = ErrorCode; - QuicConnQueueHighestPriorityOper(Connection, Oper); - } - - Entry = Entry->Flink; - } - - QuicDispatchLockRelease(&Session->ConnectionsLock); - } - - QuicTraceEvent( - ApiExit, - "[ api] Exit"); -} - -_IRQL_requires_max_(DISPATCH_LEVEL) -const uint8_t* -QuicSessionFindAlpnInList( - _In_ const QUIC_SESSION* Session, - _In_ uint16_t OtherAlpnListLength, - _In_reads_(OtherAlpnListLength) - const uint8_t* OtherAlpnList - ) -{ - const uint8_t* AlpnList = Session->AlpnList; - uint16_t AlpnListLength = Session->AlpnListLength; - - // - // We want to respect the server's ALPN preference order (i.e. Session) and - // not the client's. So we loop over every ALPN in the session and then see - // if there is a match in the client's list. - // - - while (AlpnListLength != 0) { - QUIC_ANALYSIS_ASSUME(AlpnList[0] + 1 <= AlpnListLength); - const uint8_t* Result = - QuicTlsAlpnFindInList( - OtherAlpnListLength, - OtherAlpnList, - AlpnList[0], - AlpnList + 1); - if (Result != NULL) { - // - // Return AlpnList instead of Result, since Result points into what - // might be a temporary buffer. - // - return AlpnList; - } - AlpnListLength -= AlpnList[0] + 1; - AlpnList += AlpnList[0] + 1; - } - - return NULL; -} - -_IRQL_requires_max_(DISPATCH_LEVEL) -BOOLEAN -QuicSessionHasAlpnOverlap( - _In_ const QUIC_SESSION* Session1, - _In_ const QUIC_SESSION* Session2 - ) -{ - return - QuicSessionFindAlpnInList( - Session1, - Session2->AlpnListLength, - Session2->AlpnList) != NULL; -} - -_IRQL_requires_max_(DISPATCH_LEVEL) -BOOLEAN -QuicSessionMatchesAlpn( - _In_ const QUIC_SESSION* Session, - _In_ QUIC_NEW_CONNECTION_INFO* Info - ) -{ - const uint8_t* Alpn = - QuicSessionFindAlpnInList(Session, Info->ClientAlpnListLength, Info->ClientAlpnList); - if (Alpn != NULL) { - Info->NegotiatedAlpnLength = Alpn[0]; // The length prefixed to the ALPN buffer. - Info->NegotiatedAlpn = Alpn + 1; - return TRUE; - } - return FALSE; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicSessionTraceRundown( - _In_ QUIC_SESSION* Session - ) -{ - QuicTraceEvent( - SessionRundown, - "[sess][%p] Rundown, Registration=%p, Alpn=%p", - Session, - Session->Registration, - ""); // TODO - - QuicDispatchLockAcquire(&Session->ConnectionsLock); - - for (QUIC_LIST_ENTRY* Link = Session->Connections.Flink; - Link != &Session->Connections; - Link = Link->Flink) { - QuicConnQueueTraceRundown( - QUIC_CONTAINING_RECORD(Link, QUIC_CONNECTION, SessionLink)); - } - - QuicDispatchLockRelease(&Session->ConnectionsLock); -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -_Function_class_(QUIC_STORAGE_CHANGE_CALLBACK) -void -QuicSessionSettingsChanged( - _Inout_ QUIC_SESSION* Session - ) -{ -#ifdef QUIC_SILO - if (Session->Storage != NULL) { - QuicSettingsSetDefault(&Session->Settings); - QuicSettingsLoad(&Session->Settings, Session->Storage); - } else { - QuicSettingsCopy(&Session->Settings, &MsQuicLib.Settings); - } -#else - QuicSettingsCopy(&Session->Settings, &MsQuicLib.Settings); -#endif - - if (Session->AppSpecificStorage != NULL) { - QuicSettingsLoad(&Session->Settings, Session->AppSpecificStorage); - } - - QuicTraceLogInfo( - SessionSettingsUpdated, - "[sess][%p] Settings %p Updated", - Session, - &Session->Settings); - QuicSettingsDump(&Session->Settings); -} - -_IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicSessionRegisterConnection( - _Inout_ QUIC_SESSION* Session, - _Inout_ QUIC_CONNECTION* Connection - ) -{ - QuicSessionUnregisterConnection(Connection); - Connection->Session = Session; - - if (Session->Registration != NULL) { - Connection->Registration = Session->Registration; - QuicRundownAcquire(&Session->Registration->ConnectionRundown); -#ifdef QuicVerifierEnabledByAddr - Connection->State.IsVerifying = Session->Registration->IsVerifying; -#endif - QuicConnApplySettings(Connection, &Session->Settings); - } - - QuicTraceEvent( - ConnRegisterSession, - "[conn][%p] Registered with session: %p", - Connection, - Session); - BOOLEAN Success = QuicRundownAcquire(&Session->Rundown); - QUIC_DBG_ASSERT(Success); UNREFERENCED_PARAMETER(Success); - QuicDispatchLockAcquire(&Session->ConnectionsLock); - QuicListInsertTail(&Session->Connections, &Connection->SessionLink); - QuicDispatchLockRelease(&Session->ConnectionsLock); -} - -_IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicSessionUnregisterConnection( - _Inout_ QUIC_CONNECTION* Connection - ) -{ - if (Connection->Session == NULL) { - return; - } - QUIC_SESSION* Session = Connection->Session; - Connection->Session = NULL; - QuicTraceEvent( - ConnUnregisterSession, - "[conn][%p] Unregistered from session: %p", - Connection, - Session); - QuicDispatchLockAcquire(&Session->ConnectionsLock); - QuicListEntryRemove(&Connection->SessionLink); - QuicDispatchLockRelease(&Session->ConnectionsLock); - QuicRundownRelease(&Session->Rundown); -} - -// -// Requires Session->Lock to be held (shared or exclusive). -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_SERVER_CACHE* -QuicSessionServerCacheLookup( - _In_ QUIC_SESSION* Session, - _In_ uint16_t ServerNameLength, - _In_reads_(ServerNameLength) - const char* ServerName, - _In_ uint32_t Hash - ) -{ - QUIC_HASHTABLE_LOOKUP_CONTEXT Context; - QUIC_HASHTABLE_ENTRY* Entry = - QuicHashtableLookup(&Session->ServerCache, Hash, &Context); - - while (Entry != NULL) { - QUIC_SERVER_CACHE* Temp = - QUIC_CONTAINING_RECORD(Entry, QUIC_SERVER_CACHE, Entry); - if (Temp->ServerNameLength == ServerNameLength && - memcmp(Temp->ServerName, ServerName, ServerNameLength) == 0) { - return Temp; - } - Entry = QuicHashtableLookupNext(&Session->ServerCache, &Context); - } - - return NULL; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -_Success_(return != FALSE) -BOOLEAN -QuicSessionServerCacheGetState( - _In_ QUIC_SESSION* Session, - _In_z_ const char* ServerName, - _Out_ uint32_t* QuicVersion, - _Out_ QUIC_TRANSPORT_PARAMETERS* Parameters, - _Out_ QUIC_SEC_CONFIG** ClientSecConfig - ) -{ - uint16_t ServerNameLength = (uint16_t)strlen(ServerName); - uint32_t Hash = QuicHashSimple(ServerNameLength, (const uint8_t*)ServerName); - - QuicRwLockAcquireShared(&Session->ServerCacheLock); - - QUIC_SERVER_CACHE* Cache = - QuicSessionServerCacheLookup( - Session, - ServerNameLength, - ServerName, - Hash); - - if (Cache != NULL) { - *QuicVersion = Cache->QuicVersion; - *Parameters = Cache->TransportParameters; - if (Cache->SecConfig != NULL) { - *ClientSecConfig = QuicTlsSecConfigAddRef(Cache->SecConfig); - } else { - *ClientSecConfig = NULL; - } - } - - QuicRwLockReleaseShared(&Session->ServerCacheLock); - - return Cache != NULL; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicSessionServerCacheSetStateInternal( - _In_ QUIC_SESSION* Session, - _In_ uint16_t ServerNameLength, - _In_reads_(ServerNameLength) - const char* ServerName, - _In_ uint32_t QuicVersion, - _In_ const QUIC_TRANSPORT_PARAMETERS* Parameters, - _In_opt_ QUIC_SEC_CONFIG* SecConfig - ) -{ - uint32_t Hash = QuicHashSimple(ServerNameLength, (const uint8_t*)ServerName); - - QuicRwLockAcquireExclusive(&Session->ServerCacheLock); - - QUIC_SERVER_CACHE* Cache = - QuicSessionServerCacheLookup( - Session, - ServerNameLength, - ServerName, - Hash); - - if (Cache != NULL) { - Cache->QuicVersion = QuicVersion; - Cache->TransportParameters = *Parameters; - if (SecConfig != NULL) { - if (Cache->SecConfig != NULL) { - QuicTlsSecConfigRelease(Cache->SecConfig); - } - Cache->SecConfig = QuicTlsSecConfigAddRef(SecConfig); - } - - } else { -#pragma prefast(suppress: __WARNING_6014, "Memory is correctly freed (MsQuicSessionClose).") - Cache = QUIC_ALLOC_PAGED(sizeof(QUIC_SERVER_CACHE) + ServerNameLength); - - if (Cache != NULL) { - memcpy(Cache + 1, ServerName, ServerNameLength); - Cache->ServerName = (const char*)(Cache + 1); - Cache->ServerNameLength = ServerNameLength; - Cache->QuicVersion = QuicVersion; - Cache->TransportParameters = *Parameters; - if (SecConfig != NULL) { - Cache->SecConfig = QuicTlsSecConfigAddRef(SecConfig); - } - - QuicHashtableInsert(&Session->ServerCache, &Cache->Entry, Hash, NULL); - - } else { - QuicTraceEvent( - AllocFailure, - "Allocation of '%s' failed. (%llu bytes)", - "server cache entry", - sizeof(QUIC_SERVER_CACHE) + ServerNameLength); - } - } - - QuicRwLockReleaseExclusive(&Session->ServerCacheLock); -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicSessionServerCacheSetState( - _In_ QUIC_SESSION* Session, - _In_z_ const char* ServerName, - _In_ uint32_t QuicVersion, - _In_ const QUIC_TRANSPORT_PARAMETERS* Parameters, - _In_ QUIC_SEC_CONFIG* SecConfig - ) -{ - QuicSessionServerCacheSetStateInternal( - Session, - (uint16_t)strlen(ServerName), - ServerName, - QuicVersion, - Parameters, - SecConfig); -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicSessionParamGet( - _In_ QUIC_SESSION* Session, - _In_ uint32_t Param, - _Inout_ uint32_t* BufferLength, - _Out_writes_bytes_opt_(*BufferLength) - void* Buffer - ) -{ - UNREFERENCED_PARAMETER(Session); - UNREFERENCED_PARAMETER(Param); - UNREFERENCED_PARAMETER(BufferLength); - UNREFERENCED_PARAMETER(Buffer); - return QUIC_STATUS_NOT_SUPPORTED; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicSessionParamSet( - _In_ QUIC_SESSION* Session, - _In_ uint32_t Param, - _In_ uint32_t BufferLength, - _In_reads_bytes_(BufferLength) - const void* Buffer - ) -{ - QUIC_STATUS Status; - - switch (Param) { - - case QUIC_PARAM_SESSION_TLS_TICKET_KEY: { - - if (BufferLength != 44) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - Status = - QuicTlsSessionSetTicketKey( - Session->TlsSession, - Buffer); - break; - } - - case QUIC_PARAM_SESSION_ADD_RESUMPTION_STATE: { - - const QUIC_SERIALIZED_RESUMPTION_STATE* State = - (const QUIC_SERIALIZED_RESUMPTION_STATE*)Buffer; - - if (BufferLength < sizeof(QUIC_SERIALIZED_RESUMPTION_STATE) || - BufferLength < sizeof(QUIC_SERIALIZED_RESUMPTION_STATE) + State->ServerNameLength) { - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - const char* ServerName = (const char*)State->Buffer; - - const uint8_t* TicketBuffer = State->Buffer + State->ServerNameLength; - uint32_t TicketBufferLength = - BufferLength - - sizeof(QUIC_SERIALIZED_RESUMPTION_STATE) - - State->ServerNameLength; - - QuicSessionServerCacheSetStateInternal( - Session, - State->ServerNameLength, - ServerName, - State->QuicVersion, - &State->TransportParameters, - NULL); - - Status = - QuicTlsSessionAddTicket( - Session->TlsSession, - TicketBufferLength, - TicketBuffer); - break; - } - - default: - Status = QUIC_STATUS_INVALID_PARAMETER; - break; - } - - return Status; -} diff --git a/src/core/session.h b/src/core/session.h deleted file mode 100644 index bb42aa9381..0000000000 --- a/src/core/session.h +++ /dev/null @@ -1,256 +0,0 @@ -/*++ - - Copyright (c) Microsoft Corporation. - Licensed under the MIT License. - ---*/ - -typedef struct QUIC_SERIALIZED_RESUMPTION_STATE { - - uint32_t QuicVersion; - QUIC_TRANSPORT_PARAMETERS TransportParameters; - uint16_t ServerNameLength; - uint8_t Buffer[0]; // ServerName and TLS Session/Ticket - -} QUIC_SERIALIZED_RESUMPTION_STATE; - -// -// Represents cached (in memory) state from previous connections to a server. -// -typedef struct QUIC_SERVER_CACHE { - - QUIC_HASHTABLE_ENTRY Entry; - - const char* ServerName; - - uint16_t ServerNameLength; - - uint32_t QuicVersion; - - QUIC_TRANSPORT_PARAMETERS TransportParameters; - - QUIC_SEC_CONFIG* SecConfig; - -} QUIC_SERVER_CACHE; - -// -// Represents a library session context. -// -typedef struct QUIC_SESSION { - - struct QUIC_HANDLE; - - // - // Parent registration. - // - QUIC_REGISTRATION* Registration; - - // - // Link in the parent registration's Sessions list. - // - QUIC_LIST_ENTRY Link; - - // - // Rundown for clean up. - // - QUIC_RUNDOWN_REF Rundown; - - // - // TLS Session Context. - // - QUIC_TLS_SESSION* TlsSession; - -#ifdef QUIC_SILO - // - // The silo. - // - QUIC_SILO Silo; -#endif - -#ifdef QUIC_COMPARTMENT_ID - // - // The network compartment ID. - // - QUIC_COMPARTMENT_ID CompartmentId; -#endif - - // - // Handle to persistent storage (registry). - // -#ifdef QUIC_SILO - QUIC_STORAGE* Storage; // Only necessary if it could be in a different silo. -#endif - QUIC_STORAGE* AppSpecificStorage; - - // - // Configurable (app & registry) settings. - // - QUIC_SETTINGS Settings; - - // - // Per server cached state information. - // - QUIC_HASHTABLE ServerCache; - QUIC_RW_LOCK ServerCacheLock; - - // - // List of all connections in the session. - // - QUIC_LIST_ENTRY Connections; - QUIC_DISPATCH_LOCK ConnectionsLock; - - // - // The application layer protocol negotiation buffers. Encoded in the TLS - // extension format. - // - uint16_t AlpnListLength; - _Field_size_(AlpnListLength) - uint8_t AlpnList[0]; - -} QUIC_SESSION; - -#ifdef QUIC_SILO - -#define QuicSessionAttachSilo(Session) \ - QUIC_SILO PrevSilo = (Session == NULL || Session->Silo == NULL) ? \ - QUIC_SILO_INVALID : QuicSiloAttach(Session->Silo) - -#define QuicSessionDetachSilo() \ - if (PrevSilo != QUIC_SILO_INVALID) {\ - QuicSiloDetatch(PrevSilo); \ - } - -#else - -#define QuicSessionAttachSilo(Session) -#define QuicSessionDetachSilo() - -#endif // #ifdef QUIC_SILO - -// -// Initializes an empty session object. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS -QuicSessionAlloc( - _In_opt_ QUIC_REGISTRATION* Registration, - _In_opt_ void* Context, - _When_(AlpnBufferCount > 0, _In_reads_(AlpnBufferCount)) - _When_(AlpnBufferCount == 0, _In_opt_) - const QUIC_BUFFER* const AlpnBuffers, - _In_ uint32_t AlpnBufferCount, - _Outptr_ _At_(*NewSession, __drv_allocatesMem(Mem)) - QUIC_SESSION** NewSession - ); - -// -// Returns TRUE if the two sessions have an overlapping ALPN. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -BOOLEAN -QuicSessionHasAlpnOverlap( - _In_ const QUIC_SESSION* Session1, - _In_ const QUIC_SESSION* Session2 - ); - -// -// Returns TRUE if the session has a matching ALPN. Also updates the new -// connection info with the matching ALPN. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -BOOLEAN -QuicSessionMatchesAlpn( - _In_ const QUIC_SESSION* Session, - _In_ QUIC_NEW_CONNECTION_INFO* Info - ); - -// -// Tracing rundown for the session. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicSessionTraceRundown( - _In_ QUIC_SESSION* Session - ); - -// -// Global or local settings were changed. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -_Function_class_(QUIC_STORAGE_CHANGE_CALLBACK) -void -QuicSessionSettingsChanged( - _Inout_ QUIC_SESSION* Session - ); - -// -// Registers the connection with the session. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicSessionRegisterConnection( - _Inout_ QUIC_SESSION* Session, - _Inout_ QUIC_CONNECTION* Connection - ); - -// -// Unregisters the connection with the session. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -void -QuicSessionUnregisterConnection( - _Inout_ QUIC_CONNECTION* Connection - ); - -// -// Gets a session parameter. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicSessionParamGet( - _In_ QUIC_SESSION* Session, - _In_ uint32_t Param, - _Inout_ uint32_t* BufferLength, - _Out_writes_bytes_opt_(*BufferLength) - void* Buffer - ); - -// -// Sets a session parameter. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicSessionParamSet( - _In_ QUIC_SESSION* Session, - _In_ uint32_t Param, - _In_ uint32_t BufferLength, - _In_reads_bytes_(BufferLength) - const void* Buffer - ); - -// -// Gets a previously cached server state. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -_Success_(return!=FALSE) -BOOLEAN -QuicSessionServerCacheGetState( - _In_ QUIC_SESSION* Session, - _In_z_ const char* ServerName, - _Out_ uint32_t* QuicVersion, - _Out_ QUIC_TRANSPORT_PARAMETERS* Parameters, - _Out_ QUIC_SEC_CONFIG** SecConfig - ); - -// -// Sets/updates cached server state. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicSessionServerCacheSetState( - _In_ QUIC_SESSION* Session, - _In_z_ const char* ServerName, - _In_ uint32_t QuicVersion, - _In_ const QUIC_TRANSPORT_PARAMETERS* Parameters, - _In_ QUIC_SEC_CONFIG* SecConfig - ); diff --git a/src/core/settings.c b/src/core/settings.c index 40b49e4765..b2a7cb01a4 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -20,6 +20,9 @@ QuicSettingsSetDefault( _Inout_ QUIC_SETTINGS* Settings ) { + if (!Settings->IsSet.SendBufferingEnabled) { + Settings->SendBufferingEnabled = QUIC_DEFAULT_SEND_BUFFERING_ENABLE; + } if (!Settings->IsSet.PacingEnabled) { Settings->PacingEnabled = QUIC_DEFAULT_SEND_PACING; } @@ -29,9 +32,6 @@ QuicSettingsSetDefault( if (!Settings->IsSet.DatagramReceiveEnabled) { Settings->DatagramReceiveEnabled = QUIC_DEFAULT_DATAGRAM_RECEIVE_ENABLED; } - if (!Settings->IsSet.MaxPartitionCount) { - Settings->MaxPartitionCount = QUIC_MAX_PARTITION_COUNT; - } if (!Settings->IsSet.MaxOperationsPerDrain) { Settings->MaxOperationsPerDrain = QUIC_MAX_OPERATIONS_PER_DRAIN; } @@ -103,229 +103,231 @@ QuicSettingsSetDefault( _IRQL_requires_max_(PASSIVE_LEVEL) void QuicSettingsCopy( - _Inout_ QUIC_SETTINGS* Settings, - _In_ const QUIC_SETTINGS* ParentSettings + _Inout_ QUIC_SETTINGS* Destination, + _In_ const QUIC_SETTINGS* Source ) { - if (!Settings->IsSet.PacingEnabled) { - Settings->PacingEnabled = ParentSettings->PacingEnabled; + if (!Destination->IsSet.SendBufferingEnabled) { + Destination->SendBufferingEnabled = Source->SendBufferingEnabled; } - if (!Settings->IsSet.MigrationEnabled) { - Settings->MigrationEnabled = ParentSettings->MigrationEnabled; + if (!Destination->IsSet.PacingEnabled) { + Destination->PacingEnabled = Source->PacingEnabled; } - if (!Settings->IsSet.DatagramReceiveEnabled) { - Settings->DatagramReceiveEnabled = ParentSettings->DatagramReceiveEnabled; + if (!Destination->IsSet.MigrationEnabled) { + Destination->MigrationEnabled = Source->MigrationEnabled; } - if (!Settings->IsSet.MaxPartitionCount) { - Settings->MaxPartitionCount = ParentSettings->MaxPartitionCount; + if (!Destination->IsSet.DatagramReceiveEnabled) { + Destination->DatagramReceiveEnabled = Source->DatagramReceiveEnabled; } - if (!Settings->IsSet.MaxOperationsPerDrain) { - Settings->MaxOperationsPerDrain = ParentSettings->MaxOperationsPerDrain; + if (!Destination->IsSet.MaxOperationsPerDrain) { + Destination->MaxOperationsPerDrain = Source->MaxOperationsPerDrain; } - if (!Settings->IsSet.RetryMemoryLimit) { - Settings->RetryMemoryLimit = ParentSettings->RetryMemoryLimit; + if (!Destination->IsSet.RetryMemoryLimit) { + Destination->RetryMemoryLimit = Source->RetryMemoryLimit; } - if (!Settings->IsSet.LoadBalancingMode) { - Settings->LoadBalancingMode = ParentSettings->LoadBalancingMode; + if (!Destination->IsSet.LoadBalancingMode) { + Destination->LoadBalancingMode = Source->LoadBalancingMode; } - if (!Settings->IsSet.MaxWorkerQueueDelayUs) { - Settings->MaxWorkerQueueDelayUs = ParentSettings->MaxWorkerQueueDelayUs; + if (!Destination->IsSet.MaxWorkerQueueDelayUs) { + Destination->MaxWorkerQueueDelayUs = Source->MaxWorkerQueueDelayUs; } - if (!Settings->IsSet.MaxStatelessOperations) { - Settings->MaxStatelessOperations = ParentSettings->MaxStatelessOperations; + if (!Destination->IsSet.MaxStatelessOperations) { + Destination->MaxStatelessOperations = Source->MaxStatelessOperations; } - if (!Settings->IsSet.InitialWindowPackets) { - Settings->InitialWindowPackets = ParentSettings->InitialWindowPackets; + if (!Destination->IsSet.InitialWindowPackets) { + Destination->InitialWindowPackets = Source->InitialWindowPackets; } - if (!Settings->IsSet.SendIdleTimeoutMs) { - Settings->SendIdleTimeoutMs = ParentSettings->SendIdleTimeoutMs; + if (!Destination->IsSet.SendIdleTimeoutMs) { + Destination->SendIdleTimeoutMs = Source->SendIdleTimeoutMs; } - if (!Settings->IsSet.InitialRttMs) { - Settings->InitialRttMs = ParentSettings->InitialRttMs; + if (!Destination->IsSet.InitialRttMs) { + Destination->InitialRttMs = Source->InitialRttMs; } - if (!Settings->IsSet.MaxAckDelayMs) { - Settings->MaxAckDelayMs = ParentSettings->MaxAckDelayMs; + if (!Destination->IsSet.MaxAckDelayMs) { + Destination->MaxAckDelayMs = Source->MaxAckDelayMs; } - if (!Settings->IsSet.DisconnectTimeoutMs) { - Settings->DisconnectTimeoutMs = ParentSettings->DisconnectTimeoutMs; + if (!Destination->IsSet.DisconnectTimeoutMs) { + Destination->DisconnectTimeoutMs = Source->DisconnectTimeoutMs; } - if (!Settings->IsSet.KeepAliveIntervalMs) { - Settings->KeepAliveIntervalMs = ParentSettings->KeepAliveIntervalMs; + if (!Destination->IsSet.KeepAliveIntervalMs) { + Destination->KeepAliveIntervalMs = Source->KeepAliveIntervalMs; } - if (!Settings->IsSet.IdleTimeoutMs) { - Settings->IdleTimeoutMs = ParentSettings->IdleTimeoutMs; + if (!Destination->IsSet.IdleTimeoutMs) { + Destination->IdleTimeoutMs = Source->IdleTimeoutMs; } - if (!Settings->IsSet.HandshakeIdleTimeoutMs) { - Settings->HandshakeIdleTimeoutMs = ParentSettings->HandshakeIdleTimeoutMs; + if (!Destination->IsSet.HandshakeIdleTimeoutMs) { + Destination->HandshakeIdleTimeoutMs = Source->HandshakeIdleTimeoutMs; } - if (!Settings->IsSet.PeerBidiStreamCount) { - Settings->PeerBidiStreamCount = ParentSettings->PeerBidiStreamCount; + if (!Destination->IsSet.PeerBidiStreamCount) { + Destination->PeerBidiStreamCount = Source->PeerBidiStreamCount; } - if (!Settings->IsSet.PeerUnidiStreamCount) { - Settings->PeerUnidiStreamCount = ParentSettings->PeerUnidiStreamCount; + if (!Destination->IsSet.PeerUnidiStreamCount) { + Destination->PeerUnidiStreamCount = Source->PeerUnidiStreamCount; } - if (!Settings->IsSet.TlsClientMaxSendBuffer) { - Settings->TlsClientMaxSendBuffer = ParentSettings->TlsClientMaxSendBuffer; + if (!Destination->IsSet.TlsClientMaxSendBuffer) { + Destination->TlsClientMaxSendBuffer = Source->TlsClientMaxSendBuffer; } - if (!Settings->IsSet.TlsClientMaxSendBuffer) { - Settings->TlsClientMaxSendBuffer = ParentSettings->TlsClientMaxSendBuffer; + if (!Destination->IsSet.TlsClientMaxSendBuffer) { + Destination->TlsClientMaxSendBuffer = Source->TlsClientMaxSendBuffer; } - if (!Settings->IsSet.StreamRecvWindowDefault) { - Settings->StreamRecvWindowDefault = ParentSettings->StreamRecvWindowDefault; + if (!Destination->IsSet.StreamRecvWindowDefault) { + Destination->StreamRecvWindowDefault = Source->StreamRecvWindowDefault; } - if (!Settings->IsSet.StreamRecvBufferDefault) { - Settings->StreamRecvBufferDefault = ParentSettings->StreamRecvBufferDefault; + if (!Destination->IsSet.StreamRecvBufferDefault) { + Destination->StreamRecvBufferDefault = Source->StreamRecvBufferDefault; } - if (!Settings->IsSet.ConnFlowControlWindow) { - Settings->ConnFlowControlWindow = ParentSettings->ConnFlowControlWindow; + if (!Destination->IsSet.ConnFlowControlWindow) { + Destination->ConnFlowControlWindow = Source->ConnFlowControlWindow; } - if (!Settings->IsSet.MaxBytesPerKey) { - Settings->MaxBytesPerKey = ParentSettings->MaxBytesPerKey; + if (!Destination->IsSet.MaxBytesPerKey) { + Destination->MaxBytesPerKey = Source->MaxBytesPerKey; } - if (!Settings->IsSet.ServerResumptionLevel) { - Settings->ServerResumptionLevel = ParentSettings->ServerResumptionLevel; + if (!Destination->IsSet.ServerResumptionLevel) { + Destination->ServerResumptionLevel = Source->ServerResumptionLevel; } } _IRQL_requires_max_(PASSIVE_LEVEL) BOOLEAN QuicSettingApply( - _Inout_ QUIC_SETTINGS* Settings, + _Inout_ QUIC_SETTINGS* Destination, + _In_ BOOLEAN OverWrite, _In_range_(FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey), UINT32_MAX) - uint32_t NewSessionSize, - _In_reads_bytes_(NewSessionSize) - const QUIC_SETTINGS* NewSettings + uint32_t NewSettingsSize, + _In_reads_bytes_(NewSettingsSize) + const QUIC_SETTINGS* Source ) { // TODO - Input validation - UNREFERENCED_PARAMETER(NewSessionSize); // TODO - Use to validate new settings - if (NewSettings->IsSet.PacingEnabled) { - Settings->PacingEnabled = NewSettings->PacingEnabled; - Settings->IsSet.PacingEnabled = TRUE; + UNREFERENCED_PARAMETER(NewSettingsSize); // TODO - Use to validate new settings + + if (Source->IsSet.SendBufferingEnabled && (!Destination->IsSet.SendBufferingEnabled || OverWrite)) { + Destination->SendBufferingEnabled = Source->SendBufferingEnabled; + Destination->IsSet.SendBufferingEnabled = TRUE; } - if (NewSettings->IsSet.MigrationEnabled) { - Settings->MigrationEnabled = NewSettings->MigrationEnabled; - Settings->IsSet.MigrationEnabled = TRUE; + if (Source->IsSet.PacingEnabled && (!Destination->IsSet.PacingEnabled || OverWrite)) { + Destination->PacingEnabled = Source->PacingEnabled; + Destination->IsSet.PacingEnabled = TRUE; } - if (NewSettings->IsSet.DatagramReceiveEnabled) { - Settings->DatagramReceiveEnabled = NewSettings->DatagramReceiveEnabled; - Settings->IsSet.DatagramReceiveEnabled = TRUE; + if (Source->IsSet.MigrationEnabled && (!Destination->IsSet.MigrationEnabled || OverWrite)) { + Destination->MigrationEnabled = Source->MigrationEnabled; + Destination->IsSet.MigrationEnabled = TRUE; } - if (NewSettings->IsSet.MaxPartitionCount) { - Settings->MaxPartitionCount = NewSettings->MaxPartitionCount; - Settings->IsSet.MaxPartitionCount = TRUE; + if (Source->IsSet.DatagramReceiveEnabled && (!Destination->IsSet.DatagramReceiveEnabled || OverWrite)) { + Destination->DatagramReceiveEnabled = Source->DatagramReceiveEnabled; + Destination->IsSet.DatagramReceiveEnabled = TRUE; } - if (NewSettings->IsSet.MaxOperationsPerDrain) { - Settings->MaxOperationsPerDrain = NewSettings->MaxOperationsPerDrain; - Settings->IsSet.MaxOperationsPerDrain = TRUE; + if (Source->IsSet.MaxOperationsPerDrain && (!Destination->IsSet.MaxOperationsPerDrain || OverWrite)) { + Destination->MaxOperationsPerDrain = Source->MaxOperationsPerDrain; + Destination->IsSet.MaxOperationsPerDrain = TRUE; } - if (NewSettings->IsSet.RetryMemoryLimit) { - Settings->RetryMemoryLimit = NewSettings->RetryMemoryLimit; - Settings->IsSet.RetryMemoryLimit = TRUE; + if (Source->IsSet.RetryMemoryLimit && (!Destination->IsSet.RetryMemoryLimit || OverWrite)) { + Destination->RetryMemoryLimit = Source->RetryMemoryLimit; + Destination->IsSet.RetryMemoryLimit = TRUE; } - if (NewSettings->IsSet.LoadBalancingMode) { - if (NewSettings->LoadBalancingMode > QUIC_LOAD_BALANCING_SERVER_ID_IP) { + if (Source->IsSet.LoadBalancingMode && (!Destination->IsSet.LoadBalancingMode || OverWrite)) { + if (Source->LoadBalancingMode > QUIC_LOAD_BALANCING_SERVER_ID_IP) { return FALSE; } - Settings->LoadBalancingMode = NewSettings->LoadBalancingMode; - Settings->IsSet.LoadBalancingMode = TRUE; + Destination->LoadBalancingMode = Source->LoadBalancingMode; + Destination->IsSet.LoadBalancingMode = TRUE; } - if (NewSettings->IsSet.MaxWorkerQueueDelayUs) { - Settings->MaxWorkerQueueDelayUs = NewSettings->MaxWorkerQueueDelayUs; - Settings->IsSet.MaxWorkerQueueDelayUs = TRUE; + if (Source->IsSet.MaxWorkerQueueDelayUs && (!Destination->IsSet.MaxWorkerQueueDelayUs || OverWrite)) { + Destination->MaxWorkerQueueDelayUs = Source->MaxWorkerQueueDelayUs; + Destination->IsSet.MaxWorkerQueueDelayUs = TRUE; } - if (NewSettings->IsSet.MaxStatelessOperations) { - Settings->MaxStatelessOperations = NewSettings->MaxStatelessOperations; - Settings->IsSet.MaxStatelessOperations = TRUE; + if (Source->IsSet.MaxStatelessOperations && (!Destination->IsSet.MaxStatelessOperations || OverWrite)) { + Destination->MaxStatelessOperations = Source->MaxStatelessOperations; + Destination->IsSet.MaxStatelessOperations = TRUE; } - if (NewSettings->IsSet.InitialWindowPackets) { - Settings->InitialWindowPackets = NewSettings->InitialWindowPackets; - Settings->IsSet.InitialWindowPackets = TRUE; + if (Source->IsSet.InitialWindowPackets && (!Destination->IsSet.InitialWindowPackets || OverWrite)) { + Destination->InitialWindowPackets = Source->InitialWindowPackets; + Destination->IsSet.InitialWindowPackets = TRUE; } - if (NewSettings->IsSet.SendIdleTimeoutMs) { - Settings->SendIdleTimeoutMs = NewSettings->SendIdleTimeoutMs; - Settings->IsSet.SendIdleTimeoutMs = TRUE; + if (Source->IsSet.SendIdleTimeoutMs && (!Destination->IsSet.SendIdleTimeoutMs || OverWrite)) { + Destination->SendIdleTimeoutMs = Source->SendIdleTimeoutMs; + Destination->IsSet.SendIdleTimeoutMs = TRUE; } - if (NewSettings->IsSet.InitialRttMs) { - Settings->InitialRttMs = NewSettings->InitialRttMs; - Settings->IsSet.InitialRttMs = TRUE; + if (Source->IsSet.InitialRttMs && (!Destination->IsSet.InitialRttMs || OverWrite)) { + Destination->InitialRttMs = Source->InitialRttMs; + Destination->IsSet.InitialRttMs = TRUE; } - if (NewSettings->IsSet.MaxAckDelayMs) { - if (NewSettings->MaxAckDelayMs > QUIC_TP_MAX_ACK_DELAY_MAX) { + if (Source->IsSet.MaxAckDelayMs && (!Destination->IsSet.MaxAckDelayMs || OverWrite)) { + if (Source->MaxAckDelayMs > QUIC_TP_MAX_ACK_DELAY_MAX) { return FALSE; } - Settings->MaxAckDelayMs = NewSettings->MaxAckDelayMs; - Settings->IsSet.MaxAckDelayMs = TRUE; + Destination->MaxAckDelayMs = Source->MaxAckDelayMs; + Destination->IsSet.MaxAckDelayMs = TRUE; } - if (NewSettings->IsSet.DisconnectTimeoutMs) { - if (NewSettings->DisconnectTimeoutMs > QUIC_MAX_DISCONNECT_TIMEOUT) { + if (Source->IsSet.DisconnectTimeoutMs && (!Destination->IsSet.DisconnectTimeoutMs || OverWrite)) { + if (Source->DisconnectTimeoutMs > QUIC_MAX_DISCONNECT_TIMEOUT) { return FALSE; } - Settings->DisconnectTimeoutMs = NewSettings->DisconnectTimeoutMs; - Settings->IsSet.DisconnectTimeoutMs = TRUE; + Destination->DisconnectTimeoutMs = Source->DisconnectTimeoutMs; + Destination->IsSet.DisconnectTimeoutMs = TRUE; } - if (NewSettings->IsSet.KeepAliveIntervalMs) { - Settings->KeepAliveIntervalMs = NewSettings->KeepAliveIntervalMs; - Settings->IsSet.KeepAliveIntervalMs = TRUE; + if (Source->IsSet.KeepAliveIntervalMs && (!Destination->IsSet.KeepAliveIntervalMs || OverWrite)) { + Destination->KeepAliveIntervalMs = Source->KeepAliveIntervalMs; + Destination->IsSet.KeepAliveIntervalMs = TRUE; } - if (NewSettings->IsSet.IdleTimeoutMs) { - if (NewSettings->IdleTimeoutMs > QUIC_VAR_INT_MAX) { + if (Source->IsSet.IdleTimeoutMs && (!Destination->IsSet.IdleTimeoutMs || OverWrite)) { + if (Source->IdleTimeoutMs > QUIC_VAR_INT_MAX) { return FALSE; } - Settings->IdleTimeoutMs = NewSettings->IdleTimeoutMs; - Settings->IsSet.IdleTimeoutMs = TRUE; + Destination->IdleTimeoutMs = Source->IdleTimeoutMs; + Destination->IsSet.IdleTimeoutMs = TRUE; } - if (NewSettings->IsSet.HandshakeIdleTimeoutMs) { - if (NewSettings->HandshakeIdleTimeoutMs > QUIC_VAR_INT_MAX) { + if (Source->IsSet.HandshakeIdleTimeoutMs && (!Destination->IsSet.HandshakeIdleTimeoutMs || OverWrite)) { + if (Source->HandshakeIdleTimeoutMs > QUIC_VAR_INT_MAX) { return FALSE; } - Settings->HandshakeIdleTimeoutMs = NewSettings->HandshakeIdleTimeoutMs; - Settings->IsSet.HandshakeIdleTimeoutMs = TRUE; + Destination->HandshakeIdleTimeoutMs = Source->HandshakeIdleTimeoutMs; + Destination->IsSet.HandshakeIdleTimeoutMs = TRUE; } - if (NewSettings->IsSet.PeerBidiStreamCount) { - Settings->PeerBidiStreamCount = NewSettings->PeerBidiStreamCount; - Settings->IsSet.PeerBidiStreamCount = TRUE; + if (Source->IsSet.PeerBidiStreamCount && (!Destination->IsSet.PeerBidiStreamCount || OverWrite)) { + Destination->PeerBidiStreamCount = Source->PeerBidiStreamCount; + Destination->IsSet.PeerBidiStreamCount = TRUE; } - if (NewSettings->IsSet.PeerUnidiStreamCount) { - Settings->PeerUnidiStreamCount = NewSettings->PeerUnidiStreamCount; - Settings->IsSet.PeerUnidiStreamCount = TRUE; + if (Source->IsSet.PeerUnidiStreamCount && (!Destination->IsSet.PeerUnidiStreamCount || OverWrite)) { + Destination->PeerUnidiStreamCount = Source->PeerUnidiStreamCount; + Destination->IsSet.PeerUnidiStreamCount = TRUE; } - if (NewSettings->IsSet.TlsClientMaxSendBuffer) { - Settings->TlsClientMaxSendBuffer = NewSettings->TlsClientMaxSendBuffer; - Settings->IsSet.TlsClientMaxSendBuffer = TRUE; + if (Source->IsSet.TlsClientMaxSendBuffer && (!Destination->IsSet.TlsClientMaxSendBuffer || OverWrite)) { + Destination->TlsClientMaxSendBuffer = Source->TlsClientMaxSendBuffer; + Destination->IsSet.TlsClientMaxSendBuffer = TRUE; } - if (NewSettings->IsSet.TlsClientMaxSendBuffer) { - Settings->TlsClientMaxSendBuffer = NewSettings->TlsClientMaxSendBuffer; - Settings->IsSet.TlsClientMaxSendBuffer = TRUE; + if (Source->IsSet.TlsClientMaxSendBuffer && (!Destination->IsSet.TlsClientMaxSendBuffer || OverWrite)) { + Destination->TlsClientMaxSendBuffer = Source->TlsClientMaxSendBuffer; + Destination->IsSet.TlsClientMaxSendBuffer = TRUE; } - if (NewSettings->IsSet.StreamRecvWindowDefault) { - Settings->StreamRecvWindowDefault = NewSettings->StreamRecvWindowDefault; - Settings->IsSet.StreamRecvWindowDefault = TRUE; + if (Source->IsSet.StreamRecvWindowDefault && (!Destination->IsSet.StreamRecvWindowDefault || OverWrite)) { + Destination->StreamRecvWindowDefault = Source->StreamRecvWindowDefault; + Destination->IsSet.StreamRecvWindowDefault = TRUE; } - if (NewSettings->IsSet.StreamRecvBufferDefault) { - if (NewSettings->StreamRecvBufferDefault < QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE) { + if (Source->IsSet.StreamRecvBufferDefault && (!Destination->IsSet.StreamRecvBufferDefault || OverWrite)) { + if (Source->StreamRecvBufferDefault < QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE) { return FALSE; } - Settings->StreamRecvBufferDefault = NewSettings->StreamRecvBufferDefault; - Settings->IsSet.StreamRecvBufferDefault = TRUE; + Destination->StreamRecvBufferDefault = Source->StreamRecvBufferDefault; + Destination->IsSet.StreamRecvBufferDefault = TRUE; } - if (NewSettings->IsSet.ConnFlowControlWindow) { - Settings->ConnFlowControlWindow = NewSettings->ConnFlowControlWindow; - Settings->IsSet.ConnFlowControlWindow = TRUE; + if (Source->IsSet.ConnFlowControlWindow && (!Destination->IsSet.ConnFlowControlWindow || OverWrite)) { + Destination->ConnFlowControlWindow = Source->ConnFlowControlWindow; + Destination->IsSet.ConnFlowControlWindow = TRUE; } - if (NewSettings->IsSet.MaxBytesPerKey) { - if (NewSettings->MaxBytesPerKey > QUIC_DEFAULT_MAX_BYTES_PER_KEY) { + if (Source->IsSet.MaxBytesPerKey && (!Destination->IsSet.MaxBytesPerKey || OverWrite)) { + if (Source->MaxBytesPerKey > QUIC_DEFAULT_MAX_BYTES_PER_KEY) { return FALSE; } - Settings->MaxBytesPerKey = NewSettings->MaxBytesPerKey; - Settings->IsSet.MaxBytesPerKey = TRUE; + Destination->MaxBytesPerKey = Source->MaxBytesPerKey; + Destination->IsSet.MaxBytesPerKey = TRUE; } - if (NewSettings->IsSet.ServerResumptionLevel) { - if (NewSettings->ServerResumptionLevel > QUIC_SERVER_RESUME_AND_ZERORTT) { + if (Source->IsSet.ServerResumptionLevel && (!Destination->IsSet.ServerResumptionLevel || OverWrite)) { + if (Source->ServerResumptionLevel > QUIC_SERVER_RESUME_AND_ZERORTT) { return FALSE; } - Settings->ServerResumptionLevel = NewSettings->ServerResumptionLevel; - Settings->IsSet.ServerResumptionLevel = TRUE; + Destination->ServerResumptionLevel = Source->ServerResumptionLevel; + Destination->IsSet.ServerResumptionLevel = TRUE; } return TRUE; } @@ -345,6 +347,17 @@ QuicSettingsLoad( } MultiValue; uint32_t ValueLen; + if (!Settings->IsSet.SendBufferingEnabled) { + Value = QUIC_DEFAULT_SEND_BUFFERING_ENABLE; + ValueLen = sizeof(Value); + QuicStorageReadValue( + Storage, + QUIC_SETTING_SEND_BUFFERING_DEFAULT, + (uint8_t*)&Value, + &ValueLen); + Settings->SendBufferingEnabled = !!Value; + } + if (!Settings->IsSet.PacingEnabled) { Value = QUIC_DEFAULT_SEND_PACING; ValueLen = sizeof(Value); @@ -378,19 +391,6 @@ QuicSettingsLoad( Settings->DatagramReceiveEnabled = !!Value; } - if (!Settings->IsSet.MaxPartitionCount) { - Value = QUIC_MAX_PARTITION_COUNT; - ValueLen = sizeof(Value); - QuicStorageReadValue( - Storage, - QUIC_SETTING_MAX_PARTITION_COUNT, - (uint8_t*)&Value, - &ValueLen); - if (Value <= UINT8_MAX) { - Settings->MaxPartitionCount = (uint8_t)Value; - } - } - if (!Settings->IsSet.MaxOperationsPerDrain) { Value = QUIC_MAX_OPERATIONS_PER_DRAIN; ValueLen = sizeof(Value); @@ -632,10 +632,10 @@ QuicSettingsDump( _In_ const QUIC_SETTINGS* Settings ) { - QuicTraceLogVerbose(SettingDumpPacingDefault, "[sett] PacingEnabled = %hhu", Settings->PacingEnabled); + QuicTraceLogVerbose(SettingDumpSendBufferingEnabled, "[sett] SendBufferingEnabled = %hhu", Settings->SendBufferingEnabled); + QuicTraceLogVerbose(SettingDumpPacingEnabled, "[sett] PacingEnabled = %hhu", Settings->PacingEnabled); QuicTraceLogVerbose(SettingDumpMigrationEnabled, "[sett] MigrationEnabled = %hhu", Settings->MigrationEnabled); QuicTraceLogVerbose(SettingDumpDatagramReceiveEnabled, "[sett] DatagramReceiveEnabled = %hhu", Settings->DatagramReceiveEnabled); - QuicTraceLogVerbose(SettingDumpMaxPartitionCount, "[sett] MaxPartitionCount = %hhu", Settings->MaxPartitionCount); QuicTraceLogVerbose(SettingDumpMaxOperationsPerDrain, "[sett] MaxOperationsPerDrain = %hhu", Settings->MaxOperationsPerDrain); QuicTraceLogVerbose(SettingDumpRetryMemoryLimit, "[sett] RetryMemoryLimit = %hu", Settings->RetryMemoryLimit); QuicTraceLogVerbose(SettingDumpLoadBalancingMode, "[sett] LoadBalancingMode = %hu", Settings->LoadBalancingMode); @@ -659,3 +659,94 @@ QuicSettingsDump( QuicTraceLogVerbose(SettingDumpMaxBytesPerKey, "[sett] MaxBytesPerKey = %llu", Settings->MaxBytesPerKey); QuicTraceLogVerbose(SettingDumpServerResumptionLevel, "[sett] ServerResumptionLevel = %hhu", Settings->ServerResumptionLevel); } + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicSettingsDumpNew( + _In_range_(FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey), UINT32_MAX) + uint32_t SettingsSize, + _In_reads_bytes_(SettingsSize) + const QUIC_SETTINGS* Settings + ) +{ + UNREFERENCED_PARAMETER(SettingsSize); // TODO - Use when reading settings + + if (Settings->IsSet.SendBufferingEnabled) { + QuicTraceLogVerbose(SettingDumpSendBufferingEnabled, "[sett] SendBufferingEnabled = %hhu", Settings->SendBufferingEnabled); + } + if (Settings->IsSet.PacingEnabled) { + QuicTraceLogVerbose(SettingDumpPacingEnabled, "[sett] PacingEnabled = %hhu", Settings->PacingEnabled); + } + if (Settings->IsSet.MigrationEnabled) { + QuicTraceLogVerbose(SettingDumpMigrationEnabled, "[sett] MigrationEnabled = %hhu", Settings->MigrationEnabled); + } + if (Settings->IsSet.DatagramReceiveEnabled) { + QuicTraceLogVerbose(SettingDumpDatagramReceiveEnabled, "[sett] DatagramReceiveEnabled = %hhu", Settings->DatagramReceiveEnabled); + } + if (Settings->IsSet.MaxOperationsPerDrain) { + QuicTraceLogVerbose(SettingDumpMaxOperationsPerDrain, "[sett] MaxOperationsPerDrain = %hhu", Settings->MaxOperationsPerDrain); + } + if (Settings->IsSet.RetryMemoryLimit) { + QuicTraceLogVerbose(SettingDumpRetryMemoryLimit, "[sett] RetryMemoryLimit = %hu", Settings->RetryMemoryLimit); + } + if (Settings->IsSet.LoadBalancingMode) { + QuicTraceLogVerbose(SettingDumpLoadBalancingMode, "[sett] LoadBalancingMode = %hu", Settings->LoadBalancingMode); + } + if (Settings->IsSet.MaxStatelessOperations) { + QuicTraceLogVerbose(SettingDumpMaxStatelessOperations, "[sett] MaxStatelessOperations = %u", Settings->MaxStatelessOperations); + } + if (Settings->IsSet.MaxWorkerQueueDelayUs) { + QuicTraceLogVerbose(SettingDumpMaxWorkerQueueDelayUs, "[sett] MaxWorkerQueueDelayUs = %u", Settings->MaxWorkerQueueDelayUs); + } + if (Settings->IsSet.InitialWindowPackets) { + QuicTraceLogVerbose(SettingDumpInitialWindowPackets, "[sett] InitialWindowPackets = %u", Settings->InitialWindowPackets); + } + if (Settings->IsSet.SendIdleTimeoutMs) { + QuicTraceLogVerbose(SettingDumpSendIdleTimeoutMs, "[sett] SendIdleTimeoutMs = %u", Settings->SendIdleTimeoutMs); + } + if (Settings->IsSet.InitialRttMs) { + QuicTraceLogVerbose(SettingDumpInitialRttMs, "[sett] InitialRttMs = %u", Settings->InitialRttMs); + } + if (Settings->IsSet.MaxAckDelayMs) { + QuicTraceLogVerbose(SettingDumpMaxAckDelayMs, "[sett] MaxAckDelayMs = %u", Settings->MaxAckDelayMs); + } + if (Settings->IsSet.DisconnectTimeoutMs) { + QuicTraceLogVerbose(SettingDumpDisconnectTimeoutMs, "[sett] DisconnectTimeoutMs = %u", Settings->DisconnectTimeoutMs); + } + if (Settings->IsSet.KeepAliveIntervalMs) { + QuicTraceLogVerbose(SettingDumpKeepAliveIntervalMs, "[sett] KeepAliveIntervalMs = %u", Settings->KeepAliveIntervalMs); + } + if (Settings->IsSet.IdleTimeoutMs) { + QuicTraceLogVerbose(SettingDumpIdleTimeoutMs, "[sett] IdleTimeoutMs = %llu", Settings->IdleTimeoutMs); + } + if (Settings->IsSet.HandshakeIdleTimeoutMs) { + QuicTraceLogVerbose(SettingDumpHandshakeIdleTimeoutMs, "[sett] HandshakeIdleTimeoutMs = %llu", Settings->HandshakeIdleTimeoutMs); + } + if (Settings->IsSet.PeerBidiStreamCount) { + QuicTraceLogVerbose(SettingDumpBidiStreamCount, "[sett] PeerBidiStreamCount = %hu", Settings->PeerBidiStreamCount); + } + if (Settings->IsSet.PeerUnidiStreamCount) { + QuicTraceLogVerbose(SettingDumpUnidiStreamCount, "[sett] PeerUnidiStreamCount = %hu", Settings->PeerUnidiStreamCount); + } + if (Settings->IsSet.TlsClientMaxSendBuffer) { + QuicTraceLogVerbose(SettingDumpTlsClientMaxSendBuffer, "[sett] TlsClientMaxSendBuffer = %u", Settings->TlsClientMaxSendBuffer); + } + if (Settings->IsSet.TlsServerMaxSendBuffer) { + QuicTraceLogVerbose(SettingDumpTlsServerMaxSendBuffer, "[sett] TlsServerMaxSendBuffer = %u", Settings->TlsServerMaxSendBuffer); + } + if (Settings->IsSet.StreamRecvWindowDefault) { + QuicTraceLogVerbose(SettingDumpStreamRecvWindowDefault, "[sett] StreamRecvWindowDefault= %u", Settings->StreamRecvWindowDefault); + } + if (Settings->IsSet.StreamRecvBufferDefault) { + QuicTraceLogVerbose(SettingDumpStreamRecvBufferDefault, "[sett] StreamRecvBufferDefault= %u", Settings->StreamRecvBufferDefault); + } + if (Settings->IsSet.ConnFlowControlWindow) { + QuicTraceLogVerbose(SettingDumpConnFlowControlWindow, "[sett] ConnFlowControlWindow = %u", Settings->ConnFlowControlWindow); + } + if (Settings->IsSet.MaxBytesPerKey) { + QuicTraceLogVerbose(SettingDumpMaxBytesPerKey, "[sett] MaxBytesPerKey = %llu", Settings->MaxBytesPerKey); + } + if (Settings->IsSet.ServerResumptionLevel) { + QuicTraceLogVerbose(SettingDumpServerResumptionLevel, "[sett] ServerResumptionLevel = %hhu", Settings->ServerResumptionLevel); + } +} diff --git a/src/core/settings.h b/src/core/settings.h index de4c768d7d..b4714e5b9f 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -20,8 +20,8 @@ QuicSettingsSetDefault( _IRQL_requires_max_(PASSIVE_LEVEL) void QuicSettingsCopy( - _Inout_ QUIC_SETTINGS* Settings, - _In_ const QUIC_SETTINGS* ParentSettings + _Inout_ QUIC_SETTINGS* Destination, + _In_ const QUIC_SETTINGS* Source ); // @@ -30,11 +30,12 @@ QuicSettingsCopy( _IRQL_requires_max_(PASSIVE_LEVEL) BOOLEAN QuicSettingApply( - _Inout_ QUIC_SETTINGS* Settings, + _Inout_ QUIC_SETTINGS* Destination, + _In_ BOOLEAN OverWrite, _In_range_(FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey), UINT32_MAX) - uint32_t NewSessionSize, - _In_reads_bytes_(NewSessionSize) - const QUIC_SETTINGS* NewSettings + uint32_t SourceSize, + _In_reads_bytes_(SourceSize) + const QUIC_SETTINGS* Source ); // @@ -55,3 +56,12 @@ void QuicSettingsDump( _In_ const QUIC_SETTINGS* Settings ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicSettingsDumpNew( + _In_range_(FIELD_OFFSET(QUIC_SETTINGS, MaxBytesPerKey), UINT32_MAX) + uint32_t SettingsSize, + _In_reads_bytes_(SettingsSize) + const QUIC_SETTINGS* Settings + ); diff --git a/src/core/stream.c b/src/core/stream.c index 3d5aed5385..470232409d 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -85,7 +85,7 @@ QuicStreamInitialize( } } - InitialRecvBufferLength = Connection->Session->Settings.StreamRecvBufferDefault; + InitialRecvBufferLength = Connection->Settings.StreamRecvBufferDefault; if (InitialRecvBufferLength == QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE) { PreallocatedRecvBuffer = QuicPoolAlloc(&Worker->DefaultReceiveBufferPool); if (PreallocatedRecvBuffer == NULL) { @@ -98,7 +98,7 @@ QuicStreamInitialize( QuicRecvBufferInitialize( &Stream->RecvBuffer, InitialRecvBufferLength, - Connection->Session->Settings.StreamRecvWindowDefault, + Connection->Settings.StreamRecvWindowDefault, FALSE, PreallocatedRecvBuffer); if (QUIC_FAILED(Status)) { diff --git a/src/core/stream_recv.c b/src/core/stream_recv.c index 7f5c0d6d95..8f0268eeaf 100644 --- a/src/core/stream_recv.c +++ b/src/core/stream_recv.c @@ -584,7 +584,7 @@ QuicStreamOnBytesDelivered( // Limit stream FC window growth by the connection FC window size. // if (Stream->RecvBuffer.VirtualBufferLength < - Stream->Connection->Session->Settings.ConnFlowControlWindow) { + Stream->Connection->Settings.ConnFlowControlWindow) { uint32_t TimeThreshold = (uint32_t) ((Stream->RecvWindowBytesDelivered * Stream->Connection->Paths[0].MinRtt) / RecvBufferDrainThreshold); diff --git a/src/core/stream_send.c b/src/core/stream_send.c index 0ba33686cd..8658a14f4b 100644 --- a/src/core/stream_send.c +++ b/src/core/stream_send.c @@ -406,7 +406,7 @@ QuicStreamCompleteSendRequest( QUIC_DBG_ASSERT(Connection->SendBuffer.PostedBytes >= SendRequest->TotalLength); Connection->SendBuffer.PostedBytes -= SendRequest->TotalLength; - if (Connection->State.UseSendBuffer) { + if (Connection->Settings.SendBufferingEnabled) { QuicSendBufferFill(Connection); } } @@ -577,7 +577,7 @@ QuicStreamSendFlush( Stream, QUIC_STREAM_SEND_FLAG_DATA); - if (Stream->Connection->State.UseSendBuffer) { + if (Stream->Connection->Settings.SendBufferingEnabled) { QuicSendBufferFill(Stream->Connection); } diff --git a/src/core/transport_params.h b/src/core/transport_params.h index 187973d442..3972b8d9bb 100644 --- a/src/core/transport_params.h +++ b/src/core/transport_params.h @@ -174,8 +174,10 @@ _IRQL_requires_max_(DISPATCH_LEVEL) _Success_(return != NULL) const uint8_t* QuicCryptoTlsEncodeTransportParameters( - _In_ QUIC_CONNECTION* Connection, + _In_opt_ QUIC_CONNECTION* Connection, + _In_ BOOLEAN IsServerTP, _In_ const QUIC_TRANSPORT_PARAMETERS *TransportParams, + _In_opt_ const QUIC_PRIVATE_TRANSPORT_PARAMETER* TestParam, _Out_ uint32_t* TPLen ); @@ -186,7 +188,8 @@ _IRQL_requires_max_(DISPATCH_LEVEL) _Success_(return != FALSE) BOOLEAN QuicCryptoTlsDecodeTransportParameters( - _In_ QUIC_CONNECTION* Connection, + _In_opt_ QUIC_CONNECTION* Connection, + _In_ BOOLEAN IsServerTP, _In_reads_(TPLen) const uint8_t* TPBuf, _In_ uint16_t TPLen, diff --git a/src/core/unittest/CMakeLists.txt b/src/core/unittest/CMakeLists.txt index ee237c17d7..1fffc80116 100644 --- a/src/core/unittest/CMakeLists.txt +++ b/src/core/unittest/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES PartitionTest.cpp RangeTest.cpp SpinFrame.cpp + TicketTest.cpp TransportParamTest.cpp VarIntTest.cpp ) diff --git a/src/core/unittest/TicketTest.cpp b/src/core/unittest/TicketTest.cpp new file mode 100644 index 0000000000..2c11441193 --- /dev/null +++ b/src/core/unittest/TicketTest.cpp @@ -0,0 +1,307 @@ +/*++ + + Copyright (c) Microsoft Corporation. + Licensed under the MIT License. + +Abstract: + + Test the resumption ticket encoding and decoding logic. + +--*/ + +#include "main.h" +#ifdef QUIC_CLOG +#include "TicketTest.cpp.clog.h" +#endif + +void +CompareTransportParameters( + const QUIC_TRANSPORT_PARAMETERS* A, + const QUIC_TRANSPORT_PARAMETERS* B + ) +{ + ASSERT_EQ(A->Flags, B->Flags); + COMPARE_TP_FIELD(INITIAL_MAX_DATA, InitialMaxData); + COMPARE_TP_FIELD(INITIAL_MAX_STRM_DATA_BIDI_LOCAL, InitialMaxStreamDataBidiLocal); + COMPARE_TP_FIELD(INITIAL_MAX_STRM_DATA_BIDI_REMOTE, InitialMaxStreamDataBidiRemote); + COMPARE_TP_FIELD(INITIAL_MAX_STRM_DATA_UNI, InitialMaxStreamDataUni); + COMPARE_TP_FIELD(INITIAL_MAX_STRMS_BIDI, InitialMaxBidiStreams); + COMPARE_TP_FIELD(INITIAL_MAX_STRMS_UNI, InitialMaxUniStreams); + COMPARE_TP_FIELD(ACTIVE_CONNECTION_ID_LIMIT, ActiveConnectionIdLimit); +} + +TEST(ResumptionTicketTest, ClientEncDec) +{ + // + // Original parameters + // + uint8_t ServerTicket[] = {0, 1, 2, 3, 4, 5}; + QUIC_TRANSPORT_PARAMETERS ClientTP; + const uint8_t* EncodedClientTicket = nullptr; + uint32_t EncodedClientTicketLength = 0; + + // + // Parameters to compare against + // + QUIC_TRANSPORT_PARAMETERS DecodedTP; + uint8_t* DecodedServerTicket = nullptr; + uint32_t DecodedServerTicketLength = 0; + uint32_t DecodedQuicVersion = 0; + + QuicZeroMemory(&DecodedTP, sizeof(DecodedTP)); + QuicZeroMemory(&ClientTP, sizeof(ClientTP)); + ClientTP.Flags = + QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | + QUIC_TP_FLAG_INITIAL_MAX_DATA | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_LOCAL | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI; + ClientTP.ActiveConnectionIdLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN; + + TEST_QUIC_SUCCEEDED( + QuicCryptoEncodeClientTicket( + nullptr, + sizeof(ServerTicket), + ServerTicket, + &ClientTP, + QUIC_VERSION_LATEST, + &EncodedClientTicket, + &EncodedClientTicketLength)); + + ASSERT_NE(EncodedClientTicket, nullptr); + ASSERT_NE(EncodedClientTicketLength, 0); + + TEST_QUIC_SUCCEEDED( + QuicCryptoDecodeClientTicket( + nullptr, + (uint16_t)EncodedClientTicketLength, + EncodedClientTicket, + &DecodedTP, + &DecodedServerTicket, + &DecodedServerTicketLength, + &DecodedQuicVersion)); + + ASSERT_EQ(QUIC_VERSION_LATEST, DecodedQuicVersion); + ASSERT_EQ(DecodedServerTicketLength, sizeof(ServerTicket)); + ASSERT_NE(DecodedServerTicket, nullptr); + ASSERT_TRUE(memcmp(DecodedServerTicket, ServerTicket, sizeof(ServerTicket)) == 0); + CompareTransportParameters(&ClientTP, &DecodedTP); + + QUIC_FREE(EncodedClientTicket); + QUIC_FREE(DecodedServerTicket); +} + +TEST(ResumptionTicketTest, ServerEncDec) +{ + uint8_t AppData[] = {10, 9, 8, 7, 6}; + QUIC_TRANSPORT_PARAMETERS ServerTP; + uint8_t NegotiatedAlpn[] = {4, 't', 'e', 's', 't'}; + uint8_t* EncodedServerTicket = nullptr; + uint32_t EncodedServerTicketLength = 0; + + + QUIC_TRANSPORT_PARAMETERS DecodedTP; + const uint8_t* DecodedAppData = nullptr; + uint32_t DecodedAppDataLength = 0; + + QuicZeroMemory(&ServerTP, sizeof(ServerTP)); + QuicZeroMemory(&DecodedTP, sizeof(DecodedTP)); + ServerTP.Flags = + QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | + QUIC_TP_FLAG_INITIAL_MAX_DATA | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_LOCAL | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI; + ServerTP.ActiveConnectionIdLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN; + + TEST_QUIC_SUCCEEDED( + QuicCryptoEncodeServerTicket( + nullptr, + QUIC_VERSION_LATEST, + sizeof(AppData), + AppData, + &ServerTP, + NegotiatedAlpn[0], + NegotiatedAlpn + 1, + &EncodedServerTicket, + &EncodedServerTicketLength)); + + ASSERT_NE(EncodedServerTicket, nullptr); + ASSERT_NE(EncodedServerTicketLength, 0); + + TEST_QUIC_SUCCEEDED( + QuicCryptoDecodeServerTicket( + nullptr, + EncodedServerTicketLength, + EncodedServerTicket, + NegotiatedAlpn, + sizeof(NegotiatedAlpn), + &DecodedTP, + &DecodedAppData, + &DecodedAppDataLength)); + + ASSERT_EQ(DecodedAppDataLength, sizeof(AppData)); + ASSERT_NE(DecodedAppData, nullptr); + ASSERT_TRUE(memcmp(AppData, DecodedAppData, sizeof(AppData)) == 0); + CompareTransportParameters(&ServerTP, &DecodedTP); + + QUIC_FREE(EncodedServerTicket); +} + +TEST(ResumptionTicketTest, ServerEncDecNoAppData) +{ + QUIC_TRANSPORT_PARAMETERS ServerTP; + uint8_t NegotiatedAlpn[] = {4, 't', 'e', 's', 't'}; + uint8_t* EncodedServerTicket = nullptr; + uint32_t EncodedServerTicketLength = 0; + + QUIC_TRANSPORT_PARAMETERS DecodedServerTP; + const uint8_t* DecodedAppData = nullptr; + uint32_t DecodedAppDataLength = 0; + + QuicZeroMemory(&ServerTP, sizeof(ServerTP)); + QuicZeroMemory(&DecodedServerTP, sizeof(DecodedServerTP)); + ServerTP.Flags = + QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | + QUIC_TP_FLAG_INITIAL_MAX_DATA | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_LOCAL | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI; + ServerTP.ActiveConnectionIdLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN; + + TEST_QUIC_SUCCEEDED( + QuicCryptoEncodeServerTicket( + nullptr, + QUIC_VERSION_LATEST, + 0, + nullptr, + &ServerTP, + NegotiatedAlpn[0], + NegotiatedAlpn + 1, + &EncodedServerTicket, + &EncodedServerTicketLength)); + + ASSERT_NE(EncodedServerTicket, nullptr); + ASSERT_NE(EncodedServerTicketLength, 0); + + TEST_QUIC_SUCCEEDED( + QuicCryptoDecodeServerTicket( + nullptr, + EncodedServerTicketLength, + EncodedServerTicket, + NegotiatedAlpn, + sizeof(NegotiatedAlpn), + &DecodedServerTP, + &DecodedAppData, + &DecodedAppDataLength)); + + ASSERT_EQ(DecodedAppDataLength, 0); + ASSERT_EQ(DecodedAppData, nullptr); + CompareTransportParameters(&ServerTP, &DecodedServerTP); + + QUIC_FREE(EncodedServerTicket); +} + +TEST(ResumptionTicketTest, ClientServerEndToEnd) +{ + uint8_t AppData[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + QUIC_TRANSPORT_PARAMETERS ServerTP, ClientTP, DecodedClientTP, DecodedServerTP; + uint8_t NegotiatedAlpn[] = {4, 't', 'e', 's', 't'}; + uint8_t* EncodedServerTicket = nullptr, *DecodedServerTicket = nullptr; + uint32_t EncodedServerTicketLength = 0, EncodedClientTicketLength = 0, DecodedServerTicketLength = 0, DecodedAppDataLength = 0, DecodedQuicVersion = 0; + const uint8_t* EncodedClientTicket = nullptr, *DecodedAppData = nullptr; + + QuicZeroMemory(&ServerTP, sizeof(ServerTP)); + QuicZeroMemory(&DecodedServerTP, sizeof(DecodedServerTP)); + ServerTP.Flags = + QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | + QUIC_TP_FLAG_INITIAL_MAX_DATA | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_LOCAL | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI; + ServerTP.ActiveConnectionIdLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN; + + QuicZeroMemory(&DecodedClientTP, sizeof(DecodedClientTP)); + QuicZeroMemory(&ClientTP, sizeof(ClientTP)); + ClientTP.Flags = + QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | + QUIC_TP_FLAG_INITIAL_MAX_DATA | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_LOCAL | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI; + ClientTP.ActiveConnectionIdLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN; + + TEST_QUIC_SUCCEEDED( + QuicCryptoEncodeServerTicket( + nullptr, + QUIC_VERSION_LATEST, + sizeof(AppData), + AppData, + &ServerTP, + NegotiatedAlpn[0], + NegotiatedAlpn + 1, + &EncodedServerTicket, + &EncodedServerTicketLength)); + + ASSERT_NE(EncodedServerTicket, nullptr); + ASSERT_NE(EncodedServerTicketLength, 0); + + TEST_QUIC_SUCCEEDED( + QuicCryptoEncodeClientTicket( + nullptr, + EncodedServerTicketLength, + EncodedServerTicket, + &ClientTP, + QUIC_VERSION_LATEST, + &EncodedClientTicket, + &EncodedClientTicketLength)); + + ASSERT_NE(EncodedClientTicket, nullptr); + ASSERT_NE(EncodedClientTicketLength, 0); + + TEST_QUIC_SUCCEEDED( + QuicCryptoDecodeClientTicket( + nullptr, + (uint16_t)EncodedClientTicketLength, + EncodedClientTicket, + &DecodedClientTP, + &DecodedServerTicket, + &DecodedServerTicketLength, + &DecodedQuicVersion)); + + ASSERT_EQ(QUIC_VERSION_LATEST, DecodedQuicVersion); + ASSERT_EQ(DecodedServerTicketLength, EncodedServerTicketLength); + ASSERT_NE(DecodedServerTicket, nullptr); + ASSERT_TRUE(memcmp(DecodedServerTicket, EncodedServerTicket, DecodedServerTicketLength) == 0); + CompareTransportParameters(&ClientTP, &DecodedClientTP); + + TEST_QUIC_SUCCEEDED( + QuicCryptoDecodeServerTicket( + nullptr, + EncodedServerTicketLength, + EncodedServerTicket, + NegotiatedAlpn, + sizeof(NegotiatedAlpn), + &DecodedServerTP, + &DecodedAppData, + &DecodedAppDataLength)); + + ASSERT_EQ(DecodedAppDataLength, sizeof(AppData)); + ASSERT_NE(DecodedAppData, nullptr); + ASSERT_TRUE(memcmp(AppData, DecodedAppData, sizeof(AppData)) == 0); + CompareTransportParameters(&ServerTP, &DecodedServerTP); + + QUIC_FREE(EncodedClientTicket); + QUIC_FREE(EncodedServerTicket); + QUIC_FREE(DecodedServerTicket); +} diff --git a/src/core/unittest/TransportParamTest.cpp b/src/core/unittest/TransportParamTest.cpp index 0d697ef09e..1badf5e1ff 100644 --- a/src/core/unittest/TransportParamTest.cpp +++ b/src/core/unittest/TransportParamTest.cpp @@ -22,9 +22,6 @@ void CompareTransportParams( _In_ bool IsServer = false ) { -#define COMPARE_TP_FIELD(TpName, Field) \ - if (A->Flags & QUIC_TP_FLAG_##TpName) { ASSERT_EQ(A->Field, B->Field); } - ASSERT_EQ(A->Flags, B->Flags); COMPARE_TP_FIELD(INITIAL_MAX_DATA, InitialMaxData); COMPARE_TP_FIELD(INITIAL_MAX_STRM_DATA_BIDI_LOCAL, InitialMaxStreamDataBidiLocal); @@ -57,7 +54,7 @@ void EncodeDecodeAndCompare( uint32_t BufferLength; auto Buffer = QuicCryptoTlsEncodeTransportParameters( - &JunkConnection, Original, &BufferLength); + &JunkConnection, IsServer, Original, NULL, &BufferLength); ASSERT_NE(nullptr, Buffer); ASSERT_TRUE(UINT16_MAX >= (BufferLength - QuicTlsTPHeaderSize)); @@ -68,7 +65,7 @@ void EncodeDecodeAndCompare( QUIC_TRANSPORT_PARAMETERS Decoded; BOOLEAN DecodedSuccessfully = QuicCryptoTlsDecodeTransportParameters( - &JunkConnection, TPBuffer, TPBufferLength, &Decoded); + &JunkConnection, IsServer, TPBuffer, TPBufferLength, &Decoded); QUIC_FREE(Buffer); @@ -99,3 +96,20 @@ TEST(TransportParamTest, Preset1) Original.IdleTimeout = 100000; EncodeDecodeAndCompare(&Original); } + +TEST(TransportParamTest, ZeroTP) +{ + QUIC_TRANSPORT_PARAMETERS OriginalTP; + QuicZeroMemory(&OriginalTP, sizeof(OriginalTP)); + OriginalTP.Flags = + QUIC_TP_FLAG_ACTIVE_CONNECTION_ID_LIMIT | + QUIC_TP_FLAG_INITIAL_MAX_DATA | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_LOCAL | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_BIDI_REMOTE | + QUIC_TP_FLAG_INITIAL_MAX_STRM_DATA_UNI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_BIDI | + QUIC_TP_FLAG_INITIAL_MAX_STRMS_UNI; + OriginalTP.ActiveConnectionIdLimit = QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT_MIN; + + EncodeDecodeAndCompare(&OriginalTP); +} diff --git a/src/core/unittest/main.h b/src/core/unittest/main.h index 290c93fff7..5dd71cae61 100644 --- a/src/core/unittest/main.h +++ b/src/core/unittest/main.h @@ -15,6 +15,9 @@ #define TEST_QUIC_SUCCEEDED(__condition) ASSERT_FALSE(QUIC_FAILED(__condition)) +#define COMPARE_TP_FIELD(TpName, Field) \ + if (A->Flags & QUIC_TP_FLAG_##TpName) { ASSERT_EQ(A->Field, B->Field); } + inline std::ostream& operator << (std::ostream& o, const QUIC_FRAME_TYPE& type) { switch (type) { diff --git a/src/core/worker.c b/src/core/worker.c index 19eb8dec47..506fc73e12 100644 --- a/src/core/worker.c +++ b/src/core/worker.c @@ -418,9 +418,9 @@ QuicWorkerProcessTimers( QUIC_CONTAINING_RECORD(Entry, QUIC_CONNECTION, TimerLink); Connection->WorkerThreadID = Worker->ThreadID; - QuicSessionAttachSilo(Connection->Session); + QuicConfigurationAttachSilo(Connection->Configuration); QuicConnTimerExpired(Connection, TimeNow); - QuicSessionDetachSilo(); + QuicConfigurationDetachSilo(); Connection->WorkerThreadID = 0; } } @@ -437,7 +437,7 @@ QuicWorkerProcessConnection( "[conn][%p] Scheduling: %u", Connection, QUIC_SCHEDULE_PROCESSING); - QuicSessionAttachSilo(Connection->Session); + QuicConfigurationAttachSilo(Connection->Configuration); if (Connection->Stats.Schedule.LastQueueTime != 0) { QuicWorkerUpdateQueueDelay( @@ -516,7 +516,7 @@ QuicWorkerProcessConnection( } QuicDispatchLockRelease(&Worker->Lock); - QuicSessionDetachSilo(); + QuicConfigurationDetachSilo(); if (DoneWithConnection) { if (Connection->State.UpdateWorker) { @@ -638,8 +638,8 @@ QUIC_THREAD_CALLBACK(QuicWorkerThread, Context) } // - // Because the session layer only waits for the session rundown to complete, - // and because the connection releases the session rundown on handle close, + // Because the registration layer only waits for the rundown to complete, + // and because the connection releases the rundown on handle close, // not free, it's possible that the worker thread still had the connection // in it's list by the time clean up started. So it needs to release any // remaining references on connections. diff --git a/src/inc/msquic.h b/src/inc/msquic.h index d67c493ce1..ac5392a25f 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -42,10 +42,7 @@ Supported Platforms: extern "C" { #endif - typedef struct QUIC_HANDLE *HQUIC; -typedef struct QUIC_SEC_CONFIG QUIC_SEC_CONFIG; - // // The maximum value that can be encoded in a 62-bit integer. @@ -85,16 +82,23 @@ typedef enum QUIC_LOAD_BALANCING_MODE { QUIC_LOAD_BALANCING_SERVER_ID_IP // Encodes IP address in Server ID } QUIC_LOAD_BALANCING_MODE; -typedef enum QUIC_SEC_CONFIG_FLAGS { - QUIC_SEC_CONFIG_FLAG_NONE = 0x00000000, - QUIC_SEC_CONFIG_FLAG_CERTIFICATE_HASH = 0x00000001, - QUIC_SEC_CONFIG_FLAG_CERTIFICATE_HASH_STORE = 0x00000002, - QUIC_SEC_CONFIG_FLAG_CERTIFICATE_CONTEXT = 0x00000004, - QUIC_SEC_CONFIG_FLAG_CERTIFICATE_FILE = 0x00000008, - QUIC_SEC_CONFIG_FLAG_ENABLE_OCSP = 0x00000010 -} QUIC_SEC_CONFIG_FLAGS; +typedef enum QUIC_CREDENTIAL_TYPE { + QUIC_CREDENTIAL_TYPE_NONE, + QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH, + QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE, + QUIC_CREDENTIAL_TYPE_CERTIFICATE_CONTEXT, + QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE +} QUIC_CREDENTIAL_TYPE; -DEFINE_ENUM_FLAG_OPERATORS(QUIC_SEC_CONFIG_FLAGS); +typedef enum QUIC_CREDENTIAL_FLAGS { + QUIC_CREDENTIAL_FLAG_NONE = 0x00000000, + QUIC_CREDENTIAL_FLAG_CLIENT = 0x00000001, // Lack of client flag indicates server. + QUIC_CREDENTIAL_FLAG_LOAD_ASYNCHRONOUS = 0x00000002, + QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION = 0x00000004, + QUIC_CREDENTIAL_FLAG_ENABLE_OCSP = 0x00000008 +} QUIC_CREDENTIAL_FLAGS; + +DEFINE_ENUM_FLAG_OPERATORS(QUIC_CREDENTIAL_FLAGS); typedef enum QUIC_CERTIFICATE_HASH_STORE_FLAGS { QUIC_CERTIFICATE_HASH_STORE_FLAG_NONE = 0x0000, @@ -197,6 +201,18 @@ typedef struct QUIC_REGISTRATION_CONFIG { // All fields may be NULL/zero. QUIC_EXECUTION_PROFILE ExecutionProfile; } QUIC_REGISTRATION_CONFIG; +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +_Function_class_(QUIC_CREDENTIAL_LOAD_COMPLETE) +void +(QUIC_API QUIC_CREDENTIAL_LOAD_COMPLETE)( + _In_ HQUIC Configuration, + _In_opt_ void* Context, + _In_ QUIC_STATUS Status + ); + +typedef QUIC_CREDENTIAL_LOAD_COMPLETE *QUIC_CREDENTIAL_LOAD_COMPLETE_HANDLER; + typedef struct QUIC_CERTIFICATE_HASH { uint8_t ShaHash[20]; } QUIC_CERTIFICATE_HASH; @@ -212,6 +228,22 @@ typedef struct QUIC_CERTIFICATE_FILE { char *CertificateFile; } QUIC_CERTIFICATE_FILE; +typedef void QUIC_CERTIFICATE; // Platform specific certificate context object + +typedef struct QUIC_CREDENTIAL_CONFIG { + QUIC_CREDENTIAL_TYPE Type; + QUIC_CREDENTIAL_FLAGS Flags; + union { + QUIC_CERTIFICATE_HASH* CertificateHash; + QUIC_CERTIFICATE_HASH_STORE* CertificateHashStore; + QUIC_CERTIFICATE* CertificateContext; + QUIC_CERTIFICATE_FILE* CertificateFile; + }; + const char* Principal; + void* TicketKey; // Optional, 44 byte array + QUIC_CREDENTIAL_LOAD_COMPLETE_HANDLER AsyncHandler; // Optional +} QUIC_CREDENTIAL_CONFIG; + // // A single contiguous buffer. // @@ -357,8 +389,8 @@ typedef struct QUIC_SETTINGS { uint64_t PeerUnidiStreamCount : 1; uint64_t RetryMemoryLimit : 1; uint64_t LoadBalancingMode : 1; - uint64_t MaxPartitionCount : 1; uint64_t MaxOperationsPerDrain : 1; + uint64_t SendBufferingEnabled : 1; uint64_t PacingEnabled : 1; uint64_t MigrationEnabled : 1; uint64_t DatagramReceiveEnabled : 1; @@ -387,13 +419,13 @@ typedef struct QUIC_SETTINGS { uint16_t PeerUnidiStreamCount; uint16_t RetryMemoryLimit; // Global only uint16_t LoadBalancingMode; // Global only - uint16_t MaxPartitionCount; // Global only - uint8_t MaxOperationsPerDrain; // Global only + uint8_t MaxOperationsPerDrain; + uint8_t SendBufferingEnabled : 1; uint8_t PacingEnabled : 1; uint8_t MigrationEnabled : 1; uint8_t DatagramReceiveEnabled : 1; uint8_t ServerResumptionLevel : 2; // QUIC_SERVER_RESUMPTION_LEVEL - uint8_t RESERVED : 3; + uint8_t RESERVED : 2; } QUIC_SETTINGS; @@ -436,7 +468,7 @@ void typedef enum QUIC_PARAM_LEVEL { QUIC_PARAM_LEVEL_GLOBAL, QUIC_PARAM_LEVEL_REGISTRATION, - QUIC_PARAM_LEVEL_SESSION, + QUIC_PARAM_LEVEL_CONFIGURATION, QUIC_PARAM_LEVEL_LISTENER, QUIC_PARAM_LEVEL_CONNECTION, QUIC_PARAM_LEVEL_TLS, @@ -450,6 +482,7 @@ typedef enum QUIC_PARAM_LEVEL { #define QUIC_PARAM_GLOBAL_SUPPORTED_VERSIONS 1 // uint32_t[] - network byte order #define QUIC_PARAM_GLOBAL_LOAD_BALACING_MODE 2 // uint16_t - QUIC_LOAD_BALANCING_MODE #define QUIC_PARAM_GLOBAL_PERF_COUNTERS 3 // uint64_t[] - Array size is QUIC_PERF_COUNTER_MAX +#define QUIC_PARAM_GLOBAL_SETTINGS 4 // QUIC_SETTINGS // // Parameters for QUIC_PARAM_LEVEL_REGISTRATION. @@ -457,9 +490,9 @@ typedef enum QUIC_PARAM_LEVEL { #define QUIC_PARAM_REGISTRATION_CID_PREFIX 0 // uint8_t[] // -// Parameters for QUIC_PARAM_LEVEL_SESSION. +// Parameters for QUIC_PARAM_LEVEL_CONFIGURATION. // -#define QUIC_PARAM_SESSION_TLS_TICKET_KEY 0 // uint8_t[44] +#define QUIC_PARAM_CONFIGURATION_SETTINGS 0 // QUIC_SETTINGS // // Parameters for QUIC_PARAM_LEVEL_LISTENER. @@ -473,38 +506,22 @@ typedef enum QUIC_PARAM_LEVEL { #define QUIC_PARAM_CONN_QUIC_VERSION 0 // uint32_t #define QUIC_PARAM_CONN_LOCAL_ADDRESS 1 // QUIC_ADDR #define QUIC_PARAM_CONN_REMOTE_ADDRESS 2 // QUIC_ADDR -#define QUIC_PARAM_CONN_IDLE_TIMEOUT 3 // uint64_t - milliseconds -#define QUIC_PARAM_CONN_PEER_BIDI_STREAM_COUNT 4 // uint16_t -#define QUIC_PARAM_CONN_PEER_UNIDI_STREAM_COUNT 5 // uint16_t -#define QUIC_PARAM_CONN_LOCAL_BIDI_STREAM_COUNT 6 // uint16_t -#define QUIC_PARAM_CONN_LOCAL_UNIDI_STREAM_COUNT 7 // uint16_t -#define QUIC_PARAM_CONN_CLOSE_REASON_PHRASE 8 // char[] -#define QUIC_PARAM_CONN_STATISTICS 9 // QUIC_STATISTICS -#define QUIC_PARAM_CONN_STATISTICS_PLAT 10 // QUIC_STATISTICS -#define QUIC_PARAM_CONN_CERT_VALIDATION_FLAGS 11 // uint32_t -#define QUIC_PARAM_CONN_KEEP_ALIVE 12 // uint32_t - milliseconds -#define QUIC_PARAM_CONN_DISCONNECT_TIMEOUT 13 // uint32_t - milliseconds -#define QUIC_PARAM_CONN_SEC_CONFIG 14 // QUIC_SEC_CONFIG* -#define QUIC_PARAM_CONN_SEND_BUFFERING 15 // uint8_t (BOOLEAN) -#define QUIC_PARAM_CONN_SEND_PACING 16 // uint8_t (BOOLEAN) -#define QUIC_PARAM_CONN_SHARE_UDP_BINDING 17 // uint8_t (BOOLEAN) -#define QUIC_PARAM_CONN_IDEAL_PROCESSOR 18 // uint16_t -#define QUIC_PARAM_CONN_MAX_STREAM_IDS 19 // uint64_t[4] -#define QUIC_PARAM_CONN_STREAM_SCHEDULING_SCHEME 20 // QUIC_STREAM_SCHEDULING_SCHEME -#define QUIC_PARAM_CONN_DATAGRAM_RECEIVE_ENABLED 21 // uint8_t (BOOLEAN) -#define QUIC_PARAM_CONN_DATAGRAM_SEND_ENABLED 22 // uint8_t (BOOLEAN) +#define QUIC_PARAM_CONN_IDEAL_PROCESSOR 3 // uint16_t +#define QUIC_PARAM_CONN_SETTINGS 4 // QUIC_SETTINGS +#define QUIC_PARAM_CONN_STATISTICS 5 // QUIC_STATISTICS +#define QUIC_PARAM_CONN_STATISTICS_PLAT 6 // QUIC_STATISTICS +#define QUIC_PARAM_CONN_SHARE_UDP_BINDING 7 // uint8_t (BOOLEAN) +#define QUIC_PARAM_CONN_LOCAL_BIDI_STREAM_COUNT 8 // uint16_t +#define QUIC_PARAM_CONN_LOCAL_UNIDI_STREAM_COUNT 9 // uint16_t +#define QUIC_PARAM_CONN_MAX_STREAM_IDS 10 // uint64_t[4] +#define QUIC_PARAM_CONN_CLOSE_REASON_PHRASE 11 // char[] +#define QUIC_PARAM_CONN_STREAM_SCHEDULING_SCHEME 12 // QUIC_STREAM_SCHEDULING_SCHEME +#define QUIC_PARAM_CONN_DATAGRAM_RECEIVE_ENABLED 13 // uint8_t (BOOLEAN) +#define QUIC_PARAM_CONN_DATAGRAM_SEND_ENABLED 14 // uint8_t (BOOLEAN) #ifdef QUIC_API_ENABLE_INSECURE_FEATURES -#define QUIC_PARAM_CONN_DISABLE_1RTT_ENCRYPTION 23 // uint8_t (BOOLEAN) -#endif - -#ifdef WIN32 // Windows certificate validation ignore flags. -#define QUIC_CERTIFICATE_FLAG_IGNORE_REVOCATION 0x00000080 -#define QUIC_CERTIFICATE_FLAG_IGNORE_UNKNOWN_CA 0x00000100 -#define QUIC_CERTIFICATE_FLAG_IGNORE_WRONG_USAGE 0x00000200 -#define QUIC_CERTIFICATE_FLAG_IGNORE_CERTIFICATE_CN_INVALID 0x00001000 // bad common name in X509 Cert. -#define QUIC_CERTIFICATE_FLAG_IGNORE_CERTIFICATE_DATE_INVALID 0x00002000 // expired X509 Cert. -#define QUIC_CERTIFICATE_FLAG_IGNORE_WEAK_SIGNATURE 0x00010000 +#define QUIC_PARAM_CONN_DISABLE_1RTT_ENCRYPTION 15 // uint8_t (BOOLEAN) #endif +#define QUIC_PARAM_CONN_RESUMPTION_STATE 16 // uint8_t[] // // Parameters for QUIC_PARAM_LEVEL_TLS. @@ -569,7 +586,10 @@ QUIC_STATUS ); // -// Closes the registration. +// Closes the registration. This function synchronizes the cleanup of all +// child objects. It does this by blocking until all those child objects have +// been closed by the application. +// N.B. This function will deadlock if called in any MsQuic callbacks. // typedef _IRQL_requires_max_(PASSIVE_LEVEL) @@ -580,92 +600,61 @@ void ); // -// Security Configuration Interface. +// Calls shutdown for all connections in this registration. Don't call on a +// MsQuic callback thread or it might deadlock. // - typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -_Function_class_(QUIC_SEC_CONFIG_CREATE_COMPLETE) +_IRQL_requires_max_(DISPATCH_LEVEL) void -(QUIC_API QUIC_SEC_CONFIG_CREATE_COMPLETE)( - _In_opt_ void* Context, - _In_ QUIC_STATUS Status, - _In_opt_ QUIC_SEC_CONFIG* SecurityConfig - ); - -typedef QUIC_SEC_CONFIG_CREATE_COMPLETE *QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER; - -// -// Create a new security config. -// -typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -(QUIC_API * QUIC_SEC_CONFIG_CREATE_FN)( +(QUIC_API * QUIC_REGISTRATION_SHUTDOWN_FN)( _In_ _Pre_defensive_ HQUIC Registration, - _In_ QUIC_SEC_CONFIG_FLAGS Flags, - _In_opt_ void* Certificate, - _In_opt_z_ const char* Principal, - _In_opt_ void* Context, - _In_ _Pre_defensive_ - QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER CompletionHandler - ); - -typedef -_IRQL_requires_max_(PASSIVE_LEVEL) -void -(QUIC_API * QUIC_SEC_CONFIG_DELETE_FN)( - _In_ _Pre_defensive_ QUIC_SEC_CONFIG* SecurityConfig + _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, + _In_ _Pre_defensive_ QUIC_UINT62 ErrorCode // Application defined error code ); // -// Session Context Interface. +// Configuration Interface. // // -// Opens a new session. +// Opens a new configuration. // typedef _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS -(QUIC_API * QUIC_SESSION_OPEN_FN)( +(QUIC_API * QUIC_CONFIGURATION_OPEN_FN)( _In_ _Pre_defensive_ HQUIC Registration, - _In_ uint32_t SettingsSize, - _In_reads_bytes_opt_(SettingsSize) - const QUIC_SETTINGS* Settings, _In_reads_(AlpnBufferCount) _Pre_defensive_ const QUIC_BUFFER* const AlpnBuffers, _In_range_(>, 0) uint32_t AlpnBufferCount, + _In_reads_bytes_opt_(SettingsSize) + const QUIC_SETTINGS* Settings, + _In_ uint32_t SettingsSize, _In_opt_ void* Context, - _Outptr_ _At_(*Session, __drv_allocatesMem(Mem)) _Pre_defensive_ - HQUIC* Session + _Outptr_ _At_(*Configuration, __drv_allocatesMem(Mem)) _Pre_defensive_ + HQUIC* Configuration ); // -// Closes an existing session. This function synchronizes the cleanup of all -// child objects (listeners and connections). It does this by blocking until -// all those child objects have been closed by the application. -// N.B. This function will deadlock if called in any MsQuic callbacks. +// Closes an existing configuration. // typedef _IRQL_requires_max_(PASSIVE_LEVEL) void -(QUIC_API * QUIC_SESSION_CLOSE_FN)( +(QUIC_API * QUIC_CONFIGURATION_CLOSE_FN)( _In_ _Pre_defensive_ __drv_freesMem(Mem) - HQUIC Session + HQUIC Configuration ); // -// Calls shutdown for all connections in this session. Don't call on a MsQuic -// callback thread or it might deadlock. +// Loads the credentials based on the input configuration. // typedef _IRQL_requires_max_(PASSIVE_LEVEL) -void -(QUIC_API * QUIC_SESSION_SHUTDOWN_FN)( - _In_ _Pre_defensive_ HQUIC Session, - _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, - _In_ _Pre_defensive_ QUIC_UINT62 ErrorCode // Application defined error code +QUIC_STATUS +(QUIC_API * QUIC_CONFIGURATION_LOAD_CREDENTIAL_FN)( + _In_ _Pre_defensive_ HQUIC Configuration, + _In_ _Pre_defensive_ const QUIC_CREDENTIAL_CONFIG* CredConfig ); // @@ -680,9 +669,8 @@ typedef struct QUIC_LISTENER_EVENT { QUIC_LISTENER_EVENT_TYPE Type; union { struct { - /* in */ const QUIC_NEW_CONNECTION_INFO* Info; - /* in */ HQUIC Connection; - /* out */ QUIC_SEC_CONFIG* SecurityConfig; + const QUIC_NEW_CONNECTION_INFO* Info; + HQUIC Connection; } NEW_CONNECTION; }; } QUIC_LISTENER_EVENT; @@ -706,7 +694,7 @@ typedef _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS (QUIC_API * QUIC_LISTENER_OPEN_FN)( - _In_ _Pre_defensive_ HQUIC Session, + _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_ @@ -733,6 +721,9 @@ _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS (QUIC_API * QUIC_LISTENER_START_FN)( _In_ _Pre_defensive_ HQUIC Listener, + _In_reads_(AlpnBufferCount) _Pre_defensive_ + const QUIC_BUFFER* const AlpnBuffers, + _In_range_(>, 0) uint32_t AlpnBufferCount, _In_opt_ const QUIC_ADDR* LocalAddress ); @@ -822,7 +813,7 @@ typedef struct QUIC_CONNECTION_EVENT { const uint8_t* ResumptionState; } RESUMED; struct { - uint16_t ResumptionTicketLength; + uint32_t ResumptionTicketLength; const uint8_t* ResumptionTicket; } RESUMPTION_TICKET_RECEIVED; }; @@ -847,7 +838,7 @@ typedef _IRQL_requires_max_(DISPATCH_LEVEL) QUIC_STATUS (QUIC_API * QUIC_CONNECTION_OPEN_FN)( - _In_ _Pre_defensive_ HQUIC Session, + _In_ _Pre_defensive_ HQUIC Registration, _In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler, _In_opt_ void* Context, _Outptr_ _At_(*Connection, __drv_allocatesMem(Mem)) _Pre_defensive_ @@ -889,12 +880,25 @@ _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS (QUIC_API * QUIC_CONNECTION_START_FN)( _In_ _Pre_defensive_ HQUIC Connection, + _In_ _Pre_defensive_ HQUIC Configuration, _In_ QUIC_ADDRESS_FAMILY Family, _In_reads_opt_z_(QUIC_MAX_SNI_LENGTH) const char* ServerName, _In_ uint16_t ServerPort // Host byte order ); +// +// Sets the (server-side) configuration handle for the connection. This must be +// called on an accepted connection in order to proceed with the QUIC handshake. +// +typedef +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +(QUIC_API * QUIC_CONNECTION_SET_CONFIGURATION_FN)( + _In_ _Pre_defensive_ HQUIC Connection, + _In_ _Pre_defensive_ HQUIC Configuration + ); + // // Uses the QUIC (server) handle to send a resumption ticket to the remote // client, optionally with app-specific data useful during resumption. @@ -1094,13 +1098,12 @@ typedef struct QUIC_API_TABLE { QUIC_REGISTRATION_OPEN_FN RegistrationOpen; QUIC_REGISTRATION_CLOSE_FN RegistrationClose; + QUIC_REGISTRATION_SHUTDOWN_FN RegistrationShutdown; - QUIC_SEC_CONFIG_CREATE_FN SecConfigCreate; - QUIC_SEC_CONFIG_DELETE_FN SecConfigDelete; - - QUIC_SESSION_OPEN_FN SessionOpen; - QUIC_SESSION_CLOSE_FN SessionClose; - QUIC_SESSION_SHUTDOWN_FN SessionShutdown; + QUIC_CONFIGURATION_OPEN_FN ConfigurationOpen; + QUIC_CONFIGURATION_CLOSE_FN ConfigurationClose; + QUIC_CONFIGURATION_LOAD_CREDENTIAL_FN + ConfigurationLoadCredential; QUIC_LISTENER_OPEN_FN ListenerOpen; QUIC_LISTENER_CLOSE_FN ListenerClose; @@ -1111,6 +1114,8 @@ typedef struct QUIC_API_TABLE { QUIC_CONNECTION_CLOSE_FN ConnectionClose; QUIC_CONNECTION_SHUTDOWN_FN ConnectionShutdown; QUIC_CONNECTION_START_FN ConnectionStart; + QUIC_CONNECTION_SET_CONFIGURATION_FN + ConnectionSetConfiguration; QUIC_CONNECTION_SEND_RESUMPTION_FN ConnectionSendResumptionTicket; QUIC_STREAM_OPEN_FN StreamOpen; diff --git a/src/inc/msquic.hpp b/src/inc/msquic.hpp index 51eb0e3a31..4d382e7f27 100644 --- a/src/inc/msquic.hpp +++ b/src/inc/msquic.hpp @@ -22,22 +22,26 @@ Supported Platforms: #include +#ifndef QUIC_DBG_ASSERT +#define QUIC_DBG_ASSERT(X) // no-op if not already defined +#endif + struct QuicAddr { QUIC_ADDR SockAddr; QuicAddr() { - QuicZeroMemory(&SockAddr, sizeof(SockAddr)); + memset(&SockAddr, 0, sizeof(SockAddr)); } QuicAddr(QUIC_ADDRESS_FAMILY af) { - QuicZeroMemory(&SockAddr, sizeof(SockAddr)); + memset(&SockAddr, 0, sizeof(SockAddr)); QuicAddrSetFamily(&SockAddr, af); } QuicAddr(QUIC_ADDRESS_FAMILY af, uint16_t Port) { - QuicZeroMemory(&SockAddr, sizeof(SockAddr)); + memset(&SockAddr, 0, sizeof(SockAddr)); QuicAddrSetFamily(&SockAddr, af); QuicAddrSetPort(&SockAddr, Port); } QuicAddr(QUIC_ADDRESS_FAMILY af, bool /*unused*/) { - QuicZeroMemory(&SockAddr, sizeof(SockAddr)); + memset(&SockAddr, 0, sizeof(SockAddr)); QuicAddrSetFamily(&SockAddr, af); QuicAddrSetToLoopback(&SockAddr); } @@ -190,7 +194,7 @@ class MsQuicApi : public QUIC_API_TABLE { MsQuicApi() noexcept { if (QUIC_SUCCEEDED(InitStatus = MsQuicOpen(&ApiTable))) { QUIC_API_TABLE* thisTable = this; - QuicCopyMemory(thisTable, ApiTable, sizeof(*ApiTable)); + memcpy(thisTable, ApiTable, sizeof(*ApiTable)); } } ~MsQuicApi() noexcept { @@ -198,7 +202,7 @@ class MsQuicApi : public QUIC_API_TABLE { MsQuicClose(ApiTable); ApiTable = nullptr; QUIC_API_TABLE* thisTable = this; - QuicZeroMemory(thisTable, sizeof(*thisTable)); + memset(thisTable, 0, sizeof(*thisTable)); } } QUIC_STATUS GetInitStatus() const noexcept { return InitStatus; } @@ -207,24 +211,45 @@ class MsQuicApi : public QUIC_API_TABLE { extern const MsQuicApi* MsQuic; class MsQuicRegistration { + bool CloseAllConnectionsOnDelete {false}; HQUIC Handle {nullptr}; QUIC_STATUS InitStatus; public: operator HQUIC () const noexcept { return Handle; } - MsQuicRegistration() noexcept { + MsQuicRegistration( + _In_ bool AutoCleanUp = false + ) noexcept : CloseAllConnectionsOnDelete(AutoCleanUp) { InitStatus = MsQuic->RegistrationOpen(nullptr, &Handle); } - MsQuicRegistration(_In_z_ const char* AppName, QUIC_EXECUTION_PROFILE Profile = QUIC_EXECUTION_PROFILE_LOW_LATENCY) noexcept { + MsQuicRegistration( + _In_z_ const char* AppName, + QUIC_EXECUTION_PROFILE Profile = QUIC_EXECUTION_PROFILE_LOW_LATENCY, + _In_ bool AutoCleanUp = false + ) noexcept : CloseAllConnectionsOnDelete(AutoCleanUp) { const QUIC_REGISTRATION_CONFIG RegConfig = { AppName, Profile }; InitStatus = MsQuic->RegistrationOpen(&RegConfig, &Handle); } ~MsQuicRegistration() noexcept { - MsQuic->RegistrationClose(Handle); + if (Handle != nullptr) { + if (CloseAllConnectionsOnDelete) { + MsQuic->RegistrationShutdown( + Handle, + QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT, + 1); + } + MsQuic->RegistrationClose(Handle); + } } QUIC_STATUS GetInitStatus() const noexcept { return InitStatus; } - bool IsValid() const noexcept { return Handle != nullptr; } + bool IsValid() const noexcept { return QUIC_SUCCEEDED(InitStatus); } MsQuicRegistration(MsQuicRegistration& other) = delete; MsQuicRegistration operator=(MsQuicRegistration& Other) = delete; + void Shutdown( + _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, + _In_ QUIC_UINT62 ErrorCode + ) noexcept { + MsQuic->RegistrationShutdown(Handle, Flags, ErrorCode); + } }; class MsQuicAlpn { @@ -250,6 +275,7 @@ class MsQuicAlpn { class MsQuicSettings : public QUIC_SETTINGS { public: MsQuicSettings() noexcept { IsSetFlags = 0; } + MsQuicSettings& SetSendBufferingEnabled(bool Value) { SendBufferingEnabled = Value; IsSet.SendBufferingEnabled = TRUE; return *this; } MsQuicSettings& SetPacingEnabled(bool Value) { PacingEnabled = Value; IsSet.PacingEnabled = TRUE; return *this; } MsQuicSettings& SetMigrationEnabled(bool Value) { MigrationEnabled = Value; IsSet.MigrationEnabled = TRUE; return *this; } MsQuicSettings& SetDatagramReceiveEnabled(bool Value) { DatagramReceiveEnabled = Value; IsSet.DatagramReceiveEnabled = TRUE; return *this; } @@ -262,78 +288,110 @@ class MsQuicSettings : public QUIC_SETTINGS { MsQuicSettings& SetMaxBytesPerKey(uint64_t Value) { MaxBytesPerKey = Value; IsSet.MaxBytesPerKey = TRUE; return *this; } }; -class MsQuicSession { - bool CloseAllConnectionsOnDelete {false}; - QUIC_STATUS InitStatus; +#ifndef QUIC_DEFAULT_CLIENT_CRED_FLAGS +#define QUIC_DEFAULT_CLIENT_CRED_FLAGS QUIC_CREDENTIAL_FLAG_CLIENT +#endif + +class MsQuicCredentialConfig : public QUIC_CREDENTIAL_CONFIG { public: + MsQuicCredentialConfig(const QUIC_CREDENTIAL_CONFIG& Config) { + QUIC_CREDENTIAL_CONFIG* thisStruct = this; + memcpy(thisStruct, &Config, sizeof(QUIC_CREDENTIAL_CONFIG)); + } + MsQuicCredentialConfig(QUIC_CREDENTIAL_FLAGS _Flags = QUIC_DEFAULT_CLIENT_CRED_FLAGS) { + QUIC_CREDENTIAL_CONFIG* thisStruct = this; + memset(thisStruct, 0, sizeof(QUIC_CREDENTIAL_CONFIG)); + Flags = _Flags; + } +}; + +class MsQuicConfiguration { HQUIC Handle {nullptr}; + QUIC_STATUS InitStatus; +public: operator HQUIC () const noexcept { return Handle; } - MsQuicSession( + MsQuicConfiguration( + _In_ const MsQuicRegistration& Reg, + _In_ const MsQuicAlpn& Alpns + ) { + InitStatus = !Reg.IsValid() ? + Reg.GetInitStatus() : + MsQuic->ConfigurationOpen( + Reg, + Alpns, + Alpns.Length(), + nullptr, + 0, + nullptr, + &Handle); + } + MsQuicConfiguration( _In_ const MsQuicRegistration& Reg, _In_ const MsQuicAlpn& Alpns, - _In_ bool AutoCleanUp = false - ) noexcept : CloseAllConnectionsOnDelete(AutoCleanUp) { + _In_ const MsQuicCredentialConfig& CredConfig + ) { InitStatus = !Reg.IsValid() ? Reg.GetInitStatus() : - MsQuic->SessionOpen( + MsQuic->ConfigurationOpen( Reg, + Alpns, + Alpns.Length(), + nullptr, 0, nullptr, + &Handle); + if (IsValid()) { + InitStatus = LoadCredential(&CredConfig); + } + } + MsQuicConfiguration( + _In_ const MsQuicRegistration& Reg, + _In_ const MsQuicAlpn& Alpns, + _In_ const MsQuicSettings& Settings + ) noexcept { + InitStatus = !Reg.IsValid() ? + Reg.GetInitStatus() : + MsQuic->ConfigurationOpen( + Reg, Alpns, Alpns.Length(), + &Settings, + sizeof(Settings), nullptr, &Handle); } - MsQuicSession( + MsQuicConfiguration( _In_ const MsQuicRegistration& Reg, _In_ const MsQuicAlpn& Alpns, _In_ const MsQuicSettings& Settings, - _In_ bool AutoCleanUp = false - ) noexcept : CloseAllConnectionsOnDelete(AutoCleanUp) { + _In_ const MsQuicCredentialConfig& CredConfig + ) noexcept { InitStatus = !Reg.IsValid() ? Reg.GetInitStatus() : - MsQuic->SessionOpen( + MsQuic->ConfigurationOpen( Reg, - sizeof(Settings), - &Settings, Alpns, Alpns.Length(), + &Settings, + sizeof(Settings), nullptr, &Handle); + if (IsValid()) { + InitStatus = LoadCredential(&CredConfig); + } } - ~MsQuicSession() noexcept { + ~MsQuicConfiguration() noexcept { if (Handle != nullptr) { - if (CloseAllConnectionsOnDelete) { - MsQuic->SessionShutdown( - Handle, - QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT, - 1); - } - MsQuic->SessionClose(Handle); + MsQuic->ConfigurationClose(Handle); } } QUIC_STATUS GetInitStatus() const noexcept { return InitStatus; } - bool IsValid() const noexcept { return Handle != nullptr; } - MsQuicSession(MsQuicSession& other) = delete; - MsQuicSession operator=(MsQuicSession& Other) = delete; - void Shutdown( - _In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags, - _In_ QUIC_UINT62 ErrorCode - ) noexcept { - MsQuic->SessionShutdown(Handle, Flags, ErrorCode); - } + bool IsValid() const noexcept { return QUIC_SUCCEEDED(InitStatus); } + MsQuicConfiguration(MsQuicConfiguration& other) = delete; + MsQuicConfiguration operator=(MsQuicConfiguration& Other) = delete; QUIC_STATUS - SetTlsTicketKey( - _In_reads_bytes_(44) - const uint8_t* const Buffer - ) noexcept { - return - MsQuic->SetParam( - Handle, - QUIC_PARAM_LEVEL_SESSION, - QUIC_PARAM_SESSION_TLS_TICKET_KEY, - 44, - Buffer); + LoadCredential(_In_ const QUIC_CREDENTIAL_CONFIG* CredConfig) noexcept { + return MsQuic->ConfigurationLoadCredential(Handle, CredConfig); } }; @@ -343,15 +401,15 @@ struct MsQuicListener { QUIC_LISTENER_CALLBACK_HANDLER Handler { nullptr }; void* Context{ nullptr }; - MsQuicListener(const MsQuicSession& Session) noexcept { - if (!Session.IsValid()) { - InitStatus = Session.GetInitStatus(); + MsQuicListener(const MsQuicRegistration& Registration) noexcept { + if (!Registration.IsValid()) { + InitStatus = Registration.GetInitStatus(); return; } if (QUIC_FAILED( InitStatus = MsQuic->ListenerOpen( - Session, + Registration, [](HQUIC Handle, void* Context, QUIC_LISTENER_EVENT* Event) -> QUIC_STATUS { MsQuicListener* Listener = (MsQuicListener*)Context; return Listener->Handler(Handle, Listener->Context, Event); @@ -372,12 +430,13 @@ struct MsQuicListener { QUIC_STATUS Start( + _In_ const MsQuicAlpn& Alpns, _In_ QUIC_ADDR* Address, _In_ QUIC_LISTENER_CALLBACK_HANDLER _Handler, _In_ void* _Context) noexcept { Handler = _Handler; Context = _Context; - return MsQuic->ListenerStart(Handle, Address); + return MsQuic->ListenerStart(Handle, Alpns, Alpns.Length(), Address); } QUIC_STATUS @@ -386,7 +445,7 @@ struct MsQuicListener { } QUIC_STATUS GetInitStatus() const noexcept { return InitStatus; } - bool IsValid() const { return Handle != nullptr; } + bool IsValid() const { return QUIC_SUCCEEDED(InitStatus); } MsQuicListener(MsQuicListener& other) = delete; MsQuicListener operator=(MsQuicListener& Other) = delete; operator HQUIC () const noexcept { return Handle; } @@ -416,23 +475,31 @@ struct StreamScope { operator HQUIC() const noexcept { return Handle; } }; -struct EventScope { - QUIC_EVENT Handle; - EventScope() noexcept { QuicEventInitialize(&Handle, FALSE, FALSE); } - EventScope(bool ManualReset) noexcept { QuicEventInitialize(&Handle, ManualReset, FALSE); } - EventScope(QUIC_EVENT event) noexcept : Handle(event) { } - ~EventScope() noexcept { QuicEventUninitialize(Handle); } - operator QUIC_EVENT() const noexcept { return Handle; } -}; - struct QuicBufferScope { QUIC_BUFFER* Buffer; QuicBufferScope() noexcept : Buffer(nullptr) { } QuicBufferScope(uint32_t Size) noexcept : Buffer((QUIC_BUFFER*) new uint8_t[sizeof(QUIC_BUFFER) + Size]) { - QuicZeroMemory(Buffer, sizeof(*Buffer) + Size); + memset(Buffer, 0, sizeof(*Buffer) + Size); Buffer->Length = Size; Buffer->Buffer = (uint8_t*)(Buffer + 1); } operator QUIC_BUFFER* () noexcept { return Buffer; } ~QuicBufferScope() noexcept { if (Buffer) { delete[](uint8_t*) Buffer; } } }; + +#ifdef QUIC_PLATFORM_TYPE + +// +// Abstractions for platform specific types/interfaces +// + +struct EventScope { + QUIC_EVENT Handle; + EventScope() noexcept { QuicEventInitialize(&Handle, FALSE, FALSE); } + EventScope(bool ManualReset) noexcept { QuicEventInitialize(&Handle, ManualReset, FALSE); } + EventScope(QUIC_EVENT event) noexcept : Handle(event) { } + ~EventScope() noexcept { QuicEventUninitialize(Handle); } + operator QUIC_EVENT() const noexcept { return Handle; } +}; + +#endif diff --git a/src/inc/msquic_linux.h b/src/inc/msquic_linux.h index 16064deb73..4ef6899d50 100644 --- a/src/inc/msquic_linux.h +++ b/src/inc/msquic_linux.h @@ -32,7 +32,8 @@ #include #include #include -#include +#include +#include #include "quic_sal_stub.h" #ifdef __cplusplus diff --git a/src/inc/msquichelper.h b/src/inc/msquichelper.h index c4df80c83c..2407d377bf 100644 --- a/src/inc/msquichelper.h +++ b/src/inc/msquichelper.h @@ -21,6 +21,15 @@ #include #include +typedef struct QUIC_CREDENTIAL_CONFIG_HELPER { + QUIC_CREDENTIAL_CONFIG CredConfig; + union { + QUIC_CERTIFICATE_HASH CertHash; + QUIC_CERTIFICATE_HASH_STORE CertHashStore; + QUIC_CERTIFICATE_FILE CertFile; + }; +} QUIC_CREDENTIAL_CONFIG_HELPER; + // // Converts the QUIC Status Code to a string for console output. // @@ -239,229 +248,8 @@ DecodeHexBuffer( return HexBufferLen; } -// -// Helper function to take a hex encoded byte string for the resumption state. -// -inline -BOOLEAN -SetResumptionState( - _In_ const QUIC_API_TABLE* MsQuic, - _In_ HQUIC Handle, - _In_z_ const char* SerializedState - ) -{ - uint8_t State[2048]; - uint32_t StateLen = - DecodeHexBuffer(SerializedState, sizeof(State), State); - - if (StateLen == 0) { - return FALSE; - } - - return - QUIC_SUCCEEDED( - MsQuic->SetParam( - Handle, - QUIC_PARAM_LEVEL_SESSION, - QUIC_PARAM_SESSION_ADD_RESUMPTION_STATE, - StateLen, - State)); -} - #if defined(__cplusplus) -struct CreateSecConfigHelper { - QUIC_EVENT Complete; - QUIC_SEC_CONFIG* SecurityConfig; - - CreateSecConfigHelper() : SecurityConfig(nullptr) { - QuicEventInitialize(&Complete, FALSE, FALSE); - } - - ~CreateSecConfigHelper() { - QuicEventUninitialize(Complete); - } - - _Function_class_(QUIC_SEC_CONFIG_CREATE_COMPLETE) - static void - QUIC_API - GetSecConfigComplete( - _In_opt_ void* Context, - _In_ QUIC_STATUS /* Status */, - _In_opt_ QUIC_SEC_CONFIG* SecurityConfig - ) - { - _Analysis_assume_(Context); - auto HelperContext = (CreateSecConfigHelper*)Context; - HelperContext->SecurityConfig = SecurityConfig; - QuicEventSet(HelperContext->Complete); - } - - QUIC_SEC_CONFIG* - Create( - _In_ const QUIC_API_TABLE* MsQuic, - _In_ _Pre_defensive_ HQUIC Registration, - _In_ QUIC_SEC_CONFIG_FLAGS Flags, - _In_opt_ void* Certificate, - _In_opt_z_ const char* Principal - ) - { - if (QUIC_SUCCEEDED( - MsQuic->SecConfigCreate( - Registration, - Flags, - Certificate, - Principal, - this, - GetSecConfigComplete))) { - QuicEventWaitForever(Complete); - } - return SecurityConfig; - } -}; - -inline -QUIC_SEC_CONFIG* -GetSecConfigForCertContext( - _In_ const QUIC_API_TABLE* MsQuic, - _In_ HQUIC Registration, - _In_ void* CertContext - ) -{ - CreateSecConfigHelper Helper; - return - Helper.Create( - MsQuic, - Registration, - QUIC_SEC_CONFIG_FLAG_CERTIFICATE_CONTEXT, - CertContext, - nullptr); -} - -inline -QUIC_SEC_CONFIG* -GetSecConfigForSNI( - _In_ const QUIC_API_TABLE* MsQuic, - _In_ HQUIC Registration, - _In_z_ const char* ServerName - ) -{ - CreateSecConfigHelper Helper; - return - Helper.Create( - MsQuic, - Registration, - QUIC_SEC_CONFIG_FLAG_NONE, - nullptr, - ServerName); -} - -inline -QUIC_SEC_CONFIG* -GetSecConfigForThumbprint( - _In_ const QUIC_API_TABLE* MsQuic, - _In_ HQUIC Registration, - _In_z_ const char* Thumbprint - ) -{ - QUIC_CERTIFICATE_HASH CertHash; - uint32_t CertHashLen = - DecodeHexBuffer( - Thumbprint, - sizeof(CertHash.ShaHash), - CertHash.ShaHash); - if (CertHashLen != sizeof(CertHash.ShaHash)) { - return nullptr; - } - CreateSecConfigHelper Helper; - return - Helper.Create( - MsQuic, - Registration, - QUIC_SEC_CONFIG_FLAG_CERTIFICATE_HASH, - &CertHash, - nullptr); -} - -inline -QUIC_SEC_CONFIG* -GetSecConfigForThumbprintAndStore( - _In_ const QUIC_API_TABLE* MsQuic, - _In_ HQUIC Registration, - _In_ QUIC_CERTIFICATE_HASH_STORE_FLAGS Flags, - _In_z_ const char* Thumbprint, - _In_z_ const char* StoreName - ) -{ - QUIC_CERTIFICATE_HASH_STORE CertHashStore; - QuicZeroMemory(&CertHashStore, sizeof(CertHashStore)); - - uint32_t CertHashLen = - DecodeHexBuffer( - Thumbprint, - sizeof(CertHashStore.ShaHash), - CertHashStore.ShaHash); - if (CertHashLen != sizeof(CertHashStore.ShaHash)) { - return nullptr; - } - - size_t StoreNameLen = strlen(StoreName); - QuicCopyMemory(CertHashStore.StoreName, StoreName, min(StoreNameLen, sizeof(CertHashStore.StoreName))); - - CertHashStore.Flags = Flags; - - CreateSecConfigHelper Helper; - return - Helper.Create( - MsQuic, - Registration, - QUIC_SEC_CONFIG_FLAG_CERTIFICATE_HASH_STORE, - &CertHashStore, - nullptr); -} - -inline -QUIC_SEC_CONFIG* -GetSecConfigForFile( - _In_ const QUIC_API_TABLE* MsQuic, - _In_ HQUIC Registration, - _In_z_ const char *PrivateKeyFile, - _In_z_ const char *CertificateFile - ) -{ - QUIC_CERTIFICATE_FILE CertFile; - CertFile.PrivateKeyFile = (char*)PrivateKeyFile; - CertFile.CertificateFile = (char*)CertificateFile; - CreateSecConfigHelper Helper; - return - Helper.Create( - MsQuic, - Registration, - QUIC_SEC_CONFIG_FLAG_CERTIFICATE_FILE, - &CertFile, - nullptr); -} - -#ifdef QUIC_TEST_APIS -inline -QUIC_SEC_CONFIG* -GetSecConfigForSelfSigned( - _In_ const QUIC_API_TABLE* MsQuic, - _In_ HQUIC Registration, - _In_ const QUIC_SEC_CONFIG_PARAMS* Params - ) -{ - CreateSecConfigHelper Helper; - return Helper.Create( - MsQuic, - Registration, - (QUIC_SEC_CONFIG_FLAGS)Params->Flags, - Params->Certificate, - Params->Principal - ); -} -#endif - // // Arg Value Parsers // @@ -592,4 +380,118 @@ TryGetValue( return true; } +inline +_Success_(return != false) +HQUIC +GetServerConfigurationFromArgs( + _In_ int argc, + _In_reads_(argc) _Null_terminated_ char* argv[], + _In_ const QUIC_API_TABLE* MsQuic, + _In_ HQUIC Registration, + _In_reads_(AlpnBufferCount) _Pre_defensive_ + const QUIC_BUFFER* const AlpnBuffers, + _In_range_(>, 0) uint32_t AlpnBufferCount, + _In_reads_bytes_opt_(SettingsSize) + const QUIC_SETTINGS* Settings, + _In_ uint32_t SettingsSize + ) +{ + QUIC_CREDENTIAL_CONFIG_HELPER Helper; + QuicZeroMemory(&Helper, sizeof(Helper)); + const QUIC_CREDENTIAL_CONFIG* Config = &Helper.CredConfig; + Helper.CredConfig.Flags = QUIC_CREDENTIAL_FLAG_NONE; + + const char* Cert; + const char* KeyFile; + + if (((Cert = GetValue(argc, argv, "thumbprint")) != nullptr) || + ((Cert = GetValue(argc, argv, "cert_hash")) != nullptr) || + ((Cert = GetValue(argc, argv, "hash")) != nullptr)) { + uint32_t CertHashLen = + DecodeHexBuffer( + Cert, + sizeof(Helper.CertHashStore.ShaHash), + Helper.CertHashStore.ShaHash); + if (CertHashLen != sizeof(Helper.CertHashStore.ShaHash)) { + return nullptr; + } + Helper.CredConfig.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_HASH_STORE; + Helper.CredConfig.CertificateHashStore = &Helper.CertHashStore; + memcpy(Helper.CertHashStore.StoreName, "My", sizeof("My")); + Helper.CertHashStore.Flags = + GetValue(argc, argv, "machine") ? + QUIC_CERTIFICATE_HASH_STORE_FLAG_MACHINE_STORE : + QUIC_CERTIFICATE_HASH_STORE_FLAG_NONE; + + } else if ( + (((Cert = GetValue(argc, argv, "file")) != nullptr) && + ((KeyFile = GetValue(argc, argv, "key")) != nullptr)) || + (((Cert = GetValue(argc, argv, "cert_file")) != nullptr) && + ((KeyFile = GetValue(argc, argv, "cert_key")) != nullptr))) { + Helper.CertFile.CertificateFile = (char*)Cert; + Helper.CertFile.PrivateKeyFile = (char*)KeyFile; + Helper.CredConfig.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE; + Helper.CredConfig.CertificateFile = &Helper.CertFile; + +#ifdef QUIC_TEST_APIS + } else if (GetValue(argc, argv, "selfsign")) { + Config = QuicPlatGetSelfSignedCert(QUIC_SELF_SIGN_CERT_USER); + if (!Config) { + return nullptr; + } +#endif + + } else { + return nullptr; + } + +#ifdef QUIC_TEST_APIS + void* Context = (Config != &Helper.CredConfig) ? (void*)Config : nullptr; +#else + void* Context = nullptr; +#endif + + HQUIC Configuration = nullptr; + if (QUIC_SUCCEEDED( + MsQuic->ConfigurationOpen( + Registration, + AlpnBuffers, + AlpnBufferCount, + Settings, + SettingsSize, + Context, + &Configuration)) && + QUIC_FAILED( + MsQuic->ConfigurationLoadCredential( + Configuration, + Config))) { + MsQuic->ConfigurationClose(Configuration); + Configuration = nullptr; + } + +#ifdef QUIC_TEST_APIS + if (!Configuration && Config != &Helper.CredConfig) { + QuicPlatFreeSelfSignedCert(Config); + } +#endif + + return Configuration; +} + +inline +void +FreeServerConfiguration( + _In_ const QUIC_API_TABLE* MsQuic, + _In_ HQUIC Configuration + ) +{ +#ifdef QUIC_TEST_APIS + auto SelfSignedConfig = (const QUIC_CREDENTIAL_CONFIG*)MsQuic->GetContext(Configuration); + if (SelfSignedConfig) { + QuicPlatFreeSelfSignedCert(SelfSignedConfig); + } #endif + MsQuic->ConfigurationClose(Configuration); +} + +#endif // defined(__cplusplus) diff --git a/src/inc/msquicp.h b/src/inc/msquicp.h index 6efdd49854..e812a543c6 100644 --- a/src/inc/msquicp.h +++ b/src/inc/msquicp.h @@ -23,16 +23,6 @@ extern "C" { typedef struct QUIC_RECV_DATAGRAM QUIC_RECV_DATAGRAM; typedef struct QUIC_DATAPATH_SEND_CONTEXT QUIC_DATAPATH_SEND_CONTEXT; -// -// Disables server certificate validation. -// Used with the QUIC_PARAM_CONN_CERT_VALIDATION_FLAGS parameter. -// -#define QUIC_CERTIFICATE_FLAG_DISABLE_CERT_VALIDATION 0x80000000 - -// -// The different private parameters for QUIC_PARAM_LEVEL_GLOBAL. -// - // // Returns TRUE to drop the packet. // @@ -68,28 +58,26 @@ typedef struct QUIC_TEST_DATAPATH_HOOKS { #define QUIC_TEST_DATAPATH_HOOKS_ENABLED 1 #endif -#define QUIC_PARAM_GLOBAL_TEST_DATAPATH_HOOKS 0x80000001 // QUIC_TEST_DATAPATH_HOOKS* +typedef struct QUIC_PRIVATE_TRANSPORT_PARAMETER { + uint16_t Type; + uint16_t Length; + _Field_size_(Length) + const uint8_t* Buffer; +} QUIC_PRIVATE_TRANSPORT_PARAMETER; // -// The different private parameters for QUIC_PARAM_LEVEL_SESSION. +// The different private parameters for QUIC_PARAM_LEVEL_GLOBAL. // -#define QUIC_PARAM_SESSION_ADD_RESUMPTION_STATE 0x80000001 // uint8_t* + +#define QUIC_PARAM_GLOBAL_TEST_DATAPATH_HOOKS 0x80000001 // QUIC_TEST_DATAPATH_HOOKS* // // The different private parameters for QUIC_PARAM_LEVEL_CONNECTION. // -typedef struct QUIC_PRIVATE_TRANSPORT_PARAMETER { - uint16_t Type; - uint16_t Length; - _Field_size_(Length) - const uint8_t* Buffer; -} QUIC_PRIVATE_TRANSPORT_PARAMETER; - -#define QUIC_PARAM_CONN_RESUMPTION_STATE 0x80000001 // uint8_t* -#define QUIC_PARAM_CONN_FORCE_KEY_UPDATE 0x80000002 // No payload -#define QUIC_PARAM_CONN_FORCE_CID_UPDATE 0x80000003 // No payload -#define QUIC_PARAM_CONN_TEST_TRANSPORT_PARAMETER 0x80000004 // QUIC_PRIVATE_TRANSPORT_PARAMETER +#define QUIC_PARAM_CONN_FORCE_KEY_UPDATE 0x80000001 // No payload +#define QUIC_PARAM_CONN_FORCE_CID_UPDATE 0x80000002 // No payload +#define QUIC_PARAM_CONN_TEST_TRANSPORT_PARAMETER 0x80000003 // QUIC_PRIVATE_TRANSPORT_PARAMETER #if defined(__cplusplus) } diff --git a/src/inc/quic_cert.h b/src/inc/quic_cert.h index c00ac4ffec..9717c3cb6b 100644 --- a/src/inc/quic_cert.h +++ b/src/inc/quic_cert.h @@ -15,17 +15,16 @@ #define SIZEOF_CERT_CHAIN_LIST_LENGTH 3 -typedef void QUIC_CERT; +typedef struct QUIC_CREDENTIAL_CONFIG QUIC_CREDENTIAL_CONFIG; +typedef void QUIC_CERTIFICATE; // // Gets the certificate from the input configuration. // QUIC_STATUS QuicCertCreate( - _In_ uint32_t Flags, - _In_opt_ void* CertConfig, - _In_opt_z_ const char* Principal, - _Out_ QUIC_CERT** NewCertificate + _In_ const QUIC_CREDENTIAL_CONFIG* CredConfig, + _Out_ QUIC_CERTIFICATE** NewCertificate ); // @@ -33,7 +32,7 @@ QuicCertCreate( // void QuicCertFree( - _In_ QUIC_CERT* Certificate + _In_ QUIC_CERTIFICATE* Certificate ); // @@ -43,7 +42,7 @@ QuicCertFree( _Success_(return != FALSE) BOOLEAN QuicCertSelect( - _In_opt_ QUIC_CERT* Certificate, + _In_opt_ QUIC_CERTIFICATE* Certificate, _In_reads_(SignatureAlgorithmsLength) const uint16_t *SignatureAlgorithms, _In_ size_t SignatureAlgorithmsLength, @@ -55,7 +54,7 @@ QuicCertSelect( // to a certificate object. // _Success_(return != NULL) -QUIC_CERT* +QUIC_CERTIFICATE* QuicCertParseChain( _In_ size_t ChainBufferLength, _In_reads_(ChainBufferLength) const uint8_t *ChainBuffer @@ -68,7 +67,7 @@ QuicCertParseChain( _Success_(return != 0) size_t QuicCertFormat( - _In_opt_ QUIC_CERT* Certificate, + _In_opt_ QUIC_CERTIFICATE* Certificate, _In_ size_t BufferLength, _Out_writes_to_(BufferLength, return) uint8_t* Buffer @@ -80,7 +79,7 @@ QuicCertFormat( _Success_(return != FALSE) BOOLEAN QuicCertValidateChain( - _In_ QUIC_CERT* Certificate, + _In_ QUIC_CERTIFICATE* Certificate, _In_opt_z_ const char* Host, _In_ uint32_t IgnoreFlags ); @@ -91,7 +90,7 @@ QuicCertValidateChain( _Success_(return != NULL) void* QuicCertGetPrivateKey( - _In_ QUIC_CERT* Certificate + _In_ QUIC_CERTIFICATE* Certificate ); // @@ -124,7 +123,7 @@ QuicCertSign( _Success_(return != FALSE) BOOLEAN QuicCertVerify( - _In_ QUIC_CERT* Certificate, + _In_ QUIC_CERTIFICATE* Certificate, _In_ const uint16_t SignatureAlgorithm, _In_reads_(CertListToBeSignedLength) const uint8_t *CertListToBeSigned, diff --git a/src/inc/quic_driver_helpers.h b/src/inc/quic_driver_helpers.h index 9ed716b7f0..06278cfa8b 100644 --- a/src/inc/quic_driver_helpers.h +++ b/src/inc/quic_driver_helpers.h @@ -146,7 +146,7 @@ class QuicDriverClient { public: QuicDriverClient() : DeviceHandle(INVALID_HANDLE_VALUE) { } bool Initialize( - _In_ QUIC_SEC_CONFIG_PARAMS* SecConfigParams, + _In_ QUIC_CERTIFICATE_HASH* CertHash, _In_z_ const char* DriverName ) { uint32_t Error; @@ -182,13 +182,13 @@ class QuicDriverClient { "CreateFile failed"); return false; } - if (!Run(IOCTL_QUIC_SEC_CONFIG, SecConfigParams->Thumbprint, sizeof(SecConfigParams->Thumbprint), 30000)) { + if (!Run(IOCTL_QUIC_SET_CERT_HASH, CertHash, sizeof(*CertHash), 30000)) { CloseHandle(DeviceHandle); DeviceHandle = INVALID_HANDLE_VALUE; QuicTraceEvent( LibraryError, "[ lib] ERROR, %s.", - "Run(IOCTL_QUIC_SEC_CONFIG) failed"); + "Run(IOCTL_QUIC_SET_CERT_HASH) failed"); return false; } return true; @@ -367,10 +367,10 @@ class QuicDriverService { class QuicDriverClient { public: bool Initialize( - _In_ QUIC_SEC_CONFIG_PARAMS* SecConfigParams, + _In_ QUIC_CERTIFICATE_HASH* CertHash, _In_z_ const char* DriverName ) { - UNREFERENCED_PARAMETER(SecConfigParams); + UNREFERENCED_PARAMETER(CertHash); UNREFERENCED_PARAMETER(DriverName); return false; } diff --git a/src/inc/quic_platform.h b/src/inc/quic_platform.h index 9af893a913..739839e483 100644 --- a/src/inc/quic_platform.h +++ b/src/inc/quic_platform.h @@ -253,3 +253,38 @@ QuicListPopEntry( #include "quic_hashtable.h" #include "quic_toeplitz.h" + +// +// Test Interface for loading a self-signed certificate. +// + +#ifdef QUIC_TEST_APIS + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef struct QUIC_CREDENTIAL_CONFIG QUIC_CREDENTIAL_CONFIG; + +typedef enum QUIC_SELF_SIGN_CERT_TYPE { + QUIC_SELF_SIGN_CERT_USER, + QUIC_SELF_SIGN_CERT_MACHINE +} QUIC_SELF_SIGN_CERT_TYPE; + +_IRQL_requires_max_(PASSIVE_LEVEL) +const QUIC_CREDENTIAL_CONFIG* +QuicPlatGetSelfSignedCert( + _In_ QUIC_SELF_SIGN_CERT_TYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +void +QuicPlatFreeSelfSignedCert( + _In_ const QUIC_CREDENTIAL_CONFIG* CredConfig + ); + +#if defined(__cplusplus) +} +#endif + +#endif // QUIC_TEST_APIS diff --git a/src/inc/quic_platform_linux.h b/src/inc/quic_platform_linux.h index 62717b0bbe..dc5b8aa1c6 100644 --- a/src/inc/quic_platform_linux.h +++ b/src/inc/quic_platform_linux.h @@ -756,37 +756,6 @@ QuicConvertFromMappedV6( _Out_ QUIC_ADDR* OutAddr ); -// -// Test Interface for loading a self-signed certificate. -// - -#ifdef QUIC_TEST_APIS - -typedef struct QUIC_SEC_CONFIG_PARAMS { - uint32_t Flags; - void* Certificate; - const char* Principal; -} QUIC_SEC_CONFIG_PARAMS; - -typedef enum QUIC_SELF_SIGN_CERT_TYPE { - QUIC_SELF_SIGN_CERT_USER, - QUIC_SELF_SIGN_CERT_MACHINE -} QUIC_SELF_SIGN_CERT_TYPE; - -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_SEC_CONFIG_PARAMS* -QuicPlatGetSelfSignedCert( - _In_ QUIC_SELF_SIGN_CERT_TYPE Type - ); - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicPlatFreeSelfSignedCert( - _In_ QUIC_SEC_CONFIG_PARAMS* Params - ); - -#endif // QUIC_TEST_APIS - #define QuicSetCurrentThreadProcessorAffinity(ProcessorIndex) QUIC_STATUS_SUCCESS #define QUIC_CPUID(FunctionId, eax, ebx, ecx, dx) diff --git a/src/inc/quic_platform_winuser.h b/src/inc/quic_platform_winuser.h index 86d20ddb83..441b524943 100644 --- a/src/inc/quic_platform_winuser.h +++ b/src/inc/quic_platform_winuser.h @@ -923,38 +923,6 @@ QuicSetCurrentThreadProcessorAffinity( #endif -// -// Test Interface for loading a self-signed certificate. -// - -#ifdef QUIC_TEST_APIS - -typedef struct QUIC_SEC_CONFIG_PARAMS { - uint32_t Flags; // QUIC_SEC_CONFIG_FLAGS - void* Certificate; - const char* Principal; - uint8_t Thumbprint[20]; -} QUIC_SEC_CONFIG_PARAMS; - -typedef enum QUIC_SELF_SIGN_CERT_TYPE { - QUIC_SELF_SIGN_CERT_USER, - QUIC_SELF_SIGN_CERT_MACHINE -} QUIC_SELF_SIGN_CERT_TYPE; - -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_SEC_CONFIG_PARAMS* -QuicPlatGetSelfSignedCert( - _In_ QUIC_SELF_SIGN_CERT_TYPE Type - ); - -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QuicPlatFreeSelfSignedCert( - _In_ QUIC_SEC_CONFIG_PARAMS* Params - ); - -#endif // QUIC_TEST_APIS - #ifdef _M_X64 #define QUIC_CPUID(FunctionId, eax, ebx, ecx, edx) \ int CpuInfo[4]; \ diff --git a/src/inc/quic_sal_stub.h b/src/inc/quic_sal_stub.h index 8c1492ec0c..4b73d34d66 100644 --- a/src/inc/quic_sal_stub.h +++ b/src/inc/quic_sal_stub.h @@ -182,6 +182,10 @@ #define __drv_aliasesMem #endif +#ifndef _Frees_ptr_ +#define _Frees_ptr_ +#endif + #ifndef _Frees_ptr_opt_ #define _Frees_ptr_opt_ #endif diff --git a/src/inc/quic_tls.h b/src/inc/quic_tls.h index ca81064d51..ec66994a52 100644 --- a/src/inc/quic_tls.h +++ b/src/inc/quic_tls.h @@ -21,8 +21,8 @@ extern "C" { #pragma warning(disable:4201) // nonstandard extension used: nameless struct/union #pragma warning(disable:4214) // nonstandard extension used: bit field types other than int +typedef struct QUIC_SEC_CONFIG QUIC_SEC_CONFIG; typedef struct QUIC_CONNECTION QUIC_CONNECTION; -typedef struct QUIC_TLS_SESSION QUIC_TLS_SESSION; typedef struct QUIC_TLS QUIC_TLS; #define TLS_EXTENSION_TYPE_APPLICATION_LAYER_PROTOCOL_NEGOTIATION 0x0010 // Host Byte Order @@ -67,13 +67,13 @@ typedef QUIC_TLS_RECEIVE_TP_CALLBACK *QUIC_TLS_RECEIVE_TP_CALLBACK_HANDLER; typedef _IRQL_requires_max_(PASSIVE_LEVEL) BOOLEAN -(QUIC_TLS_RECEIVE_RESUMPTION_CALLBACK)( +(QUIC_TLS_RECEIVE_TICKET_CALLBACK)( _In_ QUIC_CONNECTION* Connection, - _In_ uint16_t TicketLength, + _In_ uint32_t TicketLength, _In_reads_(TicketLength) const uint8_t* Ticket ); -typedef QUIC_TLS_RECEIVE_RESUMPTION_CALLBACK *QUIC_TLS_RECEIVE_RESUMPTION_CALLBACK_HANDLER; +typedef QUIC_TLS_RECEIVE_TICKET_CALLBACK *QUIC_TLS_RECEIVE_TICKET_CALLBACK_HANDLER; // // The input configuration for creation of a TLS context. @@ -83,9 +83,9 @@ typedef struct QUIC_TLS_CONFIG { BOOLEAN IsServer; // - // The TLS session. + // Connection context for completion callbacks. // - QUIC_TLS_SESSION* TlsSession; + QUIC_CONNECTION* Connection; // // The TLS configuration information and credentials. @@ -100,6 +100,18 @@ typedef struct QUIC_TLS_CONFIG { const uint8_t* AlpnBuffer; uint16_t AlpnBufferLength; + // + // Name of the server we are connecting to (client side only). + // + const char* ServerName; + + // + // The optional ticket buffer the client size uses to resume a previous + // session (client side only). + // + const uint8_t* ResumptionTicketBuffer; + uint32_t ResumptionTicketLength; + // // The local QUIC transport parameters to send. Buffer is freed by the TLS // context when it's no longer needed. @@ -107,30 +119,20 @@ typedef struct QUIC_TLS_CONFIG { const uint8_t* LocalTPBuffer; uint32_t LocalTPLength; - // - // Passed into completion callbacks. - // - QUIC_CONNECTION* Connection; - // // Invoked for the completion of process calls that were pending. // QUIC_TLS_PROCESS_COMPLETE_CALLBACK_HANDLER ProcessCompleteCallback; // - // Invoked when QUIC TP are received. + // Invoked when QUIC transport parameters are received. // QUIC_TLS_RECEIVE_TP_CALLBACK_HANDLER ReceiveTPCallback; // // Invoked when a resumption ticket is received. // - QUIC_TLS_RECEIVE_RESUMPTION_CALLBACK_HANDLER ReceiveResumptionCallback; - - // - // Name of the server we are connecting to (client side only). - // - const char* ServerName; + QUIC_TLS_RECEIVE_TICKET_CALLBACK_HANDLER ReceiveResumptionCallback; } QUIC_TLS_CONFIG; @@ -147,7 +149,6 @@ typedef enum QUIC_TLS_RESULT_FLAGS { QUIC_TLS_RESULT_EARLY_DATA_ACCEPT = 0x0020, // The server accepted the early (0-RTT) data. QUIC_TLS_RESULT_EARLY_DATA_REJECT = 0x0040, // The server rejected the early (0-RTT) data. QUIC_TLS_RESULT_COMPLETE = 0x0080, // Handshake complete. - QUIC_TLS_RESULT_TICKET = 0x0100, // Ticket Ready. QUIC_TLS_RESULT_ERROR = 0x8000 // An error occured. } QUIC_TLS_RESULT_FLAGS; @@ -257,89 +258,38 @@ typedef struct QUIC_TLS_PROCESS_STATE { } QUIC_TLS_PROCESS_STATE; -// -// Creates a new TLS security configuration. -// +typedef _IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicTlsServerSecConfigCreate( - _Inout_ QUIC_RUNDOWN_REF* Rundown, - _In_ QUIC_SEC_CONFIG_FLAGS Flags, - _In_opt_ void* Certificate, - _In_opt_z_ const char* Principal, +_Function_class_(QUIC_SEC_CONFIG_CREATE_COMPLETE) +void +(QUIC_API QUIC_SEC_CONFIG_CREATE_COMPLETE)( + _In_ const QUIC_CREDENTIAL_CONFIG* CredConfig, _In_opt_ void* Context, - _In_ QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER CompletionHandler - ); - -// -// Creates a new TLS security configuration for client use. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicTlsClientSecConfigCreate( - _In_ uint32_t Flags, - _Outptr_ QUIC_SEC_CONFIG** ClientConfig + _In_ QUIC_STATUS Status, + _In_opt_ QUIC_SEC_CONFIG* SecurityConfig ); -// -// Adds a reference to a TLS security configuration. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_SEC_CONFIG* -QuicTlsSecConfigAddRef( - _In_ QUIC_SEC_CONFIG* SecurityConfig - ); +typedef QUIC_SEC_CONFIG_CREATE_COMPLETE *QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER; // -// Releases a references on a TLS security configuration and cleans it up -// if it's the last reference. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -void -QUIC_API -QuicTlsSecConfigRelease( - _In_ QUIC_SEC_CONFIG* SecurityConfig - ); - -// -// Initializes a TLS session. +// Creates a new TLS security configuration. // _IRQL_requires_max_(PASSIVE_LEVEL) QUIC_STATUS -QuicTlsSessionInitialize( - _Out_ QUIC_TLS_SESSION** NewTlsSession +QuicTlsSecConfigCreate( + _In_ const QUIC_CREDENTIAL_CONFIG* CredConfig, + _In_opt_ void* Context, + _In_ QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER CompletionHandler ); // -// Uninitializes a TLS session. +// Deletes a TLS security configuration. // _IRQL_requires_max_(PASSIVE_LEVEL) void -QuicTlsSessionUninitialize( - _In_opt_ QUIC_TLS_SESSION* TlsSession - ); - -// -// Configures the 0-RTT ticket key (server side). -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicTlsSessionSetTicketKey( - _In_ QUIC_TLS_SESSION* TlsSession, - _In_reads_bytes_(44) - const void* Buffer - ); - -// -// Adds a new ticket to the ticket store, from a contiguous buffer. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicTlsSessionAddTicket( - _In_ QUIC_TLS_SESSION* TlsSession, - _In_ uint32_t BufferLength, - _In_reads_bytes_(BufferLength) - const uint8_t * const Buffer +QuicTlsSecConfigDelete( + __drv_freesMem(ServerConfig) _Frees_ptr_ _In_ + QUIC_SEC_CONFIG* SecurityConfig ); // @@ -371,16 +321,6 @@ QuicTlsReset( _In_ QUIC_TLS* TlsContext ); -// -// Returns the security configuration used to initialize this TLS. -// Caller must release the ref on the QUIC_SEC_CONFIG. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_SEC_CONFIG* -QuicTlsGetSecConfig( - _In_ QUIC_TLS* TlsContext - ); - // // Called to process any data received from the peer. In the case of the client, // the initial call is made with no input buffer to generate the initial output. @@ -412,18 +352,6 @@ QuicTlsProcessDataComplete( _Out_ uint32_t * ConsumedBuffer ); -// -// Called to read a TLS ticket. -// -_IRQL_requires_max_(PASSIVE_LEVEL) -QUIC_STATUS -QuicTlsReadTicket( - _In_ QUIC_TLS* TlsContext, - _Inout_ uint32_t* BufferLength, - _Out_writes_bytes_opt_(*BufferLength) - uint8_t* Buffer - ); - // // Sets a TLS parameter. // @@ -467,7 +395,7 @@ QuicTlsAlpnFindInList( ) { while (AlpnListLength != 0) { - QUIC_ANALYSIS_ASSUME(AlpnList[0] + 1 <= AlpnListLength); + QUIC_DBG_ASSERT(AlpnList[0] + 1 <= AlpnListLength); if (AlpnList[0] == FindAlpnLength && memcmp(AlpnList+1, FindAlpn, FindAlpnLength) == 0) { return AlpnList; diff --git a/src/inc/quic_trace.h b/src/inc/quic_trace.h index 0ac7a25742..a11f674d1f 100644 --- a/src/inc/quic_trace.h +++ b/src/inc/quic_trace.h @@ -72,11 +72,10 @@ typedef enum QUIC_TRACE_API_TYPE { QUIC_TRACE_API_GET_PARAM, QUIC_TRACE_API_REGISTRATION_OPEN, QUIC_TRACE_API_REGISTRATION_CLOSE, - QUIC_TRACE_API_SEC_CONFIG_CREATE, - QUIC_TRACE_API_SEC_CONFIG_DELETE, - QUIC_TRACE_API_SESSION_OPEN, - QUIC_TRACE_API_SESSION_CLOSE, - QUIC_TRACE_API_SESSION_SHUTDOWN, + QUIC_TRACE_API_REGISTRATION_SHUTDOWN, + QUIC_TRACE_API_CONFIGURATION_OPEN, + QUIC_TRACE_API_CONFIGURATION_CLOSE, + QUIC_TRACE_API_CONFIGURATION_LOAD_CREDENTIAL, QUIC_TRACE_API_LISTENER_OPEN, QUIC_TRACE_API_LISTENER_CLOSE, QUIC_TRACE_API_LISTENER_START, @@ -85,6 +84,7 @@ typedef enum QUIC_TRACE_API_TYPE { QUIC_TRACE_API_CONNECTION_CLOSE, QUIC_TRACE_API_CONNECTION_SHUTDOWN, QUIC_TRACE_API_CONNECTION_START, + QUIC_TRACE_API_CONNECTION_SET_CONFIGURATION, QUIC_TRACE_API_CONNECTION_SEND_RESUMPTION_TICKET, QUIC_TRACE_API_STREAM_OPEN, QUIC_TRACE_API_STREAM_CLOSE, @@ -93,7 +93,8 @@ typedef enum QUIC_TRACE_API_TYPE { QUIC_TRACE_API_STREAM_SEND, QUIC_TRACE_API_STREAM_RECEIVE_COMPLETE, QUIC_TRACE_API_STREAM_RECEIVE_SET_ENABLED, - QUIC_TRACE_API_DATAGRAM_SEND + QUIC_TRACE_API_DATAGRAM_SEND, + QUIC_TRACE_API_COUNT // Must be last } QUIC_TRACE_API_TYPE; typedef enum QUIC_TRACE_LEVEL { diff --git a/src/manifest/MsQuicEtw.man b/src/manifest/MsQuicEtw.man index de8c35518a..15b0719817 100644 --- a/src/manifest/MsQuicEtw.man +++ b/src/manifest/MsQuicEtw.man @@ -23,8 +23,8 @@ /> + -