--- /dev/null
+msquic
+certs
\ No newline at end of file
--- /dev/null
+
+
+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
--- /dev/null
+#!/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
--- /dev/null
+
+#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
--- /dev/null
+#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
--- /dev/null
+
+#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
--- /dev/null
+#!/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
+
--- /dev/null
+#!/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!"
--- /dev/null
+all:
+
+ gcc -O2 -g -o tcp.out tcp.c
+
+clean:
+
+ rm -rf *.o *.out
\ No newline at end of file
--- /dev/null
+#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
--- /dev/null
+#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
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