]> git.feebdaed.xyz Git - linuxyz.git/commitdiff
quic 2.5
authorseantywork <seantywork@gmail.com>
Tue, 1 Jul 2025 01:16:59 +0000 (10:16 +0900)
committerseantywork <seantywork@gmail.com>
Tue, 1 Jul 2025 01:16:59 +0000 (10:16 +0900)
13 files changed:
quic-bench/2506-04.xyz.md [new file with mode: 0644]
quic-bench/quic/.gitignore [new file with mode: 0644]
quic-bench/quic/Makefile [new file with mode: 0644]
quic-bench/quic/certgen.sh [new file with mode: 0755]
quic-bench/quic/client.c [new file with mode: 0644]
quic-bench/quic/quic_core.h [new file with mode: 0644]
quic-bench/quic/server.c [new file with mode: 0644]
quic-bench/quic/setup.sh [new file with mode: 0755]
quic-bench/setup.sh [new file with mode: 0755]
quic-bench/tcp/Makefile [new file with mode: 0644]
quic-bench/tcp/tcp.c [new file with mode: 0644]
quic-bench/tcp/tcp.h [new file with mode: 0644]
sock-quic/Makefile

diff --git a/quic-bench/2506-04.xyz.md b/quic-bench/2506-04.xyz.md
new file mode 100644 (file)
index 0000000..792d600
--- /dev/null
@@ -0,0 +1 @@
+#
diff --git a/quic-bench/quic/.gitignore b/quic-bench/quic/.gitignore
new file mode 100644 (file)
index 0000000..51caa86
--- /dev/null
@@ -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 (file)
index 0000000..6ca2807
--- /dev/null
@@ -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 (executable)
index 0000000..902992a
--- /dev/null
@@ -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 (file)
index 0000000..591d9a0
--- /dev/null
@@ -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 (file)
index 0000000..8ac72b1
--- /dev/null
@@ -0,0 +1,48 @@
+#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
new file mode 100644 (file)
index 0000000..86a19e8
--- /dev/null
@@ -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 (executable)
index 0000000..ed51603
--- /dev/null
@@ -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 (executable)
index 0000000..fcc25e3
--- /dev/null
@@ -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 (file)
index 0000000..55917f0
--- /dev/null
@@ -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 (file)
index 0000000..3ae7e91
--- /dev/null
@@ -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 (file)
index 0000000..d7145b3
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _BENCH_TCP_H_
+#define _BENCH_TCP_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>
+
+
+
+
+#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
index 8b38f2e2a4720b5eda7bde3aa368a445190ae71d..937a7ad69b8d49d8d836bc4a4789666614857924 100644 (file)
@@ -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