From: seantywork Date: Tue, 1 Jul 2025 01:16:59 +0000 (+0900) Subject: quic 2.5 X-Git-Url: https://git.feebdaed.xyz/?a=commitdiff_plain;h=763a1a09da09a54c5af96dcfdd6ad4bec83049cb;p=linuxyz.git quic 2.5 --- diff --git a/quic-bench/2506-04.xyz.md b/quic-bench/2506-04.xyz.md new file mode 100644 index 0000000..792d600 --- /dev/null +++ b/quic-bench/2506-04.xyz.md @@ -0,0 +1 @@ +# diff --git a/quic-bench/quic/.gitignore b/quic-bench/quic/.gitignore new file mode 100644 index 0000000..51caa86 --- /dev/null +++ b/quic-bench/quic/.gitignore @@ -0,0 +1,2 @@ +msquic +certs \ No newline at end of file diff --git a/quic-bench/quic/Makefile b/quic-bench/quic/Makefile new file mode 100644 index 0000000..6ca2807 --- /dev/null +++ b/quic-bench/quic/Makefile @@ -0,0 +1,21 @@ + + +FLAGS := -Wall -O2 -g + +INCLUDES := -Imsquic/src/inc -Imsquic/build/_deps/opensslquic-build/quictls/include -I. + +LINKS := -Lmsquic/build/obj/Release -Lmsquic/build/bin/Release -Wl,-rpath=msquic/build/bin/Release +LINKS += -Lmsquic/build/_deps/opensslquic-build/quictls/lib -Lmsquic/build/_deps/opensslquic-build/submodules/quictls + +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) + +clean: + + rm -rf *.o *.out \ No newline at end of file diff --git a/quic-bench/quic/certgen.sh b/quic-bench/quic/certgen.sh new file mode 100755 index 0000000..902992a --- /dev/null +++ b/quic-bench/quic/certgen.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +rm -r ./certs/* + +mkdir -p ./certs + +echo "root generating...." + +openssl genrsa -out ./certs/ca_priv.pem 4096 + +openssl rsa -in ./certs/ca_priv.pem -outform PEM -pubout -out ./certs/ca_pub.pem + +openssl req -x509 -new -key ./certs/ca_priv.pem -days 3650 -out ./certs/ca.pem -subj "/CN=quicroot" + +echo "server key pair, csr generating...." + +openssl genrsa -out ./certs/server.key.pem 4096 + +openssl rsa -in ./certs/server.key.pem -outform PEM -pubout -out ./certs/server.pub.pem + +openssl req -key ./certs/server.key.pem -new -sha256 -out ./certs/server.csr -subj "/CN=quichbench" + +echo "client key pair, csr generating...." + +openssl genrsa -out ./certs/client.key.pem 4096 + +openssl rsa -in ./certs/client.key.pem -outform PEM -pubout -out ./certs/client.pub.pem + +openssl req -key ./certs/client.key.pem -new -sha256 -out ./certs/client.csr -subj "/CN=client" + + +echo "signing requests for server...." + +openssl x509 -req -extfile <(printf "subjectAltName = DNS:quicbench") -days 365 -in ./certs/server.csr -CA ./certs/ca.pem -CAkey ./certs/ca_priv.pem -CAcreateserial -sha256 -out ./certs/server.crt.pem + +echo "signing requests for client...." + +openssl x509 -req -extfile <(printf "subjectAltName = DNS:client") -days 365 -in ./certs/client.csr -CA ./certs/ca.pem -CAkey ./certs/ca_priv.pem -CAcreateserial -sha256 -out ./certs/client.crt.pem + +sudo /bin/cp -Rf ./certs/ca.pem /usr/local/share/ca-certificates/quicroot.crt + +sudo update-ca-certificates + +echo "done!" \ No newline at end of file diff --git a/quic-bench/quic/client.c b/quic-bench/quic/client.c new file mode 100644 index 0000000..591d9a0 --- /dev/null +++ b/quic-bench/quic/client.c @@ -0,0 +1,365 @@ + +#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/quic_core.h b/quic-bench/quic/quic_core.h new file mode 100644 index 0000000..8ac72b1 --- /dev/null +++ b/quic-bench/quic/quic_core.h @@ -0,0 +1,48 @@ +#ifndef _SOCK_QUIC_H_ +#define _SOCK_QUIC_H_ + +#include "msquic.h" +#include +#include + +#ifndef UNREFERENCED_PARAMETER +#define UNREFERENCED_PARAMETER(P) (void)(P) +#endif + + +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_CERTIFICATE_FILE_PROTECTED CertFileProtected; + }; +} QUIC_CREDENTIAL_CONFIG_HELPER; + + + +extern QUIC_REGISTRATION_CONFIG quic_req_config; + +extern QUIC_BUFFER quic_alpn; + +extern uint16_t quic_udp_port; + +extern uint64_t quic_idle_timeoutms; + +extern uint32_t quic_send_buffer_len; + +extern QUIC_API_TABLE* quic_api; + +extern HQUIC quic_registration; + +extern HQUIC quic_configuration; + +extern QUIC_TLS_SECRETS quic_client_secrets; + +extern char* quic_ssl_keylog_env; + + + + +#endif \ No newline at end of file diff --git a/quic-bench/quic/server.c b/quic-bench/quic/server.c new file mode 100644 index 0000000..86a19e8 --- /dev/null +++ b/quic-bench/quic/server.c @@ -0,0 +1,376 @@ + +#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"; + + +void +ServerSend( + _In_ HQUIC Stream + ) +{ + // + // Allocates and builds the buffer to send over the stream. + // + void* SendBufferRaw = malloc(sizeof(QUIC_BUFFER) + quic_send_buffer_len); + if (SendBufferRaw == NULL) { + printf("SendBuffer allocation failed!\n"); + quic_api->StreamShutdown(Stream, QUIC_STREAM_SHUTDOWN_FLAG_ABORT, 0); + return; + } + QUIC_BUFFER* SendBuffer = (QUIC_BUFFER*)SendBufferRaw; + SendBuffer->Buffer = (uint8_t*)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. + // + QUIC_STATUS Status; + if (QUIC_FAILED(Status = quic_api->StreamSend(Stream, SendBuffer, 1, QUIC_SEND_FLAG_FIN, SendBuffer))) { + printf("StreamSend failed, 0x%x!\n", Status); + free(SendBufferRaw); + quic_api->StreamShutdown(Stream, QUIC_STREAM_SHUTDOWN_FLAG_ABORT, 0); + } +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +_Function_class_(QUIC_STREAM_CALLBACK) +QUIC_STATUS +QUIC_API +ServerStreamCallback( + _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_SHUTDOWN: + // + // The peer gracefully shut down its send direction of the stream. + // + printf("[strm][%p] Peer shut down\n", Stream); + ServerSend(Stream); + break; + case QUIC_STREAM_EVENT_PEER_SEND_ABORTED: + // + // The peer aborted its send direction of the stream. + // + printf("[strm][%p] Peer aborted\n", Stream); + quic_api->StreamShutdown(Stream, QUIC_STREAM_SHUTDOWN_FLAG_ABORT, 0); + 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); + quic_api->StreamClose(Stream); + break; + default: + break; + } + return QUIC_STATUS_SUCCESS; +} + +// +// The server's callback for connection events from quic_api. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +_Function_class_(QUIC_CONNECTION_CALLBACK) +QUIC_STATUS +QUIC_API +ServerConnectionCallback( + _In_ HQUIC Connection, + _In_opt_ void* Context, + _Inout_ QUIC_CONNECTION_EVENT* Event + ) +{ + UNREFERENCED_PARAMETER(Context); + switch (Event->Type) { + case QUIC_CONNECTION_EVENT_CONNECTED: + // + // The handshake has completed for the connection. + // + printf("[conn][%p] Connected\n", Connection); + quic_api->ConnectionSendResumptionTicket(Connection, QUIC_SEND_RESUMPTION_FLAG_NONE, 0, NULL); + 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); + quic_api->ConnectionClose(Connection); + break; + case QUIC_CONNECTION_EVENT_PEER_STREAM_STARTED: + // + // The peer has started/created a new stream. The app MUST set the + // callback handler before returning. + // + printf("[strm][%p] Peer started\n", Event->PEER_STREAM_STARTED.Stream); + quic_api->SetCallbackHandler(Event->PEER_STREAM_STARTED.Stream, (void*)ServerStreamCallback, NULL); + break; + case QUIC_CONNECTION_EVENT_RESUMED: + // + // The connection succeeded in doing a TLS resumption of a previous + // connection's session. + // + printf("[conn][%p] Connection resumed!\n", Connection); + break; + default: + break; + } + return QUIC_STATUS_SUCCESS; +} + +// +// The server's callback for listener events from quic_api. +// +_IRQL_requires_max_(PASSIVE_LEVEL) +_Function_class_(QUIC_LISTENER_CALLBACK) +QUIC_STATUS +QUIC_API +ServerListenerCallback( + _In_ HQUIC Listener, + _In_opt_ void* Context, + _Inout_ QUIC_LISTENER_EVENT* Event + ) +{ + UNREFERENCED_PARAMETER(Listener); + UNREFERENCED_PARAMETER(Context); + QUIC_STATUS Status = QUIC_STATUS_NOT_SUPPORTED; + switch (Event->Type) { + case QUIC_LISTENER_EVENT_NEW_CONNECTION: + // + // A new connection is being attempted by a client. For the handshake to + // proceed, the server must provide a configuration for QUIC to use. The + // app MUST set the callback handler before returning. + // + quic_api->SetCallbackHandler(Event->NEW_CONNECTION.Connection, (void*)ServerConnectionCallback, NULL); + Status = quic_api->ConnectionSetConfiguration(Event->NEW_CONNECTION.Connection, quic_configuration); + break; + default: + break; + } + return Status; +} + + +// +// Helper function to load a server configuration. Uses the command line +// arguments to load the credential part of the configuration. +// +BOOLEAN ServerLoadConfiguration() { + + QUIC_SETTINGS Settings = {0}; + // + // Configures the server's idle timeout. + // + Settings.IdleTimeoutMs = quic_idle_timeoutms; + Settings.IsSet.IdleTimeoutMs = TRUE; + // + // Configures the server's resumption level to allow for resumption and + // 0-RTT. + // + Settings.ServerResumptionLevel = QUIC_SERVER_RESUME_AND_ZERORTT; + Settings.IsSet.ServerResumptionLevel = TRUE; + // + // Configures the server's settings to allow for the peer to open a single + // bidirectional stream. By default connections are not configured to allow + // any streams from the peer. + // + Settings.PeerBidiStreamCount = 1; + Settings.IsSet.PeerBidiStreamCount = TRUE; + + QUIC_CREDENTIAL_CONFIG_HELPER Config; + memset(&Config, 0, sizeof(Config)); + Config.CredConfig.Flags = QUIC_CREDENTIAL_FLAG_NONE; + + + const char* Cert = "certs/server.crt.pem"; + const char* KeyFile = "certs/server.key.pem"; + + + Config.CertFile.CertificateFile = (char*)Cert; + Config.CertFile.PrivateKeyFile = (char*)KeyFile; + Config.CredConfig.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE; + Config.CredConfig.CertificateFile = &Config.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. + // + if (QUIC_FAILED(Status = quic_api->ConfigurationLoadCredential(quic_configuration, &Config.CredConfig))) { + printf("ConfigurationLoadCredential failed, 0x%x!\n", Status); + return FALSE; + } + + return TRUE; +} + +// +// Runs the server side of the protocol. +// +void RunServer(){ + QUIC_STATUS Status; + HQUIC Listener = NULL; + + // + // Configures the address used for the listener to listen on all IP + // addresses and the given UDP port. + // + QUIC_ADDR Address = {0}; + QuicAddrSetFamily(&Address, QUIC_ADDRESS_FAMILY_UNSPEC); + QuicAddrSetPort(&Address, quic_udp_port); + + // + // Load the server configuration based on the command line. + // + if (!ServerLoadConfiguration()) { + return; + } + + // + // Create/allocate a new listener object. + // + if (QUIC_FAILED(Status = quic_api->ListenerOpen(quic_registration, ServerListenerCallback, NULL, &Listener))) { + printf("ListenerOpen failed, 0x%x!\n", Status); + goto Error; + } + + // + // Starts listening for incoming connections. + // + if (QUIC_FAILED(Status = quic_api->ListenerStart(Listener, &quic_alpn, 1, &Address))) { + printf("ListenerStart failed, 0x%x!\n", Status); + goto Error; + } + + // + // Continue listening for connections until the Enter key is pressed. + // + printf("Press Enter to exit.\n\n"); + getchar(); + +Error: + + if (Listener != NULL) { + quic_api->ListenerClose(Listener); + } +} + + + +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; + } + + RunServer(); + +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/setup.sh b/quic-bench/quic/setup.sh new file mode 100755 index 0000000..ed51603 --- /dev/null +++ b/quic-bench/quic/setup.sh @@ -0,0 +1,28 @@ +#!/bin/bash + + +sudo apt-get update +sudo apt-get install cmake build-essential liblttng-ust-dev lttng-tools + + +git clone https://github.com/microsoft/msquic.git + + +mkdir -p msquic/build + +pushd msquic + +git switch -c release/2.5 origin/release/2.5 + +git submodule update --init --recursive + +pushd build + +cmake .. + +make + +popd + +popd + diff --git a/quic-bench/setup.sh b/quic-bench/setup.sh new file mode 100755 index 0000000..fcc25e3 --- /dev/null +++ b/quic-bench/setup.sh @@ -0,0 +1,18 @@ +#!/bin/bash + + +echo "creating interface..." + +sudo ip netns add net1 + +sudo ip link add dev veth11 type veth peer name veth12 netns net1 + +sudo ip link set up veth11 + +sudo ip netns exec net1 ip link set up veth12 + +sudo ip addr add 192.168.62.5/24 dev veth11 + +sudo ip netns exec net1 ip addr add 192.168.62.6/24 dev veth12 + +echo "created interface!" diff --git a/quic-bench/tcp/Makefile b/quic-bench/tcp/Makefile new file mode 100644 index 0000000..55917f0 --- /dev/null +++ b/quic-bench/tcp/Makefile @@ -0,0 +1,7 @@ +all: + + gcc -O2 -g -o tcp.out tcp.c + +clean: + + rm -rf *.o *.out \ No newline at end of file diff --git a/quic-bench/tcp/tcp.c b/quic-bench/tcp/tcp.c new file mode 100644 index 0000000..3ae7e91 --- /dev/null +++ b/quic-bench/tcp/tcp.c @@ -0,0 +1,199 @@ +#include "tcp.h" + + +static int client(){ + + int result = 0; + int sockfd = -1; + struct sockaddr_in servaddr; + in_addr_t s_addr = inet_addr(SERVER_ADDR); + int addr_port = SERVER_PORT; + int keepalive = 1; + int chunk = 0; + int content_len = 0; + int message_len = 0; + float percent = 0; + struct timeval t1, t2; + + uint64_t total_sent = 0; + uint8_t data[INPUT_BUFF_CHUNK] = {0}; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) { + fprintf(stderr, "socket creation failed\n"); + return -1; + } + + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = s_addr; + servaddr.sin_port = htons(addr_port); + + if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))!= 0) { + fprintf(stderr, "connection failed\n"); + return -2; + } + + printf("connected, sending...\n"); + + gettimeofday(&t1, NULL); + + while(keepalive){ + + if(getrandom(data, INPUT_BUFF_CHUNK, 0) < 0){ + printf("getrandom failed\n"); + return -3; + } + + int wb = write(sockfd, data, INPUT_BUFF_CHUNK); + + if(wb <= 0){ + keepalive = 0; + continue; + } + + total_sent += (uint64_t)wb; + + percent = ((float)total_sent / (float)INPUT_BUFF_MAX) * 100; + + printf("progress: %.2f\n", percent); + + if(total_sent > INPUT_BUFF_MAX){ + keepalive = 0; + continue; + } + + } + + if(total_sent <= INPUT_BUFF_MAX){ + printf("connection closed before sending completed\n"); + return -4; + } + + gettimeofday(&t2, NULL); + + uint32_t seconds = t2.tv_sec - t1.tv_sec; + uint32_t ms = (t2.tv_usec - t1.tv_usec) / 1000; + + printf("sec: %lu ms: %lu\n", seconds, ms); + printf("total sent: " "%" PRIu64 "\n", total_sent); + + return 0; +} + + + +static int server(){ + + int sockfd, connfd = -1; + struct sockaddr_in servaddr, cli; + int keepalive = 1; + + + in_addr_t s_addr = INADDR_ANY; + + int addr_port = SERVER_PORT; + int enable = 1; + int clilen = sizeof(cli); + + uint8_t data[INPUT_BUFF_CHUNK] = {0}; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) { + fprintf(stderr,"socket creation failed...\n"); + return -1; + } + + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = s_addr; + servaddr.sin_port = htons(addr_port); + + if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0) { + fprintf(stderr, "socket bind failed\n"); + return -2; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0){ + fprintf(stderr, "socket opt failed\n"); + return -3; + } + + if ((listen(sockfd, 1)) != 0) { + fprintf(stderr,"socket listen failed\n"); + return -4; + } + + while(keepalive){ + + connfd = accept(sockfd, (struct sockaddr*)&cli, (socklen_t*)&clilen); + if (connfd < 0) { + fprintf(stderr, "server accept failed\n"); + continue; + } + + printf("client connected\n"); + printf("receiving...\n"); + + while(keepalive){ + + int valread = 0; + + while(valread < INPUT_BUFF_CHUNK){ + + int rb = read(connfd, data + valread, INPUT_BUFF_CHUNK - valread); + if (rb <= 0){ + keepalive = 0; + break; + } + valread += rb; + + } + + if(keepalive == 0){ + continue; + } + } + + close(connfd); + + } + return 0; +} + + + +static void help(){ + + printf("option: [c|s]\n"); + printf("c: client mode\n"); + printf("s: server mode\n"); +} + + +int main(int argc, char** argv){ + + int result = 0; + + if(argc != 2){ + + help(); + + return -1; + } + + if(strcmp(argv[1], "c") == 0){ + + result = client(); + + } else if(strcmp(argv[1], "s") == 0){ + + result = server(); + + } else { + + help(); + + return -1; + } + + return result; +} \ No newline at end of file diff --git a/quic-bench/tcp/tcp.h b/quic-bench/tcp/tcp.h new file mode 100644 index 0000000..d7145b3 --- /dev/null +++ b/quic-bench/tcp/tcp.h @@ -0,0 +1,32 @@ +#ifndef _BENCH_TCP_H_ +#define _BENCH_TCP_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + +#define SERVER_ADDR "192.168.62.6" +#define SERVER_PORT 9999 +#define INPUT_BUFF_CHUNK 65536 +#define INPUT_BUFF_MAX 4294967296 + + +#endif \ No newline at end of file diff --git a/sock-quic/Makefile b/sock-quic/Makefile index 8b38f2e..937a7ad 100644 --- a/sock-quic/Makefile +++ b/sock-quic/Makefile @@ -2,10 +2,10 @@ FLAGS := -Wall -g -INCLUDES := -Imsquic/src/inc -Imsquic/build/_deps/opensslquic-build/openssl/include -I. +INCLUDES := -Imsquic/src/inc -Imsquic/build/_deps/opensslquic-build/quictls/include -I. LINKS := -Lmsquic/build/obj/Release -Lmsquic/build/bin/Release -Wl,-rpath=msquic/build/bin/Release -LINKS += -Lmsquic/build/_deps/opensslquic-build/openssl/lib -Lmsquic/build/_deps/opensslquic-build/submodules/openssl +LINKS += -Lmsquic/build/_deps/opensslquic-build/quictls/lib -Lmsquic/build/_deps/opensslquic-build/submodules/quictls LIBS := -lcore -lmsquic -lmsquic_platform -lssl -lcrypto