]> git.feebdaed.xyz Git - linuxyz.git/commitdiff
quic 2.5
authorseantywork <seantywork@gmail.com>
Tue, 1 Jul 2025 01:26:16 +0000 (10:26 +0900)
committerseantywork <seantywork@gmail.com>
Tue, 1 Jul 2025 01:26:16 +0000 (10:26 +0900)
quic-bench/quic/Makefile
quic-bench/quic/client.c [deleted file]
quic-bench/quic/quic.c [new file with mode: 0644]
quic-bench/quic/quic.h [new file with mode: 0644]
quic-bench/quic/quic_core.h [deleted file]
quic-bench/quic/server.c [deleted file]

index 6ca280768d06195ad35c3e5cfb77e8bb6cbe0471..f24146e90e80fd3329703bdddca7a3673a5bb18a 100644 (file)
@@ -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 (file)
index 591d9a0..0000000
+++ /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/quic.c b/quic-bench/quic/quic.c
new file mode 100644 (file)
index 0000000..84231e9
--- /dev/null
@@ -0,0 +1,668 @@
+
+#include "quic.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);
+    }
+}
+
+
+
+_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.h b/quic-bench/quic/quic.h
new file mode 100644 (file)
index 0000000..3a1c1da
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _BENCH_QUIC_H_
+#define _BENCH_QUIC_H_
+
+#include "msquic.h"
+#include <stdio.h> 
+#include <netdb.h> 
+#include <netinet/in.h> 
+#include <arpa/inet.h>
+#include <stdlib.h> 
+#include <string.h> 
+#include <sys/socket.h> 
+#include <sys/types.h> 
+#include <unistd.h> 
+#include <stdint.h>
+#include <pthread.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/random.h>
+#include <inttypes.h>
+
+#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/quic_core.h b/quic-bench/quic/quic_core.h
deleted file mode 100644 (file)
index 8ac72b1..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef _SOCK_QUIC_H_
-#define _SOCK_QUIC_H_
-
-#include "msquic.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-#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
deleted file mode 100644 (file)
index 86a19e8..0000000
+++ /dev/null
@@ -1,376 +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";
-
-
-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