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:
+++ /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
+
+#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
--- /dev/null
+#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
+++ /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