From 493e4e16b85f2e24ad7120080ca1c96352d3ee8e Mon Sep 17 00:00:00 2001 From: seantywork Date: Tue, 1 Jul 2025 10:26:16 +0900 Subject: [PATCH] quic 2.5 --- quic-bench/quic/Makefile | 5 +- quic-bench/quic/client.c | 365 ------------------------ quic-bench/quic/{server.c => quic.c} | 296 ++++++++++++++++++- quic-bench/quic/{quic_core.h => quic.h} | 24 +- 4 files changed, 315 insertions(+), 375 deletions(-) delete mode 100644 quic-bench/quic/client.c rename quic-bench/quic/{server.c => quic.c} (54%) rename quic-bench/quic/{quic_core.h => quic.h} (65%) diff --git a/quic-bench/quic/Makefile b/quic-bench/quic/Makefile index 6ca2807..f24146e 100644 --- a/quic-bench/quic/Makefile +++ b/quic-bench/quic/Makefile @@ -11,10 +11,7 @@ LIBS := -lcore -lmsquic -lmsquic_platform -lssl -lcrypto all: - - gcc $(FLAGS) $(INCLUDES) $(LINKS) -o client.out client.c $(LIBS) - - gcc $(FLAGS) $(INCLUDES) $(LINKS) -o server.out server.c $(LIBS) + gcc $(FLAGS) $(INCLUDES) $(LINKS) -o quic.out quic.c $(LIBS) clean: diff --git a/quic-bench/quic/client.c b/quic-bench/quic/client.c deleted file mode 100644 index 591d9a0..0000000 --- a/quic-bench/quic/client.c +++ /dev/null @@ -1,365 +0,0 @@ - -#include "quic_core.h" - - -QUIC_REGISTRATION_CONFIG quic_reg_config = { "quicsample", QUIC_EXECUTION_PROFILE_LOW_LATENCY }; - -QUIC_BUFFER quic_alpn = { sizeof("sample") - 1, (uint8_t*)"sample" }; - -uint16_t quic_udp_port = 4567; - -uint64_t quic_idle_timeoutms = 1000; - -uint32_t quic_send_buffer_len = 100; - -QUIC_API_TABLE* quic_api; - - -HQUIC quic_registration; - - -HQUIC quic_configuration; - -QUIC_TLS_SECRETS quic_client_secrets = {0}; - - -char* quic_ssl_keylog_env = "SSLKEYLOGFILE"; - - -_IRQL_requires_max_(DISPATCH_LEVEL) -_Function_class_(QUIC_STREAM_CALLBACK) -QUIC_STATUS -QUIC_API -ClientStreamCallback( - _In_ HQUIC Stream, - _In_opt_ void* Context, - _Inout_ QUIC_STREAM_EVENT* Event - ) -{ - UNREFERENCED_PARAMETER(Context); - switch (Event->Type) { - case QUIC_STREAM_EVENT_SEND_COMPLETE: - // - // A previous StreamSend call has completed, and the context is being - // returned back to the app. - // - free(Event->SEND_COMPLETE.ClientContext); - printf("[strm][%p] Data sent\n", Stream); - break; - case QUIC_STREAM_EVENT_RECEIVE: - // - // Data was received from the peer on the stream. - // - printf("[strm][%p] Data received\n", Stream); - break; - case QUIC_STREAM_EVENT_PEER_SEND_ABORTED: - // - // The peer gracefully shut down its send direction of the stream. - // - printf("[strm][%p] Peer aborted\n", Stream); - break; - case QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN: - // - // The peer aborted its send direction of the stream. - // - printf("[strm][%p] Peer shut down\n", Stream); - break; - case QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE: - // - // Both directions of the stream have been shut down and quic_api is done - // with the stream. It can now be safely cleaned up. - // - printf("[strm][%p] All done\n", Stream); - if (!Event->SHUTDOWN_COMPLETE.AppCloseInProgress) { - quic_api->StreamClose(Stream); - } - break; - default: - break; - } - return QUIC_STATUS_SUCCESS; -} - -void -ClientSend( - _In_ HQUIC Connection - ) -{ - QUIC_STATUS Status; - HQUIC Stream = NULL; - uint8_t* SendBufferRaw; - QUIC_BUFFER* SendBuffer; - - // - // Create/allocate a new bidirectional stream. The stream is just allocated - // and no QUIC stream identifier is assigned until it's started. - // - if (QUIC_FAILED(Status = quic_api->StreamOpen(Connection, QUIC_STREAM_OPEN_FLAG_NONE, ClientStreamCallback, NULL, &Stream))) { - printf("StreamOpen failed, 0x%x!\n", Status); - goto Error; - } - - printf("[strm][%p] Starting...\n", Stream); - - // - // Starts the bidirectional stream. By default, the peer is not notified of - // the stream being started until data is sent on the stream. - // - if (QUIC_FAILED(Status = quic_api->StreamStart(Stream, QUIC_STREAM_START_FLAG_NONE))) { - printf("StreamStart failed, 0x%x!\n", Status); - quic_api->StreamClose(Stream); - goto Error; - } - - // - // Allocates and builds the buffer to send over the stream. - // - SendBufferRaw = (uint8_t*)malloc(sizeof(QUIC_BUFFER) + quic_send_buffer_len); - if (SendBufferRaw == NULL) { - printf("SendBuffer allocation failed!\n"); - Status = QUIC_STATUS_OUT_OF_MEMORY; - goto Error; - } - SendBuffer = (QUIC_BUFFER*)SendBufferRaw; - SendBuffer->Buffer = SendBufferRaw + sizeof(QUIC_BUFFER); - SendBuffer->Length = quic_send_buffer_len; - - printf("[strm][%p] Sending data...\n", Stream); - - // - // Sends the buffer over the stream. Note the FIN flag is passed along with - // the buffer. This indicates this is the last buffer on the stream and the - // the stream is shut down (in the send direction) immediately after. - // - if (QUIC_FAILED(Status = quic_api->StreamSend(Stream, SendBuffer, 1, QUIC_SEND_FLAG_FIN, SendBuffer))) { - printf("StreamSend failed, 0x%x!\n", Status); - free(SendBufferRaw); - goto Error; - } - -Error: - - if (QUIC_FAILED(Status)) { - quic_api->ConnectionShutdown(Connection, QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0); - } -} - -// -// The clients's callback for connection events from quic_api. -// -_IRQL_requires_max_(DISPATCH_LEVEL) -_Function_class_(QUIC_CONNECTION_CALLBACK) -QUIC_STATUS -QUIC_API -ClientConnectionCallback( - _In_ HQUIC Connection, - _In_opt_ void* Context, - _Inout_ QUIC_CONNECTION_EVENT* Event - ) -{ - UNREFERENCED_PARAMETER(Context); - - if (Event->Type == QUIC_CONNECTION_EVENT_CONNECTED) { - - printf("client: quic event connected\n"); - } - - switch (Event->Type) { - case QUIC_CONNECTION_EVENT_CONNECTED: - // - // The handshake has completed for the connection. - // - printf("[conn][%p] Connected\n", Connection); - ClientSend(Connection); - break; - case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT: - // - // The connection has been shut down by the transport. Generally, this - // is the expected way for the connection to shut down with this - // protocol, since we let idle timeout kill the connection. - // - if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_IDLE) { - printf("[conn][%p] Successfully shut down on idle.\n", Connection); - } else { - printf("[conn][%p] Shut down by transport, 0x%x\n", Connection, Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status); - } - break; - case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER: - // - // The connection was explicitly shut down by the peer. - // - printf("[conn][%p] Shut down by peer, 0x%llu\n", Connection, (unsigned long long)Event->SHUTDOWN_INITIATED_BY_PEER.ErrorCode); - break; - case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE: - // - // The connection has completed the shutdown process and is ready to be - // safely cleaned up. - // - printf("[conn][%p] All done\n", Connection); - if (!Event->SHUTDOWN_COMPLETE.AppCloseInProgress) { - quic_api->ConnectionClose(Connection); - } - break; - case QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED: - // - // A resumption ticket (also called New Session Ticket or NST) was - // received from the server. - // - printf("[conn][%p] Resumption ticket received (%u bytes):\n", Connection, Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength); - for (uint32_t i = 0; i < Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength; i++) { - printf("%.2X", (uint8_t)Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicket[i]); - } - printf("\n"); - break; - default: - break; - } - return QUIC_STATUS_SUCCESS; -} - -// -// Helper function to load a client configuration. -// -BOOLEAN ClientLoadConfiguration() -{ - QUIC_SETTINGS Settings = {0}; - // - // Configures the client's idle timeout. - // - Settings.IdleTimeoutMs = quic_idle_timeoutms; - Settings.IsSet.IdleTimeoutMs = TRUE; - - // - // Configures a default client configuration, optionally disabling - // server certificate validation. - // - QUIC_CREDENTIAL_CONFIG Config; - memset(&Config, 0, sizeof(Config)); - Config.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE; - Config.Flags = QUIC_CREDENTIAL_FLAG_CLIENT; - -// const char* Ca = "certs/ca.pem"; - const char* Cert = "certs/client.crt.pem"; - const char* Key = "certs/client.key.pem"; - -// Config.CaCertificateFile = Ca; - - QUIC_CERTIFICATE_FILE CertFile; - CertFile.CertificateFile = (char*)Cert; - CertFile.PrivateKeyFile = (char*)Key; - Config.CertificateFile = &CertFile; - - // - // Allocate/initialize the configuration object, with the configured ALPN - // and settings. - // - QUIC_STATUS Status = QUIC_STATUS_SUCCESS; - if (QUIC_FAILED(Status = quic_api->ConfigurationOpen(quic_registration, &quic_alpn, 1, &Settings, sizeof(Settings), NULL, &quic_configuration))) { - printf("ConfigurationOpen failed, 0x%x!\n", Status); - return FALSE; - } - - // - // Loads the TLS credential part of the configuration. This is required even - // on client side, to indicate if a certificate is required or not. - // - if (QUIC_FAILED(Status = quic_api->ConfigurationLoadCredential(quic_configuration, &Config))) { - printf("ConfigurationLoadCredential failed, 0x%x!\n", Status); - return FALSE; - } - - return TRUE; -} - -// -// Runs the client side of the protocol. -// -void RunClient() { - // - // Load the client configuration based on the "unsecure" command line option. - // - if (!ClientLoadConfiguration()) { - return; - } - - QUIC_STATUS Status; - const char* ResumptionTicketString = NULL; - const char* SslKeyLogFile = getenv(quic_ssl_keylog_env); - HQUIC Connection = NULL; - - // - // Allocate a new connection object. - // - if (QUIC_FAILED(Status = quic_api->ConnectionOpen(quic_registration, ClientConnectionCallback, NULL, &Connection))) { - printf("ConnectionOpen failed, 0x%x!\n", Status); - goto Error; - } - - // - // Get the target / server name or IP from the command line. - // - const char* Target = "localhost"; - - printf("[conn][%p] Connecting...\n", Connection); - - // - // Start the connection to the server. - // - if (QUIC_FAILED(Status = quic_api->ConnectionStart(Connection, quic_configuration, QUIC_ADDRESS_FAMILY_UNSPEC, Target, quic_udp_port))) { - printf("ConnectionStart failed, 0x%x!\n", Status); - goto Error; - } - -Error: - - if (QUIC_FAILED(Status) && Connection != NULL) { - quic_api->ConnectionClose(Connection); - } -} - -int -QUIC_MAIN_EXPORT -main( - _In_ int argc, - _In_reads_(argc) _Null_terminated_ char* argv[] - ) -{ - QUIC_STATUS Status = QUIC_STATUS_SUCCESS; - - // - // Open a handle to the library and get the API function table. - // - if (QUIC_FAILED(Status = MsQuicOpen2(&quic_api))) { - printf("MsQuicOpen2 failed, 0x%x!\n", Status); - goto Error; - } - - // - // Create a registration for the app's connections. - // - if (QUIC_FAILED(Status = quic_api->RegistrationOpen(&quic_reg_config, &quic_registration))) { - printf("RegistrationOpen failed, 0x%x!\n", Status); - goto Error; - } - - RunClient(); - - -Error: - - if (quic_api != NULL) { - if (quic_configuration != NULL) { - quic_api->ConfigurationClose(quic_configuration); - } - if (quic_registration != NULL) { - // - // This will block until all outstanding child objects have been - // closed. - // - quic_api->RegistrationClose(quic_registration); - } - MsQuicClose(quic_api); - } - - return (int)Status; -} \ No newline at end of file diff --git a/quic-bench/quic/server.c b/quic-bench/quic/quic.c similarity index 54% rename from quic-bench/quic/server.c rename to quic-bench/quic/quic.c index 86a19e8..84231e9 100644 --- a/quic-bench/quic/server.c +++ b/quic-bench/quic/quic.c @@ -1,5 +1,5 @@ -#include "quic_core.h" +#include "quic.h" QUIC_REGISTRATION_CONFIG quic_reg_config = { "quicsample", QUIC_EXECUTION_PROFILE_LOW_LATENCY }; @@ -329,6 +329,297 @@ Error: +_IRQL_requires_max_(DISPATCH_LEVEL) +_Function_class_(QUIC_STREAM_CALLBACK) +QUIC_STATUS +QUIC_API +ClientStreamCallback( + _In_ HQUIC Stream, + _In_opt_ void* Context, + _Inout_ QUIC_STREAM_EVENT* Event + ) +{ + UNREFERENCED_PARAMETER(Context); + switch (Event->Type) { + case QUIC_STREAM_EVENT_SEND_COMPLETE: + // + // A previous StreamSend call has completed, and the context is being + // returned back to the app. + // + free(Event->SEND_COMPLETE.ClientContext); + printf("[strm][%p] Data sent\n", Stream); + break; + case QUIC_STREAM_EVENT_RECEIVE: + // + // Data was received from the peer on the stream. + // + printf("[strm][%p] Data received\n", Stream); + break; + case QUIC_STREAM_EVENT_PEER_SEND_ABORTED: + // + // The peer gracefully shut down its send direction of the stream. + // + printf("[strm][%p] Peer aborted\n", Stream); + break; + case QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN: + // + // The peer aborted its send direction of the stream. + // + printf("[strm][%p] Peer shut down\n", Stream); + break; + case QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE: + // + // Both directions of the stream have been shut down and quic_api is done + // with the stream. It can now be safely cleaned up. + // + printf("[strm][%p] All done\n", Stream); + if (!Event->SHUTDOWN_COMPLETE.AppCloseInProgress) { + quic_api->StreamClose(Stream); + } + break; + default: + break; + } + return QUIC_STATUS_SUCCESS; +} + +void +ClientSend( + _In_ HQUIC Connection + ) +{ + QUIC_STATUS Status; + HQUIC Stream = NULL; + uint8_t* SendBufferRaw; + QUIC_BUFFER* SendBuffer; + + // + // Create/allocate a new bidirectional stream. The stream is just allocated + // and no QUIC stream identifier is assigned until it's started. + // + if (QUIC_FAILED(Status = quic_api->StreamOpen(Connection, QUIC_STREAM_OPEN_FLAG_NONE, ClientStreamCallback, NULL, &Stream))) { + printf("StreamOpen failed, 0x%x!\n", Status); + goto Error; + } + + printf("[strm][%p] Starting...\n", Stream); + + // + // Starts the bidirectional stream. By default, the peer is not notified of + // the stream being started until data is sent on the stream. + // + if (QUIC_FAILED(Status = quic_api->StreamStart(Stream, QUIC_STREAM_START_FLAG_NONE))) { + printf("StreamStart failed, 0x%x!\n", Status); + quic_api->StreamClose(Stream); + goto Error; + } + + // + // Allocates and builds the buffer to send over the stream. + // + SendBufferRaw = (uint8_t*)malloc(sizeof(QUIC_BUFFER) + quic_send_buffer_len); + if (SendBufferRaw == NULL) { + printf("SendBuffer allocation failed!\n"); + Status = QUIC_STATUS_OUT_OF_MEMORY; + goto Error; + } + SendBuffer = (QUIC_BUFFER*)SendBufferRaw; + SendBuffer->Buffer = SendBufferRaw + sizeof(QUIC_BUFFER); + SendBuffer->Length = quic_send_buffer_len; + + printf("[strm][%p] Sending data...\n", Stream); + + // + // Sends the buffer over the stream. Note the FIN flag is passed along with + // the buffer. This indicates this is the last buffer on the stream and the + // the stream is shut down (in the send direction) immediately after. + // + if (QUIC_FAILED(Status = quic_api->StreamSend(Stream, SendBuffer, 1, QUIC_SEND_FLAG_FIN, SendBuffer))) { + printf("StreamSend failed, 0x%x!\n", Status); + free(SendBufferRaw); + goto Error; + } + +Error: + + if (QUIC_FAILED(Status)) { + quic_api->ConnectionShutdown(Connection, QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0); + } +} + +// +// The clients's callback for connection events from quic_api. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +_Function_class_(QUIC_CONNECTION_CALLBACK) +QUIC_STATUS +QUIC_API +ClientConnectionCallback( + _In_ HQUIC Connection, + _In_opt_ void* Context, + _Inout_ QUIC_CONNECTION_EVENT* Event + ) +{ + UNREFERENCED_PARAMETER(Context); + + if (Event->Type == QUIC_CONNECTION_EVENT_CONNECTED) { + + printf("client: quic event connected\n"); + } + + switch (Event->Type) { + case QUIC_CONNECTION_EVENT_CONNECTED: + // + // The handshake has completed for the connection. + // + printf("[conn][%p] Connected\n", Connection); + ClientSend(Connection); + break; + case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT: + // + // The connection has been shut down by the transport. Generally, this + // is the expected way for the connection to shut down with this + // protocol, since we let idle timeout kill the connection. + // + if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_IDLE) { + printf("[conn][%p] Successfully shut down on idle.\n", Connection); + } else { + printf("[conn][%p] Shut down by transport, 0x%x\n", Connection, Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status); + } + break; + case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER: + // + // The connection was explicitly shut down by the peer. + // + printf("[conn][%p] Shut down by peer, 0x%llu\n", Connection, (unsigned long long)Event->SHUTDOWN_INITIATED_BY_PEER.ErrorCode); + break; + case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE: + // + // The connection has completed the shutdown process and is ready to be + // safely cleaned up. + // + printf("[conn][%p] All done\n", Connection); + if (!Event->SHUTDOWN_COMPLETE.AppCloseInProgress) { + quic_api->ConnectionClose(Connection); + } + break; + case QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED: + // + // A resumption ticket (also called New Session Ticket or NST) was + // received from the server. + // + printf("[conn][%p] Resumption ticket received (%u bytes):\n", Connection, Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength); + for (uint32_t i = 0; i < Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength; i++) { + printf("%.2X", (uint8_t)Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicket[i]); + } + printf("\n"); + break; + default: + break; + } + return QUIC_STATUS_SUCCESS; +} + +// +// Helper function to load a client configuration. +// +BOOLEAN ClientLoadConfiguration() +{ + QUIC_SETTINGS Settings = {0}; + // + // Configures the client's idle timeout. + // + Settings.IdleTimeoutMs = quic_idle_timeoutms; + Settings.IsSet.IdleTimeoutMs = TRUE; + + // + // Configures a default client configuration, optionally disabling + // server certificate validation. + // + QUIC_CREDENTIAL_CONFIG Config; + memset(&Config, 0, sizeof(Config)); + Config.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE; + Config.Flags = QUIC_CREDENTIAL_FLAG_CLIENT; + +// const char* Ca = "certs/ca.pem"; + const char* Cert = "certs/client.crt.pem"; + const char* Key = "certs/client.key.pem"; + +// Config.CaCertificateFile = Ca; + + QUIC_CERTIFICATE_FILE CertFile; + CertFile.CertificateFile = (char*)Cert; + CertFile.PrivateKeyFile = (char*)Key; + Config.CertificateFile = &CertFile; + + // + // Allocate/initialize the configuration object, with the configured ALPN + // and settings. + // + QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + if (QUIC_FAILED(Status = quic_api->ConfigurationOpen(quic_registration, &quic_alpn, 1, &Settings, sizeof(Settings), NULL, &quic_configuration))) { + printf("ConfigurationOpen failed, 0x%x!\n", Status); + return FALSE; + } + + // + // Loads the TLS credential part of the configuration. This is required even + // on client side, to indicate if a certificate is required or not. + // + if (QUIC_FAILED(Status = quic_api->ConfigurationLoadCredential(quic_configuration, &Config))) { + printf("ConfigurationLoadCredential failed, 0x%x!\n", Status); + return FALSE; + } + + return TRUE; +} + +// +// Runs the client side of the protocol. +// +void RunClient() { + // + // Load the client configuration based on the "unsecure" command line option. + // + if (!ClientLoadConfiguration()) { + return; + } + + QUIC_STATUS Status; + const char* ResumptionTicketString = NULL; + const char* SslKeyLogFile = getenv(quic_ssl_keylog_env); + HQUIC Connection = NULL; + + // + // Allocate a new connection object. + // + if (QUIC_FAILED(Status = quic_api->ConnectionOpen(quic_registration, ClientConnectionCallback, NULL, &Connection))) { + printf("ConnectionOpen failed, 0x%x!\n", Status); + goto Error; + } + + // + // Get the target / server name or IP from the command line. + // + const char* Target = "localhost"; + + printf("[conn][%p] Connecting...\n", Connection); + + // + // Start the connection to the server. + // + if (QUIC_FAILED(Status = quic_api->ConnectionStart(Connection, quic_configuration, QUIC_ADDRESS_FAMILY_UNSPEC, Target, quic_udp_port))) { + printf("ConnectionStart failed, 0x%x!\n", Status); + goto Error; + } + +Error: + + if (QUIC_FAILED(Status) && Connection != NULL) { + quic_api->ConnectionClose(Connection); + } +} + int QUIC_MAIN_EXPORT main( @@ -354,7 +645,8 @@ main( goto Error; } - RunServer(); + RunClient(); + Error: diff --git a/quic-bench/quic/quic_core.h b/quic-bench/quic/quic.h similarity index 65% rename from quic-bench/quic/quic_core.h rename to quic-bench/quic/quic.h index 8ac72b1..3a1c1da 100644 --- a/quic-bench/quic/quic_core.h +++ b/quic-bench/quic/quic.h @@ -1,9 +1,25 @@ -#ifndef _SOCK_QUIC_H_ -#define _SOCK_QUIC_H_ +#ifndef _BENCH_QUIC_H_ +#define _BENCH_QUIC_H_ #include "msquic.h" -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifndef UNREFERENCED_PARAMETER #define UNREFERENCED_PARAMETER(P) (void)(P) -- 2.43.0