diff --git a/CMakeLists.txt b/CMakeLists.txt index 23817063..7a4b57c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,6 @@ else() set(QUIC_ENABLE_LOGGING "OFF") endif() - if (DEFINED ENV{QUICER_USE_LTTNG}) add_compile_options(-DQUICER_USE_LTTNG) endif() @@ -35,6 +34,8 @@ set(QUIC_BUILD_TEST "OFF") set(QUIC_BUILD_TOOLS "OFF") set(QUIC_BUILD_PERF "OFF") +set(QUIC_TLS_SECRETS_SUPPORT "ON") + # src files set(SOURCES c_src/quicer_nif.c diff --git a/c_src/quicer_config.c b/c_src/quicer_config.c index 2b6778f3..edf31dcf 100644 --- a/c_src/quicer_config.c +++ b/c_src/quicer_config.c @@ -15,7 +15,9 @@ limitations under the License. -------------------------------------------------------------------*/ #include "quicer_config.h" +#include "quicer_internal.h" #include "quicer_queue.h" +#include extern BOOLEAN isRegistered; @@ -157,6 +159,13 @@ ClientLoadConfiguration(ErlNifEnv *env, return ERROR_TUPLE_2(ATOM_BADARG); } + // Uncomment to make client prefer to use Draft-29 + // This is for Draft-29 version in HOST byte order. + /* const uint32_t DesiredVersion = 0xff00001dU; */ + /* Settings.DesiredVersionsList = &DesiredVersion; */ + /* Settings.DesiredVersionsListLength = 1; */ + /* Settings.IsSet.DesiredVersionsList = TRUE; */ + // // Configures a default client configuration, optionally disabling // server certificate validation. diff --git a/c_src/quicer_config.h b/c_src/quicer_config.h index 4eb115ed..b525a8b2 100644 --- a/c_src/quicer_config.h +++ b/c_src/quicer_config.h @@ -17,21 +17,9 @@ limitations under the License. #ifndef __QUICER_CONFIG_H_ #define __QUICER_CONFIG_H_ +#include "quicer_internal.h" #include "quicer_nif.h" - -// @todo check if we can make use of it. -//#include - -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_CREDENTIAL_CONFIG_HELPER; +#include bool ReloadCertConfig(HQUIC Configuration, QUIC_CREDENTIAL_CONFIG_HELPER *Config); @@ -73,5 +61,4 @@ ERL_NIF_TERM setopt3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); bool create_settings(ErlNifEnv *env, const ERL_NIF_TERM *emap, QUIC_SETTINGS *Settings); - #endif // __QUICER_CONFIG_H_ diff --git a/c_src/quicer_connection.c b/c_src/quicer_connection.c index 870d072b..b4908036 100644 --- a/c_src/quicer_connection.c +++ b/c_src/quicer_connection.c @@ -13,12 +13,109 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -------------------------------------------------------------------*/ - #include "quicer_connection.h" - #include #include +extern inline void +EncodeHexBuffer(uint8_t *Buffer, uint8_t BufferLen, char *HexString); + +extern inline const char* QuicStatusToString(QUIC_STATUS Status); + +void +dump_sslkeylogfile(_In_z_ const char *FileName, + _In_ CXPLAT_TLS_SECRETS TlsSecrets) +{ + FILE *File = NULL; +#ifdef _WIN32 + if (fopen_s(&File, FileName, "ab")) + { + printf("Failed to open sslkeylogfile %s\n", FileName); + return; + } +#else + File = fopen(FileName, "ab"); +#endif + + if (File == NULL) + { + printf("Failed to open sslkeylogfile %s\n", FileName); + return; + } + if (fseek(File, 0, SEEK_END) == 0 && ftell(File) == 0) + { + fprintf(File, "# TLS 1.3 secrets log file\n"); + } + char ClientRandomBuffer + [(2 * sizeof(((CXPLAT_TLS_SECRETS *)NULL)->ClientRandom)) + 1] + = { 0 }; + char TempHexBuffer[(2 * CXPLAT_TLS_SECRETS_MAX_SECRET_LEN) + 1] = { 0 }; + if (TlsSecrets.IsSet.ClientRandom) + { + EncodeHexBuffer(TlsSecrets.ClientRandom, + (uint8_t)sizeof(TlsSecrets.ClientRandom), + ClientRandomBuffer); + } + + if (TlsSecrets.IsSet.ClientEarlyTrafficSecret) + { + EncodeHexBuffer(TlsSecrets.ClientEarlyTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + fprintf(File, + "CLIENT_EARLY_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + } + + if (TlsSecrets.IsSet.ClientHandshakeTrafficSecret) + { + EncodeHexBuffer(TlsSecrets.ClientHandshakeTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + fprintf(File, + "CLIENT_HANDSHAKE_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + } + + if (TlsSecrets.IsSet.ServerHandshakeTrafficSecret) + { + EncodeHexBuffer(TlsSecrets.ServerHandshakeTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + fprintf(File, + "SERVER_HANDSHAKE_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + } + + if (TlsSecrets.IsSet.ClientTrafficSecret0) + { + EncodeHexBuffer(TlsSecrets.ClientTrafficSecret0, + TlsSecrets.SecretLength, + TempHexBuffer); + fprintf(File, + "CLIENT_TRAFFIC_SECRET_0 %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + } + + if (TlsSecrets.IsSet.ServerTrafficSecret0) + { + EncodeHexBuffer(TlsSecrets.ServerTrafficSecret0, + TlsSecrets.SecretLength, + TempHexBuffer); + fprintf(File, + "SERVER_TRAFFIC_SECRET_0 %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + } + + fflush(File); + fclose(File); +} + // // The clients's callback for connection events from MsQuic. // @@ -140,6 +237,12 @@ _IRQL_requires_max_(DISPATCH_LEVEL) MsQuic->ConnectionClose(Connection); c_ctx->is_closed = TRUE; } + + if (NULL != c_ctx->TlsSecrets && NULL != c_ctx->ssl_keylogfile) + { + dump_sslkeylogfile(c_ctx->ssl_keylogfile, *(c_ctx->TlsSecrets)); + } + destroy_c_ctx(c_ctx); break; case QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED: @@ -175,7 +278,7 @@ ServerConnectionCallback(HQUIC Connection, // The handshake has completed for the connection. // - assert(c_ctx->Connection == NULL); + assert(c_ctx->Connection == Connection); c_ctx->Connection = Connection; acc = c_ctx->owner; acc_pid = &(acc->Pid); @@ -214,6 +317,7 @@ ServerConnectionCallback(HQUIC Connection, MsQuic->ConnectionSendResumptionTicket( Connection, QUIC_SEND_RESUMPTION_FLAG_NONE, 0, NULL); + break; case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT: // @@ -380,6 +484,39 @@ async_connect3(ErlNifEnv *env, return ERROR_TUPLE_2(ATOM_CONN_OPEN_ERROR); } + ERL_NIF_TERM essl_keylogfile; + if (enif_get_map_value( + env, eoptions, ATOM_SSL_KEYLOGFILE_NAME, &essl_keylogfile)) + { + char *keylogfile = CXPLAT_ALLOC_NONPAGED(PATH_MAX, QUICER_TRACE); + if (enif_get_string( + env, essl_keylogfile, keylogfile, PATH_MAX, ERL_NIF_LATIN1)) + { + CXPLAT_TLS_SECRETS *TlsSecrets = CXPLAT_ALLOC_NONPAGED( + sizeof(CXPLAT_TLS_SECRETS), QUICER_TLS_SECRETS); + + CxPlatZeroMemory(TlsSecrets, sizeof(CXPLAT_TLS_SECRETS)); + Status = MsQuic->SetParam(c_ctx->Connection, + QUIC_PARAM_LEVEL_CONNECTION, + QUIC_PARAM_CONN_TLS_SECRETS, + sizeof(CXPLAT_TLS_SECRETS), + TlsSecrets); + if (QUIC_FAILED(Status)) + { + fprintf(stderr, + "failed to enable secret logging: %s", + QuicStatusToString(Status)); + } + c_ctx->TlsSecrets = TlsSecrets; + c_ctx->ssl_keylogfile = keylogfile; + } + + else + { + fprintf(stderr, "failed to read string ssl_keylogfile"); + } + } + if (QUIC_FAILED(Status = MsQuic->ConnectionStart(c_ctx->Connection, c_ctx->Configuration, QUIC_ADDRESS_FAMILY_UNSPEC, @@ -533,6 +670,24 @@ addr2eterm(ErlNifEnv *env, QUIC_ADDR *addr) enif_make_int(env, ntohs(addr->Ipv4.sin_port))); } } + +ERL_NIF_TERM +get_conn_rid1(ErlNifEnv *env, int args, const ERL_NIF_TERM argv[]) +{ + QuicerConnCTX *c_ctx; + if (1 != args) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } + + if (!enif_get_resource(env, argv[0], ctx_connection_t, (void **)&c_ctx)) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } + + return SUCCESS(enif_make_ulong(env, (unsigned long)c_ctx->Connection)); +} + ///_* Emacs ///==================================================================== /// Local Variables: diff --git a/c_src/quicer_connection.h b/c_src/quicer_connection.h index 9f273973..ea01e258 100644 --- a/c_src/quicer_connection.h +++ b/c_src/quicer_connection.h @@ -16,7 +16,9 @@ limitations under the License. #ifndef __QUICER_CONNECTION_H_ #define __QUICER_CONNECTION_H_ +#include "quicer_internal.h" #include "quicer_nif.h" +#include ERL_NIF_TERM async_connect3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); @@ -31,4 +33,8 @@ QUIC_STATUS ServerConnectionCallback(HQUIC Connection, QUIC_CONNECTION_EVENT *Event); ERL_NIF_TERM addr2eterm(ErlNifEnv *env, QUIC_ADDR *addr); + +ERL_NIF_TERM +get_conn_rid1(ErlNifEnv *env, int args, const ERL_NIF_TERM argv[]); + #endif // __QUICER_CONNECTION_H_ diff --git a/c_src/quicer_ctx.c b/c_src/quicer_ctx.c index b41542ec..ace16e95 100644 --- a/c_src/quicer_ctx.c +++ b/c_src/quicer_ctx.c @@ -52,6 +52,8 @@ init_c_ctx() = CXPLAT_ALLOC_NONPAGED(sizeof(ErlNifMonitor), QUICER_OWNER_MON); c_ctx->lock = enif_mutex_create("quicer:c_ctx"); c_ctx->is_closed = FALSE; + c_ctx->TlsSecrets = NULL; + c_ctx->ssl_keylogfile = NULL; return c_ctx; } diff --git a/c_src/quicer_ctx.h b/c_src/quicer_ctx.h index 557607fc..2d0e3ead 100644 --- a/c_src/quicer_ctx.h +++ b/c_src/quicer_ctx.h @@ -19,6 +19,7 @@ limitations under the License. #include "quicer_nif.h" #include "quicer_queue.h" +#include #define _CTX_CALLBACK_WRITE_ #define _CTX_CALLBACK_READ_ @@ -50,6 +51,8 @@ typedef struct ErlNifEnv *env; ErlNifMutex *lock; BOOLEAN is_closed; + CXPLAT_TLS_SECRETS *TlsSecrets; + char *ssl_keylogfile; void *reserved1; void *reserved2; void *reserved3; diff --git a/c_src/quicer_eterms.h b/c_src/quicer_eterms.h index c2124b27..78befc5a 100644 --- a/c_src/quicer_eterms.h +++ b/c_src/quicer_eterms.h @@ -240,6 +240,12 @@ extern ERL_NIF_TERM ATOM_SNK_KIND; extern ERL_NIF_TERM ATOM_SNK_META; extern ERL_NIF_TERM ATOM_FUNCTION; extern ERL_NIF_TERM ATOM_SNABBKAFFE_NEMESIS; + +/*----------------------------------------------------------*/ +/* Additional Connection Opt */ +/*----------------------------------------------------------*/ +extern ERL_NIF_TERM ATOM_SSL_KEYLOGFILE_NAME; + /*----------------------------------------------------------*/ /* ATOMS ends here */ /*----------------------------------------------------------*/ diff --git a/c_src/quicer_internal.h b/c_src/quicer_internal.h new file mode 100644 index 00000000..50657e84 --- /dev/null +++ b/c_src/quicer_internal.h @@ -0,0 +1,34 @@ +/*-------------------------------------------------------------------- +Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------*/ + +#ifndef QUICER_INTERNAL_H_ +#define QUICER_INTERNAL_H_ + +#if defined(__linux__) +#include +#elif defined(__APPLE__) +#include +#else +#include +#endif + +#if defined(__linux__) +#define CX_PLATFORM_LINUX 1 +#elif defined(__APPLE__) +#define CX_PLATFORM_DARWIN 1 +#endif + +#endif // QUICER_INTERNAL_H_ diff --git a/c_src/quicer_listener.c b/c_src/quicer_listener.c index 7fbedd10..a86b7805 100644 --- a/c_src/quicer_listener.c +++ b/c_src/quicer_listener.c @@ -15,6 +15,7 @@ limitations under the License. -------------------------------------------------------------------*/ #include "quicer_listener.h" +#include "quicer_config.h" QUIC_STATUS ServerListenerCallback(__unused_parm__ HQUIC Listener, @@ -23,7 +24,6 @@ ServerListenerCallback(__unused_parm__ HQUIC Listener, { QUIC_STATUS Status = QUIC_STATUS_SUCCESS; QuicerListenerCTX *l_ctx = (QuicerListenerCTX *)Context; - ErlNifEnv *env = l_ctx->env; QuicerConnCTX *c_ctx = NULL; switch (Event->Type) { @@ -37,9 +37,11 @@ ServerListenerCallback(__unused_parm__ HQUIC Listener, if (!c_ctx) { - return ERROR_TUPLE_2(ATOM_CTX_INIT_FAILED); + return QUIC_STATUS_OUT_OF_MEMORY; } + c_ctx->Connection = Event->NEW_CONNECTION.Connection; + c_ctx->l_ctx = l_ctx; ACCEPTOR *conn_owner = AcceptorDequeue(l_ctx->acceptor_queue); diff --git a/c_src/quicer_listener.h b/c_src/quicer_listener.h index f8ec276a..8cdee9ad 100644 --- a/c_src/quicer_listener.h +++ b/c_src/quicer_listener.h @@ -17,6 +17,7 @@ limitations under the License. #ifndef __QUICER_LISTENER_H_ #define __QUICER_LISTENER_H_ +#include "quicer_internal.h" #include "quicer_nif.h" //#include "quicer_config.h" diff --git a/c_src/quicer_nif.c b/c_src/quicer_nif.c index 18731f5f..2dd82149 100644 --- a/c_src/quicer_nif.c +++ b/c_src/quicer_nif.c @@ -249,6 +249,12 @@ ERL_NIF_TERM ATOM_SNK_META; ERL_NIF_TERM ATOM_GEN_CAST; ERL_NIF_TERM ATOM_FUNCTION; ERL_NIF_TERM ATOM_SNABBKAFFE_NEMESIS; + +/*----------------------------------------------------------*/ +/* Additional Connection Opt */ +/*----------------------------------------------------------*/ +ERL_NIF_TERM ATOM_SSL_KEYLOGFILE_NAME; + // Mirror 'status' in msquic_linux.h /* @@ -468,8 +474,8 @@ ERL_NIF_TERM ATOM_SNABBKAFFE_NEMESIS; ATOM(ATOM_SNK_META, ~meta); \ ATOM(ATOM_GEN_CAST, $gen_cast); \ ATOM(ATOM_FUNCTION, function); \ - ATOM(ATOM_SNABBKAFFE_NEMESIS, snabbkaffe_nemesis); - + ATOM(ATOM_SNABBKAFFE_NEMESIS, snabbkaffe_nemesis); \ + ATOM(ATOM_SSL_KEYLOGFILE_NAME, sslkeylogfile); HQUIC Registration; const QUIC_API_TABLE *MsQuic; @@ -503,6 +509,8 @@ resource_conn_dealloc_callback(__unused_parm__ ErlNifEnv *caller_env, enif_free_env(c_ctx->env); enif_mutex_destroy(c_ctx->lock); CXPLAT_FREE(c_ctx->owner_mon, QUICER_OWNER_MON); + CXPLAT_FREE(c_ctx->TlsSecrets, QUICER_TLS_SECRETS); + CXPLAT_FREE(c_ctx->ssl_keylogfile, QUICER_TRACE); AcceptorDestroy(c_ctx->owner); } @@ -876,7 +884,10 @@ static ErlNifFunc nif_funcs[] = { { "async_close_stream", 1, close_stream1, 0}, { "sockname", 1, sockname1, 0}, { "getopt", 3, getopt3, 0}, - { "setopt", 3, setopt3, 0} + { "setopt", 3, setopt3, 0}, + /* for DEBUG */ + { "get_conn_rid", 1, get_conn_rid1, 1}, + { "get_stream_rid", 1, get_stream_rid1, 1} // clang-format on }; diff --git a/c_src/quicer_nif.h b/c_src/quicer_nif.h index 9533a4a4..36760097 100644 --- a/c_src/quicer_nif.h +++ b/c_src/quicer_nif.h @@ -16,9 +16,11 @@ limitations under the License. #ifndef __QUICER_NIF_H_ #define __QUICER_NIF_H_ +#include "quicer_internal.h" #include #include #include +#include #include #include "quicer_config.h" @@ -32,14 +34,6 @@ limitations under the License. // @todo is 16 enough? #define MAX_ALPN 16 -#if defined(__linux__) -#include -#elif defined(__APPLE__) -#include -#else -#include -#endif - // Global registration // @todo avoid use globals extern HQUIC Registration; diff --git a/c_src/quicer_queue.h b/c_src/quicer_queue.h index 9e6344eb..1186fd8b 100644 --- a/c_src/quicer_queue.h +++ b/c_src/quicer_queue.h @@ -17,12 +17,7 @@ limitations under the License. #ifndef __QUICER_QUEUE_H_ #define __QUICER_QUEUE_H_ -#if defined(__linux__) -#define CX_PLATFORM_LINUX 1 -#elif defined(__APPLE__) -#define CX_PLATFORM_DARWIN 1 -#endif - +#include "quicer_internal.h" #include #include #include @@ -36,7 +31,9 @@ limitations under the License. '30rQ' // Qr03 QUICER_CREDENTIAL_CONFIG_HELPER #define QUICER_OPT_BUFF '40rQ' // Qr04 - QUICER OPT #define QUICER_SETTINGS '50rQ' // Qr05 - QUICER CONNECTION SETTINGS - +#define QUICER_TLS_SECRETS \ + '60rQ' // Qr06 - QUICER TLS SECRETS for SSLKeyLogFile +#define QUICER_TRACE '70rQ' // Qr07 - QUICER TRACE, unimportant typedef enum ACCEPTOR_RECV_MODE { ACCEPTOR_RECV_MODE_PASSIVE, diff --git a/c_src/quicer_stream.c b/c_src/quicer_stream.c index 0ffe5c5f..24f82f47 100644 --- a/c_src/quicer_stream.c +++ b/c_src/quicer_stream.c @@ -660,6 +660,23 @@ handle_stream_recv_event(HQUIC Stream, return status; } +ERL_NIF_TERM +get_stream_rid1(ErlNifEnv *env, int args, const ERL_NIF_TERM argv[]) +{ + QuicerStreamCTX *s_ctx; + if (1 != args) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } + + if (!enif_get_resource(env, argv[0], ctx_stream_t, (void **)&s_ctx)) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } + + return SUCCESS(enif_make_ulong(env, (unsigned long)s_ctx->Stream)); +} + ///_* Emacs ///==================================================================== /// Local Variables: diff --git a/c_src/quicer_stream.h b/c_src/quicer_stream.h index 977dc35c..06cffdad 100644 --- a/c_src/quicer_stream.h +++ b/c_src/quicer_stream.h @@ -18,6 +18,7 @@ limitations under the License. #define __QUICER_STREAM_H_ #include "quicer_config.h" +#include "quicer_internal.h" #include "quicer_nif.h" QUIC_STATUS @@ -42,4 +43,6 @@ _IRQL_requires_max_(DISPATCH_LEVEL) _In_opt_ void *Context, _Inout_ QUIC_STREAM_EVENT *Event); +ERL_NIF_TERM +get_stream_rid1(ErlNifEnv *env, int args, const ERL_NIF_TERM argv[]); #endif // __QUICER_STREAM_H_ diff --git a/c_src/quicer_tp.c b/c_src/quicer_tp.c index 70005a5d..f4ddb828 100644 --- a/c_src/quicer_tp.c +++ b/c_src/quicer_tp.c @@ -38,9 +38,5 @@ tp_snk(ErlNifEnv *env, env, ATOM_GEN_CAST, enif_make_tuple2(env, ATOM_TRACE, snk_event)); enif_send(NULL, &pid, NULL, report); } - else - { - fprintf(stderr, "Warning snabbcaffe_collector not found\n"); - } } //#endif /* QUICER_USE_SNK */ diff --git a/src/quicer.erl b/src/quicer.erl index 303c3e5c..b184f66f 100644 --- a/src/quicer.erl +++ b/src/quicer.erl @@ -45,6 +45,11 @@ , peername/1 ]). +%% Exports for test +-export([ get_conn_rid/1 + , get_stream_rid/1 + ]). + -export([ start_listener/3 %% start application over quic , stop_listener/1 ]). @@ -273,9 +278,17 @@ getstat(Conn, Cnts) -> -spec peername(connection_handler() | stream_handler()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, any()}. -peername(Handle)-> +peername(Handle) -> quicer_nif:getopt(Handle, param_conn_remote_address, false). +-spec get_conn_rid(connection_handler()) -> {ok, non_neg_integer()} | {error, any()}. +get_conn_rid(Conn) -> + quicer_nif:get_conn_rid(Conn). + +-spec get_stream_rid(stream_handler()) -> {ok, non_neg_integer()} | {error, any()}. +get_stream_rid(Stream) -> + quicer_nif:get_stream_rid(Stream). + %%% Internal helpers stats_map(recv_cnt) -> "Recv.TotalPackets"; diff --git a/src/quicer_nif.erl b/src/quicer_nif.erl index 66fff487..21f0dd9e 100644 --- a/src/quicer_nif.erl +++ b/src/quicer_nif.erl @@ -33,6 +33,10 @@ , setopt/3 ]). +-export([ get_conn_rid/1 + , get_stream_rid/1 + ]). + -on_load(init/0). -include_lib("kernel/include/file.hrl"). @@ -102,6 +106,12 @@ getopt(_Handle, _Optname, _IsRaw) -> setopt(_Handle, _Opt, _Value) -> erlang:nif_error(nif_library_not_loaded). +get_conn_rid(_Handle)-> + erlang:nif_error(nif_library_not_loaded). + +get_stream_rid(_Handle)-> + erlang:nif_error(nif_library_not_loaded). + %% Internals -spec locate_lib(file:name(), file:name()) -> diff --git a/test/quicer_SUITE.erl b/test/quicer_SUITE.erl index 951a5ae8..a11f9bd9 100644 --- a/test/quicer_SUITE.erl +++ b/test/quicer_SUITE.erl @@ -15,6 +15,7 @@ %%-------------------------------------------------------------------- -module(quicer_SUITE). +-include_lib("kernel/include/file.hrl"). %% API -export([all/0, @@ -62,6 +63,7 @@ , tc_strm_opt_active_once/1 , tc_strm_opt_active_1/1 , tc_strm_opt_active_badarg/1 + , tc_conn_opt_sslkeylogfile/1 , tc_get_stream_id/1 , tc_getstat/1 , tc_peername_v4/1 @@ -71,6 +73,9 @@ , tc_alpn_mismatch/1 , tc_idle_timeout/1 + + , tc_get_conn_rid/1 + , tc_get_stream_rid/1 %% testcase to verify env works %% , tc_network/1 ]). @@ -851,6 +856,66 @@ tc_strm_opt_active_badarg(Config) -> {ok, Conn} = quicer:connect("localhost", Port, default_conn_opts(), 5000), {error, badarg} = quicer:start_stream(Conn, [{active, twice}]). +tc_get_conn_rid(Config) -> + Port = 8891, + application:ensure_all_started(quicer), + ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], + ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} + , {stream_acceptors, 32} + | default_conn_opts()], + StreamOpts = [ {stream_callback, quicer_echo_server_stream_callback} + | default_stream_opts() ], + Options = {ListenerOpts, ConnectionOpts, StreamOpts}, + ct:pal("Listener Options: ~p", [Options]), + {ok, _QuicApp} = quicer:start_listener(mqtt, Port, Options), + {ok, Conn} = quicer:connect("localhost", Port, default_conn_opts(), 5000), + {ok, Rid} = quicer:get_conn_rid(Conn), + ?assert(is_integer(Rid) andalso Rid =/=0). + +tc_get_stream_rid(Config) -> + Port = 8891, + application:ensure_all_started(quicer), + ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], + ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} + , {stream_acceptors, 32} + | default_conn_opts()], + StreamOpts = [ {stream_callback, quicer_echo_server_stream_callback} + | default_stream_opts() ], + Options = {ListenerOpts, ConnectionOpts, StreamOpts}, + ct:pal("Listener Options: ~p", [Options]), + {ok, _QuicApp} = quicer:start_listener(mqtt, Port, Options), + {ok, Conn} = quicer:connect("localhost", Port, default_conn_opts(), 5000), + {ok, Stm} = quicer:start_stream(Conn, [{active, 3}]), + {ok, Rid} = quicer:get_stream_rid(Stm), + {ok, 5} = quicer:async_send(Stm, <<"ping1">>), + receive + {quic, <<"ping1">>, Stm, _, _, _} -> ok + end, + ?assert(is_integer(Rid)), + ?assert(Rid =/= 0). + +tc_conn_opt_sslkeylogfile(Config) -> + Port = 8892, + TargetFName = "SSLKEYLOGFILE", + file:delete(TargetFName), + application:ensure_all_started(quicer), + ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], + ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} + , {stream_acceptors, 32} + | default_conn_opts()], + StreamOpts = [ {stream_callback, quicer_echo_server_stream_callback} + | default_stream_opts() ], + Options = {ListenerOpts, ConnectionOpts, StreamOpts}, + ct:pal("Listener Options: ~p", [Options]), + {ok, _QuicApp} = quicer:start_listener(mqtt, Port, Options), + {ok, Conn} = quicer:connect("localhost", Port, + [ {sslkeylogfile, TargetFName} | + default_conn_opts() ], + 5000), + quicer:close_connection(Conn), + timer:sleep(100), + {ok, #file_info{type=regular}} = file:read_file_info("SSLKEYLOGFILE"). + %%% ==================== %%% Internal helpers %%% ==================== diff --git a/test/quicer_snb_SUITE.erl b/test/quicer_snb_SUITE.erl index a303a963..1b990224 100644 --- a/test/quicer_snb_SUITE.erl +++ b/test/quicer_snb_SUITE.erl @@ -40,7 +40,6 @@ suite() -> init_per_suite(Config) -> application:ensure_all_started(quicer), application:ensure_all_started(snabbkaffe), - snabbkaffe:start_trace(), Config. %%-------------------------------------------------------------------- @@ -152,16 +151,28 @@ tc_app_echo_server(Config) -> {ok, _QuicApp} = quicer:start_listener(mqtt, Port, Options), {ok, Conn} = quicer:connect("localhost", Port, default_conn_opts(), 5000), {ok, Stm} = quicer:start_stream(Conn, [{active, false}]), - ?check_trace(begin + ?check_trace(#{timetrap => 1000}, + begin {ok, 4} = quicer:async_send(Stm, <<"ping">>), quicer:recv(Stm, 4) end, fun(Result, Trace) -> ?assertEqual({ok, <<"ping">>}, Result), ct:pal("Trace is ~p", [Trace]), - ?assert(?strict_causality(#{?snk_kind := debug, function := "ClientStreamCallback", mark := ?QUIC_STREAM_EVENT_SEND_COMPLETE}, - #{?snk_kind := debug, function := "ServerStreamCallback", mark := ?QUIC_STREAM_EVENT_RECEIVE}, - Trace)) + ?assert(?strict_causality(#{ ?snk_kind := debug + , function := "ClientStreamCallback" + , tag := "event" + , mark := ?QUIC_STREAM_EVENT_SEND_COMPLETE + , resource_id := _RidC + }, + #{ ?snk_kind := debug + , function := "ServerStreamCallback" + , tag := "event" + , mark := ?QUIC_STREAM_EVENT_RECEIVE + , resource_id := _RidS + }, + _RidC =/= _RidS, + Trace)) end), quicer:close_stream(Stm),