From 95708283376699575402508df560377ae4afd344 Mon Sep 17 00:00:00 2001 From: William Yang Date: Sun, 22 Aug 2021 22:46:21 +0200 Subject: [PATCH 1/7] feat(conn): immediate close conn when owner is dead --- c_src/quicer_connection.c | 2 + c_src/quicer_ctx.c | 2 + c_src/quicer_nif.c | 32 +++++++--- src/quicer_conn_acceptor.erl | 1 + test/quicer_snb_SUITE.erl | 113 +++++++++++++++++++++++++++++++++-- 5 files changed, 137 insertions(+), 13 deletions(-) diff --git a/c_src/quicer_connection.c b/c_src/quicer_connection.c index a76949b8..3bc1ffee 100644 --- a/c_src/quicer_connection.c +++ b/c_src/quicer_connection.c @@ -133,6 +133,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) BOOLEAN is_destroy = FALSE; enif_mutex_lock(c_ctx->lock); + TP_CB_3(event, Connection, Event->Type); switch (Event->Type) { case QUIC_CONNECTION_EVENT_CONNECTED: @@ -150,6 +151,7 @@ _IRQL_requires_max_(DISPATCH_LEVEL) ATOM_CONNECTED, enif_make_resource(env, c_ctx)))) { + TP_CB_3(app_down, Connection, Event->Type); enif_mutex_unlock(c_ctx->lock); return QUIC_STATUS_INTERNAL_ERROR; } diff --git a/c_src/quicer_ctx.c b/c_src/quicer_ctx.c index e19c5198..1a30f11b 100644 --- a/c_src/quicer_ctx.c +++ b/c_src/quicer_ctx.c @@ -57,6 +57,7 @@ init_c_ctx() void destroy_c_ctx(QuicerConnCTX *c_ctx) { + enif_demonitor_process(c_ctx->env, c_ctx, &c_ctx->owner_mon); enif_release_resource(c_ctx); } @@ -83,6 +84,7 @@ void destroy_s_ctx(QuicerStreamCTX *s_ctx) { // note, see resource_stream_dealloc_callback + enif_demonitor_process(s_ctx->env, s_ctx, &s_ctx->owner_mon); enif_release_resource(s_ctx); } diff --git a/c_src/quicer_nif.c b/c_src/quicer_nif.c index bc36ec0f..dfccaf1a 100644 --- a/c_src/quicer_nif.c +++ b/c_src/quicer_nif.c @@ -513,10 +513,10 @@ resource_listener_down_callback(__unused_parm__ ErlNifEnv *caller_env, } void -resource_conn_dealloc_callback(__unused_parm__ ErlNifEnv *caller_env, - void *obj) +resource_conn_dealloc_callback(__unused_parm__ ErlNifEnv *env, void *obj) { QuicerConnCTX *c_ctx = (QuicerConnCTX *)obj; + TP_CB_3(start, c_ctx->Connection, 0); enif_demonitor_process(c_ctx->env, c_ctx, &c_ctx->owner_mon); AcceptorQueueDestroy(c_ctx->acceptor_queue); enif_free_env(c_ctx->env); @@ -524,31 +524,44 @@ resource_conn_dealloc_callback(__unused_parm__ ErlNifEnv *caller_env, CXPLAT_FREE(c_ctx->TlsSecrets, QUICER_TLS_SECRETS); CXPLAT_FREE(c_ctx->ssl_keylogfile, QUICER_TRACE); AcceptorDestroy(c_ctx->owner); + TP_CB_3(end, c_ctx->Connection, 0); } void -resource_conn_down_callback(__unused_parm__ ErlNifEnv *caller_env, - __unused_parm__ void *obj, +resource_conn_down_callback(__unused_parm__ ErlNifEnv *env, + void *ctx, __unused_parm__ ErlNifPid *pid, __unused_parm__ ErlNifMonitor *mon) { - // todo + QuicerConnCTX *c_ctx = ctx; + if (!ctx) + { + return; + } + else + { + TP_CB_3(start, c_ctx->Connection, (uint64_t)ctx); + MsQuic->ConnectionShutdown( + c_ctx->Connection, QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0); + TP_CB_3(end, c_ctx->Connection, (uint64_t)ctx); + } } void -resource_stream_dealloc_callback(__unused_parm__ ErlNifEnv *caller_env, - void *obj) +resource_stream_dealloc_callback(__unused_parm__ ErlNifEnv *env, void *obj) { QuicerStreamCTX *s_ctx = (QuicerStreamCTX *)obj; + TP_CB_3(start, s_ctx->Stream, 0); enif_mutex_lock(s_ctx->lock); enif_free_env(s_ctx->env); enif_mutex_unlock(s_ctx->lock); enif_mutex_destroy(s_ctx->lock); + TP_CB_3(end, s_ctx->Stream, 0); } void resource_stream_down_callback(__unused_parm__ ErlNifEnv *env, - __unused_parm__ void *ctx, + void *ctx, __unused_parm__ ErlNifPid *pid, __unused_parm__ ErlNifMonitor *mon) { @@ -858,7 +871,7 @@ connection_controlling_process(ErlNifEnv *env, const ErlNifPid *caller, const ERL_NIF_TERM *pid) { - + TP_NIF_3(enter, c_ctx->Connection, (uint64_t)&c_ctx); if (0 != enif_compare_pids(&c_ctx->owner->Pid, caller)) { return ERROR_TUPLE_2(ATOM_NOT_OWNER); @@ -879,6 +892,7 @@ connection_controlling_process(ErlNifEnv *env, return ERROR_TUPLE_2(ATOM_OWNER_DEAD); } + TP_NIF_3(exit, c_ctx->Connection, (uint64_t)&c_ctx); return ATOM_OK; } diff --git a/src/quicer_conn_acceptor.erl b/src/quicer_conn_acceptor.erl index bae52a4e..e189d278 100644 --- a/src/quicer_conn_acceptor.erl +++ b/src/quicer_conn_acceptor.erl @@ -173,6 +173,7 @@ handle_info({quic, shutdown, C}, #state{conn = C, callback = M, handle_info({quic, closed, C}, #state{conn = C} = State) -> %% @todo, connection closed + ?tp(quic_closed, #{module=>?MODULE}), {stop, normal, State}. %%-------------------------------------------------------------------- diff --git a/test/quicer_snb_SUITE.erl b/test/quicer_snb_SUITE.erl index cb799067..6c44c085 100644 --- a/test/quicer_snb_SUITE.erl +++ b/test/quicer_snb_SUITE.erl @@ -20,6 +20,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). +%-include_lib("quicer/include/quicer.hrl"). -include("quicer_nif_macro.hrl"). %%-------------------------------------------------------------------- @@ -124,6 +125,7 @@ all() -> [ tc_app_echo_server , tc_slow_conn , tc_stream_owner_down + , tc_conn_owner_down ]. %%-------------------------------------------------------------------- @@ -255,7 +257,7 @@ tc_stream_owner_down(Config) -> Pid ! down, ?block_until( #{'$kind' := debug, context := "callback", - function := "ServerStreamCallback", mark := 7, + function := "ServerStreamCallback", mark := ?QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE, tag := "event"}, 1000), ct:pal("stop listener"), ok = quicer:stop_listener(mqtt) @@ -287,17 +289,17 @@ tc_stream_owner_down(Config) -> , context := "callback" , function := "ClientStreamCallback" , tag := "event" - , mark := 6 + , mark := ?QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE , resource_id := _Rid }, Trace)), - %% check that client side immediate shutdown trigger an peer_send_abort event at server side + %% check that client side immediate shutdown trigger a peer_send_abort event at server side ?assert(?strict_causality(#{ ?snk_kind := debug , context := "callback" , function := "ClientStreamCallback" , tag := "event" - , mark := 6 + , mark := ?QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE }, #{ ?snk_kind := peer_send_aborted , module := quicer_stream @@ -307,6 +309,109 @@ tc_stream_owner_down(Config) -> end), ok. + +tc_conn_owner_down(Config) -> + Port = 8888, + ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], + ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} + , {fast_conn, false} + , {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]), + ?check_trace(#{timetrap => 1000}, + begin + {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}]), + {ok, 4} = quicer:async_send(Stm, <<"ping">>), + quicer:recv(Stm, 4), + Pid = spawn(fun() -> + receive down -> ok end + end), + quicer:controlling_process(Conn, Pid), + Pid ! down, + ?block_until( + #{'$kind' := debug, context := "callback", + function := "ServerStreamCallback", mark := ?QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE, + tag := "event"}, 1000), + ct:pal("stop listener"), + ok = quicer:stop_listener(mqtt) + end, + fun(Result, Trace) -> + ct:pal("Trace is ~p", [Trace]), + ?assertEqual(ok, Result), + %% check that conn down callback is triggered when conn owner process is dead + ?assert(?strict_causality(#{ ?snk_kind := debug + , function := "connection_controlling_process" + , tag := "exit" + , resource_id := _Rid + }, + #{ ?snk_kind := debug + , function := "resource_conn_down_callback" + , tag := "start" + , resource_id := _Rid + }, + Trace)), + %% check that it triggered a immediate connection shutdown + ?assert(?strict_causality(#{ ?snk_kind := debug + , function := "resource_conn_down_callback" + , tag := "end" + , resource_id := _Rid + }, + #{ ?snk_kind := debug + , context := "callback" + , function := "ClientConnectionCallback" + , tag := "event" + , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE + , resource_id := _Rid + }, + Trace)), + %% check that client side immediate shutdown triggers a stream shutdown + ?assert(?strict_causality(#{ ?snk_kind := debug + , function := "resource_conn_down_callback" + , tag := "end" + , resource_id := _Rid + }, + #{ ?snk_kind := debug + , context := "callback" + , function := "ClientStreamCallback" + , mark := ?QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE + , tag := "event" + }, + Trace)), + %% check that client side conn shutdown happens after stream shutdown + ?assert(?strict_causality(#{ ?snk_kind := debug + , context := "callback" + , function := "ClientStreamCallback" + , mark := ?QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE + , tag := "event" + }, + #{ ?snk_kind := debug + , context := "callback" + , function := "ClientConnectionCallback" + , tag := "event" + , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE + }, + Trace)), + %% check that client side immediate shutdown trigger a close at server side + ?assertMatch([{pair, _, _}], + ?find_pairs(true, + #{ ?snk_kind := debug + , context := "callback" + , function := "ClientConnectionCallback" + , tag := "event" + , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE + }, + #{ ?snk_kind := quic_closed + , module := quicer_conn_acceptor + }, + Trace)) + end), + ok. + %%% Internal Helpers default_stream_opts() -> []. From 3d8ff2bfb93789ec2ecfe1f7be92c4e32aba24de Mon Sep 17 00:00:00 2001 From: William Yang Date: Mon, 23 Aug 2021 11:50:40 +0200 Subject: [PATCH 2/7] feat(app_callback): peer send aborted with Reason --- src/quicer_stream.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quicer_stream.erl b/src/quicer_stream.erl index 0627e539..c7a702d9 100644 --- a/src/quicer_stream.erl +++ b/src/quicer_stream.erl @@ -167,9 +167,9 @@ handle_info({quic, _Bin, StreamA, _, _, _}, #state{stream = StreamB} = State) handle_info({quic, peer_send_aborted, Stream, Reason}, #state{stream = Stream, opts = Options} = State) -> ?tp(peer_send_aborted, #{module=>?MODULE, stream=>Stream, reason=>Reason}), #{stream_callback := CallbackModule} = Options, - case erlang:function_exported(CallbackModule, peer_send_aborted, 2) of + case erlang:function_exported(CallbackModule, peer_send_aborted, 3) of true -> - NewState = CallbackModule:peer_send_aborted(Stream, State), + NewState = CallbackModule:peer_send_aborted(Stream, State, Reason), {noreply, NewState}; false -> {noreply, State} From 69d3b96bf08156dfd9e4b1dbac6a19b6af7d1536 Mon Sep 17 00:00:00 2001 From: William Yang Date: Mon, 23 Aug 2021 15:20:31 +0200 Subject: [PATCH 3/7] feat: stream close with Flags and ErrorCode --- c_src/quicer_nif.c | 2 +- c_src/quicer_stream.c | 15 +++++++-- c_src/quicer_stream.h | 2 +- include/quicer.hrl | 70 +++++++++++++++++++++++++++++++++++++++ src/quicer.erl | 17 ++++++++-- src/quicer_nif.erl | 4 +-- test/quicer_snb_SUITE.erl | 4 +-- 7 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 include/quicer.hrl diff --git a/c_src/quicer_nif.c b/c_src/quicer_nif.c index dfccaf1a..1c37fe46 100644 --- a/c_src/quicer_nif.c +++ b/c_src/quicer_nif.c @@ -947,7 +947,7 @@ static ErlNifFunc nif_funcs[] = { { "start_stream", 2, async_start_stream2, 0}, { "send", 3, send3, 0}, { "recv", 2, recv2, 0}, - { "async_close_stream", 1, close_stream1, 0}, + { "async_close_stream", 3, close_stream3, 0}, { "sockname", 1, sockname1, 0}, { "getopt", 3, getopt3, 0}, { "setopt", 3, setopt3, 0}, diff --git a/c_src/quicer_stream.c b/c_src/quicer_stream.c index d175c026..0a76de1b 100644 --- a/c_src/quicer_stream.c +++ b/c_src/quicer_stream.c @@ -593,17 +593,28 @@ recv2(ErlNifEnv *env, __unused_parm__ int argc, const ERL_NIF_TERM argv[]) } ERL_NIF_TERM -close_stream1(ErlNifEnv *env, +close_stream3(ErlNifEnv *env, __unused_parm__ int argc, const ERL_NIF_TERM argv[]) { QUIC_STATUS Status; ERL_NIF_TERM ret = ATOM_OK; QuicerStreamCTX *s_ctx; + uint32_t app_errcode = 0, flags = 0; if (!enif_get_resource(env, argv[0], ctx_stream_t, (void **)&s_ctx)) { return ERROR_TUPLE_2(ATOM_BADARG); } + + if (!enif_get_uint(env, argv[1], &flags)) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } + + if (!enif_get_uint(env, argv[2], &app_errcode)) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } //@todo support application specific error code. // we don't use trylock since we are in NIF call. enif_mutex_lock(s_ctx->lock); @@ -612,7 +623,7 @@ close_stream1(ErlNifEnv *env, { if (QUIC_FAILED( Status = MsQuic->StreamShutdown( - s_ctx->Stream, QUIC_STREAM_SHUTDOWN_FLAG_GRACEFUL, 0))) + s_ctx->Stream, flags, app_errcode))) { ret = ERROR_TUPLE_2(ETERM_INT(Status)); } diff --git a/c_src/quicer_stream.h b/c_src/quicer_stream.h index cdf65a4e..f7fa3ede 100644 --- a/c_src/quicer_stream.h +++ b/c_src/quicer_stream.h @@ -35,7 +35,7 @@ ERL_NIF_TERM send3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM recv2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM -close_stream1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); +close_stream3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); _IRQL_requires_max_(DISPATCH_LEVEL) _Function_class_(QUIC_STREAM_CALLBACK) QUIC_STATUS QUIC_API diff --git a/include/quicer.hrl b/include/quicer.hrl new file mode 100644 index 00000000..a9d0c067 --- /dev/null +++ b/include/quicer.hrl @@ -0,0 +1,70 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2020-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_HRL). +-define(QUICER_HRL, true). + +%%% ======================================== +%%% mirror macro from NIF code +%%% ======================================== + +%% QUIC_STREAM_EVENT_TYPE +-define(QUIC_STREAM_EVENT_START_COMPLETE , 0). +-define(QUIC_STREAM_EVENT_RECEIVE , 1). +-define(QUIC_STREAM_EVENT_SEND_COMPLETE , 2). +-define(QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN , 3). +-define(QUIC_STREAM_EVENT_PEER_SEND_ABORTED , 4). +-define(QUIC_STREAM_EVENT_PEER_RECEIVE_ABORTED , 5). +-define(QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE , 6). +-define(QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE , 7). +-define(QUIC_STREAM_EVENT_IDEAL_SEND_BUFFER_SIZE , 8). + + +%% QUIC_LISTENER_EVENT_TYPE +-define(QUIC_LISTENER_EVENT_NEW_CONNECTION , 0). + +%% QUIC_CONNECTION_EVENT_TYPE +-define(QUIC_CONNECTION_EVENT_CONNECTED , 0). +-define(QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT , 1). +-define(QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER , 2). +-define(QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE , 3). +-define(QUIC_CONNECTION_EVENT_LOCAL_ADDRESS_CHANGED , 4). +-define(QUIC_CONNECTION_EVENT_PEER_ADDRESS_CHANGED , 5). +-define(QUIC_CONNECTION_EVENT_PEER_STREAM_STARTED , 6). +-define(QUIC_CONNECTION_EVENT_STREAMS_AVAILABLE , 7). +-define(QUIC_CONNECTION_EVENT_PEER_NEEDS_STREAMS , 8). +-define(QUIC_CONNECTION_EVENT_IDEAL_PROCESSOR_CHANGED , 9). +-define(QUIC_CONNECTION_EVENT_DATAGRAM_STATE_CHANGED , 10). +-define(QUIC_CONNECTION_EVENT_DATAGRAM_RECEIVED , 11). +-define(QUIC_CONNECTION_EVENT_DATAGRAM_SEND_STATE_CHANGED , 12). +-define(QUIC_CONNECTION_EVENT_RESUMED , 13). +-define(QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED , 14). +-define(QUIC_CONNECTION_EVENT_PEER_CERTIFICATE_RECEIVED , 15). + + +%% STREAM SHUTDOWN FLAGS +-define(QUIC_STREAM_SHUTDOWN_FLAG_NONE , 0). +-define(QUIC_STREAM_SHUTDOWN_FLAG_GRACEFUL , 1). % Cleanly closes the send path. +-define(QUIC_STREAM_SHUTDOWN_FLAG_ABORT_SEND , 2). % Abruptly closes the send path. +-define(QUIC_STREAM_SHUTDOWN_FLAG_ABORT_RECEIVE , 4). % Abruptly closes the receive path. +-define(QUIC_STREAM_SHUTDOWN_FLAG_ABORT , 6). % Abruptly closes both send and receive paths. +-define(QUIC_STREAM_SHUTDOWN_FLAG_IMMEDIATE , 8). + + +%% CONNECTED SHUTDOWN FLAGS +-define(QUIC_CONNECTION_SHUTDOWN_FLAG_NONE , 0). +-define(QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT , 1). +-endif. %% QUICER_HRL diff --git a/src/quicer.erl b/src/quicer.erl index f6a77439..b6aded71 100644 --- a/src/quicer.erl +++ b/src/quicer.erl @@ -16,6 +16,7 @@ -module(quicer). +-include("quicer.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -export([ listen/2 @@ -38,7 +39,9 @@ , recv/2 , close_stream/1 , close_stream/2 + , close_stream/4 , async_close_stream/1 + , async_close_stream/3 , sockname/1 , getopt/2 , getopt/3 @@ -260,7 +263,12 @@ close_stream(Stream) -> -spec close_stream(stream_handler(), timer:timeout()) -> ok | {error, any()}. close_stream(Stream, Timeout) -> - case async_close_stream(Stream) of + close_stream(Stream, ?QUIC_STREAM_SHUTDOWN_FLAG_GRACEFUL, 0, Timeout). + +-spec close_stream(stream_handler(), non_neg_integer(), non_neg_integer(), time:timeout()) + -> ok | {error, any()}. +close_stream(Stream, Flags, ErrorCode, Timeout) -> + case async_close_stream(Stream, Flags, ErrorCode) of ok -> receive {quic, closed, Stream, _IsGraceful} -> @@ -272,9 +280,14 @@ close_stream(Stream, Timeout) -> Err end. + -spec async_close_stream(stream_handler()) -> ok | {error, any()}. async_close_stream(Stream) -> - quicer_nif:async_close_stream(Stream). + quicer_nif:async_close_stream(Stream, ?QUIC_STREAM_SHUTDOWN_FLAG_GRACEFUL, 0). + +-spec async_close_stream(stream_handler(), non_neg_integer(), non_neg_integer()) -> ok | {error, any()}. +async_close_stream(Stream, Flags, Reason) -> + quicer_nif:async_close_stream(Stream, Flags, Reason). -spec sockname(listener_handler() | connection_handler() | stream_handler()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, any()}. diff --git a/src/quicer_nif.erl b/src/quicer_nif.erl index c67f96d7..ef73839d 100644 --- a/src/quicer_nif.erl +++ b/src/quicer_nif.erl @@ -28,7 +28,7 @@ , start_stream/2 , send/3 , recv/2 - , async_close_stream/1 + , async_close_stream/3 , sockname/1 , getopt/3 , setopt/3 @@ -99,7 +99,7 @@ send(_Stream, _Data, _IsSync) -> recv(_Stream, _Len) -> erlang:nif_error(nif_library_not_loaded). -async_close_stream(_Stream) -> +async_close_stream(_Stream, _Flags, _ErrorCode) -> erlang:nif_error(nif_library_not_loaded). sockname(_Conn) -> diff --git a/test/quicer_snb_SUITE.erl b/test/quicer_snb_SUITE.erl index 6c44c085..952cf67d 100644 --- a/test/quicer_snb_SUITE.erl +++ b/test/quicer_snb_SUITE.erl @@ -294,7 +294,7 @@ tc_stream_owner_down(Config) -> }, Trace)), - %% check that client side immediate shutdown trigger a peer_send_abort event at server side + %% check that client side immediate shutdown triggers a peer_send_abort event at server side ?assert(?strict_causality(#{ ?snk_kind := debug , context := "callback" , function := "ClientStreamCallback" @@ -396,7 +396,7 @@ tc_conn_owner_down(Config) -> , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE }, Trace)), - %% check that client side immediate shutdown trigger a close at server side + %% check that client side immediate shutdown triggers a close at server side ?assertMatch([{pair, _, _}], ?find_pairs(true, #{ ?snk_kind := debug From 480304f23d957983d6bcca9b8f4169c14d300466 Mon Sep 17 00:00:00 2001 From: William Yang Date: Mon, 23 Aug 2021 15:41:35 +0200 Subject: [PATCH 4/7] feat: close connection with flags and ErrorCode --- c_src/quicer_connection.c | 18 +++++++++++++----- c_src/quicer_connection.h | 2 +- c_src/quicer_nif.c | 2 +- c_src/quicer_stream.c | 5 ++--- src/quicer.erl | 20 +++++++++++++++++--- src/quicer_nif.erl | 4 ++-- 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/c_src/quicer_connection.c b/c_src/quicer_connection.c index 3bc1ffee..3d2ae568 100644 --- a/c_src/quicer_connection.c +++ b/c_src/quicer_connection.c @@ -589,23 +589,31 @@ async_accept2(ErlNifEnv *env, //@todo, shutdown with error ERL_NIF_TERM -close_connection1(ErlNifEnv *env, +close_connection3(ErlNifEnv *env, __unused_parm__ int argc, const ERL_NIF_TERM argv[]) { QuicerConnCTX *c_ctx; + uint32_t app_errcode = 0, flags = 0; if (!enif_get_resource(env, argv[0], ctx_connection_t, (void **)&c_ctx)) { return ERROR_TUPLE_2(ATOM_BADARG); } + + if (!enif_get_uint(env, argv[1], &flags)) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } + + if (!enif_get_uint(env, argv[2], &app_errcode)) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } enif_mutex_lock(c_ctx->lock); if (!c_ctx->is_closed) { c_ctx->is_closed = TRUE; - MsQuic->ConnectionShutdown(c_ctx->Connection, - //@todo, check rfc for the error code - QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, - 0); + MsQuic->ConnectionShutdown(c_ctx->Connection, flags, app_errcode); } enif_mutex_unlock(c_ctx->lock); return ATOM_OK; diff --git a/c_src/quicer_connection.h b/c_src/quicer_connection.h index fbde5171..017014b2 100644 --- a/c_src/quicer_connection.h +++ b/c_src/quicer_connection.h @@ -25,7 +25,7 @@ async_connect3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM async_accept2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM -close_connection1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); +close_connection3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM sockname1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); QUIC_STATUS ServerConnectionCallback(HQUIC Connection, diff --git a/c_src/quicer_nif.c b/c_src/quicer_nif.c index 1c37fe46..43f59818 100644 --- a/c_src/quicer_nif.c +++ b/c_src/quicer_nif.c @@ -942,7 +942,7 @@ static ErlNifFunc nif_funcs[] = { { "async_connect", 3, async_connect3, 0}, { "async_accept", 2, async_accept2, 0}, { "async_handshake", 1, async_handshake_1, 0}, - { "async_close_connection", 1, close_connection1, 0}, + { "async_close_connection", 3, close_connection3, 0}, { "async_accept_stream", 2, async_accept_stream2, 0}, { "start_stream", 2, async_start_stream2, 0}, { "send", 3, send3, 0}, diff --git a/c_src/quicer_stream.c b/c_src/quicer_stream.c index 0a76de1b..dac29bfb 100644 --- a/c_src/quicer_stream.c +++ b/c_src/quicer_stream.c @@ -621,9 +621,8 @@ close_stream3(ErlNifEnv *env, enif_keep_resource(s_ctx); if (!s_ctx->is_closed) { - if (QUIC_FAILED( - Status = MsQuic->StreamShutdown( - s_ctx->Stream, flags, app_errcode))) + if (QUIC_FAILED(Status = MsQuic->StreamShutdown( + s_ctx->Stream, flags, app_errcode))) { ret = ERROR_TUPLE_2(ETERM_INT(Status)); } diff --git a/src/quicer.erl b/src/quicer.erl index b6aded71..2428888e 100644 --- a/src/quicer.erl +++ b/src/quicer.erl @@ -29,7 +29,10 @@ , accept/3 , close_connection/1 , close_connection/2 + , close_connection/3 + , close_connection/4 , async_close_connection/1 + , async_close_connection/3 , accept_stream/2 , accept_stream/3 , async_accept_stream/2 @@ -157,9 +160,16 @@ accept(LSock, Opts, Timeout) -> close_connection(Conn) -> close_connection(Conn, 5000). --spec close_connection(connection_handler(), timer:timeout()) -> ok. close_connection(Conn, Timeout) -> - ok = async_close_connection(Conn), + close_connection(Conn, ?QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0, Timeout). + +-spec close_connection(connection_handler(), non_neg_integer(), non_neg_integer()) -> ok. +close_connection(Conn, Flags, ErrorCode) -> + close_connection(Conn, Flags, ErrorCode, 5000). + +-spec close_connection(connection_handler(), timer:timeout()) -> ok. +close_connection(Conn, Flags, ErrorCode, Timeout) -> + ok = async_close_connection(Conn, Flags, ErrorCode), %% @todo make_ref receive {quic, closed, Conn} -> @@ -170,7 +180,11 @@ close_connection(Conn, Timeout) -> -spec async_close_connection(connection_handler()) -> ok. async_close_connection(Conn) -> - quicer_nif:async_close_connection(Conn). + quicer_nif:async_close_connection(Conn, ?QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0). + +-spec async_close_connection(connection_handler(), non_neg_integer(), non_neg_integer()) -> ok. +async_close_connection(Conn, Flags, ErrorCode) -> + quicer_nif:async_close_connection(Conn, Flags, ErrorCode). -spec accept_stream(connection_handler(), proplists:proplist() | map()) -> {ok, stream_handler()} | {error, any()}. diff --git a/src/quicer_nif.erl b/src/quicer_nif.erl index ef73839d..b47cc0c1 100644 --- a/src/quicer_nif.erl +++ b/src/quicer_nif.erl @@ -23,7 +23,7 @@ , async_connect/3 , async_accept/2 , async_handshake/1 - , async_close_connection/1 + , async_close_connection/3 , async_accept_stream/2 , start_stream/2 , send/3 @@ -84,7 +84,7 @@ async_accept(_Listener, _Opts) -> async_handshake(_Connection)-> erlang:nif_error(nif_library_not_loaded). -async_close_connection(_Conn) -> +async_close_connection(_Conn, _Flags, _ErrorCode) -> erlang:nif_error(nif_library_not_loaded). async_accept_stream(_Conn, _Opts)-> From 04f3029fbd3b46e7beeb081bf8d599a915ec2307 Mon Sep 17 00:00:00 2001 From: William Yang Date: Mon, 23 Aug 2021 17:43:25 +0200 Subject: [PATCH 5/7] test: add tests close connection with flag --- c_src/quicer_connection.c | 4 + c_src/quicer_stream.c | 1 + test/quicer_nif_macro.hrl | 53 --------- test/quicer_snb_SUITE.erl | 230 ++++++++++++++++++++++++++++++++------ 4 files changed, 199 insertions(+), 89 deletions(-) delete mode 100644 test/quicer_nif_macro.hrl diff --git a/c_src/quicer_connection.c b/c_src/quicer_connection.c index 3d2ae568..aa72f747 100644 --- a/c_src/quicer_connection.c +++ b/c_src/quicer_connection.c @@ -283,6 +283,7 @@ ServerConnectionCallback(HQUIC Connection, BOOLEAN is_destroy = FALSE; enif_mutex_lock(c_ctx->lock); + TP_CB_3(event, Connection, Event->Type); switch (Event->Type) { case QUIC_CONNECTION_EVENT_CONNECTED: @@ -363,6 +364,9 @@ ServerConnectionCallback(HQUIC Connection, // The connection has completed the shutdown process and is ready to be // safely cleaned up. // + TP_CB_3(shutdown_complete, + Connection, + Event->SHUTDOWN_COMPLETE.AppCloseInProgress); report = enif_make_tuple3( env, ATOM_QUIC, ATOM_CLOSED, enif_make_resource(env, c_ctx)); diff --git a/c_src/quicer_stream.c b/c_src/quicer_stream.c index dac29bfb..ac85b440 100644 --- a/c_src/quicer_stream.c +++ b/c_src/quicer_stream.c @@ -105,6 +105,7 @@ ServerStreamCallback(HQUIC Stream, void *Context, QUIC_STREAM_EVENT *Event) // // The peer aborted its send direction of the stream. // + TP_CB_3(peer_send_aborted, Stream, Event->PEER_SEND_ABORTED.ErrorCode); report = enif_make_tuple4( env, ATOM_QUIC, diff --git a/test/quicer_nif_macro.hrl b/test/quicer_nif_macro.hrl deleted file mode 100644 index 15b86545..00000000 --- a/test/quicer_nif_macro.hrl +++ /dev/null @@ -1,53 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020-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. -%%-------------------------------------------------------------------- - - -%%% ======================================== -%%% mirror macro from NIF code -%%% ======================================== - -%% QUIC_STREAM_EVENT_TYPE --define(QUIC_STREAM_EVENT_START_COMPLETE , 0). --define(QUIC_STREAM_EVENT_RECEIVE , 1). --define(QUIC_STREAM_EVENT_SEND_COMPLETE , 2). --define(QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN , 3). --define(QUIC_STREAM_EVENT_PEER_SEND_ABORTED , 4). --define(QUIC_STREAM_EVENT_PEER_RECEIVE_ABORTED , 5). --define(QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE , 6). --define(QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE , 7). --define(QUIC_STREAM_EVENT_IDEAL_SEND_BUFFER_SIZE , 8). - - -%% QUIC_LISTENER_EVENT_TYPE --define(QUIC_LISTENER_EVENT_NEW_CONNECTION , 0). - -%% QUIC_CONNECTION_EVENT_TYPE --define(QUIC_CONNECTION_EVENT_CONNECTED , 0). --define(QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT , 1). --define(QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER , 2). --define(QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE , 3). --define(QUIC_CONNECTION_EVENT_LOCAL_ADDRESS_CHANGED , 4). --define(QUIC_CONNECTION_EVENT_PEER_ADDRESS_CHANGED , 5). --define(QUIC_CONNECTION_EVENT_PEER_STREAM_STARTED , 6). --define(QUIC_CONNECTION_EVENT_STREAMS_AVAILABLE , 7). --define(QUIC_CONNECTION_EVENT_PEER_NEEDS_STREAMS , 8). --define(QUIC_CONNECTION_EVENT_IDEAL_PROCESSOR_CHANGED , 9). --define(QUIC_CONNECTION_EVENT_DATAGRAM_STATE_CHANGED , 10). --define(QUIC_CONNECTION_EVENT_DATAGRAM_RECEIVED , 11). --define(QUIC_CONNECTION_EVENT_DATAGRAM_SEND_STATE_CHANGED , 12). --define(QUIC_CONNECTION_EVENT_RESUMED , 13). --define(QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED , 14). --define(QUIC_CONNECTION_EVENT_PEER_CERTIFICATE_RECEIVED , 15). diff --git a/test/quicer_snb_SUITE.erl b/test/quicer_snb_SUITE.erl index 952cf67d..4a9a59bd 100644 --- a/test/quicer_snb_SUITE.erl +++ b/test/quicer_snb_SUITE.erl @@ -20,8 +20,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -%-include_lib("quicer/include/quicer.hrl"). --include("quicer_nif_macro.hrl"). +-include("quicer.hrl"). %%-------------------------------------------------------------------- %% @spec suite() -> Info @@ -126,6 +125,9 @@ all() -> , tc_slow_conn , tc_stream_owner_down , tc_conn_owner_down + , tc_conn_close_flag_1 + , tc_conn_close_flag_2 + , tc_stream_close_errno ]. %%-------------------------------------------------------------------- @@ -233,7 +235,7 @@ tc_slow_conn(Config) -> ok. tc_stream_owner_down(Config) -> - Port = 8888, +Port = 8888, ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} , {fast_conn, false} @@ -278,7 +280,7 @@ tc_stream_owner_down(Config) -> , resource_id := _Rid }, Trace)), - %% check that it triggered a immediate stream shutdown + %% check that it triggers a immediate stream shutdown ?assert(?strict_causality(#{ ?snk_kind := debug , function := "resource_stream_down_callback" , tag := "start" @@ -326,8 +328,9 @@ tc_conn_owner_down(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}]), - {ok, 4} = quicer:async_send(Stm, <<"ping">>), - quicer:recv(Stm, 4), + {ok, 4} = quicer:send(Stm, <<"ping">>), + {ok, <<"ping">>} = quicer:recv(Stm, 4), + {ok, SRid} = quicer:get_stream_rid(Stm), Pid = spawn(fun() -> receive down -> ok end end), @@ -335,83 +338,238 @@ tc_conn_owner_down(Config) -> Pid ! down, ?block_until( #{'$kind' := debug, context := "callback", - function := "ServerStreamCallback", mark := ?QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE, + function := "ServerConnectionCallback", mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE, tag := "event"}, 1000), ct:pal("stop listener"), - ok = quicer:stop_listener(mqtt) + ok = quicer:stop_listener(mqtt), + {ok, CRid} = quicer:get_conn_rid(Conn), + {CRid, SRid} end, fun(Result, Trace) -> - ct:pal("Trace is ~p", [Trace]), - ?assertEqual(ok, Result), + {CRid, SRid} = Result, + ct:pal("Rid is ~p~n Sid is ~p~nTrace is ~p, ", [CRid, SRid,Trace]), %% check that conn down callback is triggered when conn owner process is dead ?assert(?strict_causality(#{ ?snk_kind := debug , function := "connection_controlling_process" , tag := "exit" - , resource_id := _Rid + , resource_id := CRid }, #{ ?snk_kind := debug , function := "resource_conn_down_callback" , tag := "start" - , resource_id := _Rid + , resource_id := CRid }, Trace)), %% check that it triggered a immediate connection shutdown ?assert(?strict_causality(#{ ?snk_kind := debug , function := "resource_conn_down_callback" , tag := "end" - , resource_id := _Rid + , resource_id := CRid }, #{ ?snk_kind := debug , context := "callback" , function := "ClientConnectionCallback" , tag := "event" , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE - , resource_id := _Rid + , resource_id := CRid }, Trace)), %% check that client side immediate shutdown triggers a stream shutdown + ?assert(?causality(#{ ?snk_kind := debug + , function := "resource_conn_down_callback" + , tag := "end" + , resource_id := CRid + }, + #{ ?snk_kind := debug + , context := "callback" + , function := "ClientStreamCallback" + , mark := ?QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE + , tag := "event" + , resource_id := SRid + }, + Trace)), + %% check that client side conn shutdown happens after stream shutdown ?assert(?strict_causality(#{ ?snk_kind := debug - , function := "resource_conn_down_callback" - , tag := "end" - , resource_id := _Rid - }, - #{ ?snk_kind := debug , context := "callback" , function := "ClientStreamCallback" , mark := ?QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE , tag := "event" + , resource_id := SRid + }, + #{ ?snk_kind := debug + , context := "callback" + , function := "ClientConnectionCallback" + , tag := "event" + , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE + , resource_id := CRid }, Trace)), - %% check that client side conn shutdown happens after stream shutdown + %% check that client side immediate shutdown triggers a close at server side + ?assert(?strict_causality( #{ ?snk_kind := quic_shutdown + , module := quicer_conn_acceptor + , '~meta' := #{pid := _PID}}, + #{ ?snk_kind := quic_closed + , module := quicer_conn_acceptor + ,'~meta' := #{pid := _PID}}, + Trace)) + end), + ok. + + +tc_conn_close_flag_1(Config) -> + Port = 8888, + ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], + ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} + , {fast_conn, false} + , {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]), + ?check_trace(#{timetrap => 1000}, + begin + {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}]), + {ok, 4} = quicer:async_send(Stm, <<"ping">>), + quicer:recv(Stm, 4), + quicer:close_connection(Conn, ?QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 111), + ?block_until( + #{ ?snk_kind := debug + , context := "callback" + , function := "ServerConnectionCallback" + , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE + , tag := "event"}, 1000, 3000), + ?block_until( + #{ ?snk_kind := debug + , context := "callback" + , function := "ClientConnectionCallback" + , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE + , tag := "event"}, 1000, 3000), + ct:pal("stop listener"), + ok = quicer:stop_listener(mqtt) + end, + fun(Result, Trace) -> + ct:pal("Trace is ~p", [Trace]), + ?assertEqual(ok, Result), + %% verify that client close_connection with default flag + %% triggers a close at server side ?assert(?strict_causality(#{ ?snk_kind := debug , context := "callback" - , function := "ClientStreamCallback" - , mark := ?QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE + , function := "ServerConnectionCallback" + , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER , tag := "event" + , resource_id := _CRid }, #{ ?snk_kind := debug , context := "callback" - , function := "ClientConnectionCallback" + , function := "ServerConnectionCallback" , tag := "event" , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE + , resource_id := _CRid + }, + Trace)) + end), + ok. + +tc_conn_close_flag_2(Config) -> + Port = 8888, + ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], + ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} + , {fast_conn, false} + , {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]), + ?check_trace(#{timetrap => 1000}, + begin + {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}]), + {ok, 4} = quicer:async_send(Stm, <<"ping">>), + quicer:recv(Stm, 4), + quicer:close_connection(Conn, ?QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT, 111), + ?block_until( + #{?snk_kind := debug + , context := "callback" + , function := "ServerConnectionCallback" + , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE + , tag := "event"}, 3000, 3000), %% assume idle_timeout_is 5s + ct:pal("stop listener"), + ok = quicer:stop_listener(mqtt) + end, + fun(Result, Trace) -> + ct:pal("Trace is ~p", [Trace]), + ?assertEqual(ok, Result), + %% check that client conn silent shutdown does not trigger + %% active connection shutdown at server side + ?assertEqual([], ?of_kind(quic_closed, Trace)) + end), + ok. + +tc_stream_close_errno(Config) -> + Errno = 1234, + Port = 8888, + ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], + ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} + , {fast_conn, false} + , {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]), + ?check_trace(#{timetrap => 1000}, + begin + {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}]), + {ok, 4} = quicer:async_send(Stm, <<"ping">>), + quicer:recv(Stm, 4), + quicer:close_stream(Stm, ?QUIC_STREAM_SHUTDOWN_FLAG_ABORT_SEND, Errno, 5000), + quicer:close_connection(Conn), + ?block_until( + #{'$kind' := debug, context := "callback", + function := "ServerStreamCallback", mark := ?QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE, + tag := "event"}, 1000), + ct:pal("stop listener"), + ok = quicer:stop_listener(mqtt) + end, + fun(Result, Trace) -> + ct:pal("Trace is ~p", [Trace]), + ?assertEqual(ok, Result), + %% check that server side + ?assert(?strict_causality(#{ ?snk_kind := debug + , context := "callback" + , function := "ServerStreamCallback" + , tag := "event" + , mark := ?QUIC_STREAM_EVENT_PEER_SEND_ABORTED + }, + #{ ?snk_kind := debug + , context := "callback" + , function := "ServerStreamCallback" + , tag := "peer_send_aborted" + , mark := Errno }, Trace)), - %% check that client side immediate shutdown triggers a close at server side - ?assertMatch([{pair, _, _}], - ?find_pairs(true, - #{ ?snk_kind := debug - , context := "callback" - , function := "ClientConnectionCallback" - , tag := "event" - , mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE - }, - #{ ?snk_kind := quic_closed - , module := quicer_conn_acceptor - }, - Trace)) + ?assert(?strict_causality(#{ ?snk_kind := debug + , context := "callback" + , function := "ServerStreamCallback" + , tag := "event" + , mark := ?QUIC_STREAM_EVENT_PEER_SEND_ABORTED + }, + #{ ?snk_kind := peer_send_aborted + , module := quicer_stream + , reason := Errno + }, + Trace)) end), ok. + %%% Internal Helpers default_stream_opts() -> []. From 8fa92c1c57a49e23f7a3d3a56da7b22b2bb5da44 Mon Sep 17 00:00:00 2001 From: William Yang Date: Tue, 24 Aug 2021 16:46:22 +0200 Subject: [PATCH 6/7] chore: README update and some minor changes for conn/stream close --- README.md | 20 ++++++++++++++++---- c_src/quicer_ctx.c | 5 ++++- c_src/quicer_stream.c | 1 + src/quicer.erl | 3 ++- test/quicer_snb_SUITE.erl | 12 ++++++------ 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e6e04465..57ffd92d 100644 --- a/README.md +++ b/README.md @@ -169,13 +169,20 @@ quicer:connection(Hostname, Port, Options, Timeout) -> {ok, Connection} | {error, any()} | {error, any(), ErrorCode::integer()}. ``` -### close_connection +### Close_connection ``` erlang quicer:close_connection(Connection) -> ok. +quicer:close_connection(Connection, Timeout) -> ok. +quicer:close_connection(Connection, Flag, Reason) -> ok. +quicer:close_connection(Connection, Flag, Reason, Timeout) -> ok. + +Flag :: ?QUIC_CONNECTION_SHUTDOWN_FLAG_NONE | ?QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT. ``` -Gracefully Shutdown connection. +Shutdown connection with app specific reason, it also implicitly shuts down the streams. + +`QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT` is used for lowmem scenarios without sending a connection_close frame to the peer. ## Stream API @@ -253,10 +260,15 @@ note, the requested Len cannot exceeed the stream recv window size of connection ### Shutdown stream ``` erlang -quicer:close_stream(Stream) -> ok. +quicer:close_stream(Stream) -> ok | {error, any()}. +quicer:close_stream(Stream, Timeout) -> ok | {error, any()}. +quicer:close_stream(Stream, Flags, Reason, Timeout) -> ok | {error, any()}. ``` +Shutdown stream with an app specific reason (integer) indicate to the peer as the reason for the shutdown. + +Use flags to control of the behavior of shutdown, check ?QUIC_STREAM_SHUTDOWN_FLAG_* in =quicer.hrl= for more. -Shutdown stream gracefully. +note, could return error if wrong combination of flags are set. ### Get/Set Connection/Stream Opts diff --git a/c_src/quicer_ctx.c b/c_src/quicer_ctx.c index 1a30f11b..14137338 100644 --- a/c_src/quicer_ctx.c +++ b/c_src/quicer_ctx.c @@ -57,6 +57,8 @@ init_c_ctx() void destroy_c_ctx(QuicerConnCTX *c_ctx) { + // Since enif_release_resource is async call, + // we should demon the owner now! enif_demonitor_process(c_ctx->env, c_ctx, &c_ctx->owner_mon); enif_release_resource(c_ctx); } @@ -83,7 +85,8 @@ init_s_ctx() void destroy_s_ctx(QuicerStreamCTX *s_ctx) { - // note, see resource_stream_dealloc_callback + // Since enif_release_resource is async call, + // we should demon the owner now! enif_demonitor_process(s_ctx->env, s_ctx, &s_ctx->owner_mon); enif_release_resource(s_ctx); } diff --git a/c_src/quicer_stream.c b/c_src/quicer_stream.c index ac85b440..b0dfe2a6 100644 --- a/c_src/quicer_stream.c +++ b/c_src/quicer_stream.c @@ -607,6 +607,7 @@ close_stream3(ErlNifEnv *env, return ERROR_TUPLE_2(ATOM_BADARG); } + // only check type, actual flag will be validated by msquic if (!enif_get_uint(env, argv[1], &flags)) { return ERROR_TUPLE_2(ATOM_BADARG); diff --git a/src/quicer.erl b/src/quicer.erl index 2428888e..1611c80b 100644 --- a/src/quicer.erl +++ b/src/quicer.erl @@ -160,6 +160,7 @@ accept(LSock, Opts, Timeout) -> close_connection(Conn) -> close_connection(Conn, 5000). +-spec close_connection(connection_handler(), timer:timeout()) -> ok. close_connection(Conn, Timeout) -> close_connection(Conn, ?QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0, Timeout). @@ -167,7 +168,7 @@ close_connection(Conn, Timeout) -> close_connection(Conn, Flags, ErrorCode) -> close_connection(Conn, Flags, ErrorCode, 5000). --spec close_connection(connection_handler(), timer:timeout()) -> ok. +-spec close_connection(connection_handler(), non_neg_integer(), non_neg_integer(), timer:timeout()) -> ok. close_connection(Conn, Flags, ErrorCode, Timeout) -> ok = async_close_connection(Conn, Flags, ErrorCode), %% @todo make_ref diff --git a/test/quicer_snb_SUITE.erl b/test/quicer_snb_SUITE.erl index 4a9a59bd..011b807f 100644 --- a/test/quicer_snb_SUITE.erl +++ b/test/quicer_snb_SUITE.erl @@ -235,7 +235,7 @@ tc_slow_conn(Config) -> ok. tc_stream_owner_down(Config) -> -Port = 8888, + Port = 8888, ListenerOpts = [{conn_acceptors, 32} | default_listen_opts(Config)], ConnectionOpts = [ {conn_callback, quicer_server_conn_callback} , {fast_conn, false} @@ -258,7 +258,7 @@ Port = 8888, quicer:controlling_process(Stm, Pid), Pid ! down, ?block_until( - #{'$kind' := debug, context := "callback", + #{?snk_kind := debug, context := "callback", function := "ServerStreamCallback", mark := ?QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE, tag := "event"}, 1000), ct:pal("stop listener"), @@ -280,7 +280,7 @@ Port = 8888, , resource_id := _Rid }, Trace)), - %% check that it triggers a immediate stream shutdown + %% check that it triggers an immediate stream shutdown ?assert(?strict_causality(#{ ?snk_kind := debug , function := "resource_stream_down_callback" , tag := "start" @@ -337,7 +337,7 @@ tc_conn_owner_down(Config) -> quicer:controlling_process(Conn, Pid), Pid ! down, ?block_until( - #{'$kind' := debug, context := "callback", + #{?snk_kind := debug, context := "callback", function := "ServerConnectionCallback", mark := ?QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE, tag := "event"}, 1000), ct:pal("stop listener"), @@ -360,7 +360,7 @@ tc_conn_owner_down(Config) -> , resource_id := CRid }, Trace)), - %% check that it triggered a immediate connection shutdown + %% check that it triggers an immediate connection shutdown ?assert(?strict_causality(#{ ?snk_kind := debug , function := "resource_conn_down_callback" , tag := "end" @@ -532,7 +532,7 @@ tc_stream_close_errno(Config) -> quicer:close_stream(Stm, ?QUIC_STREAM_SHUTDOWN_FLAG_ABORT_SEND, Errno, 5000), quicer:close_connection(Conn), ?block_until( - #{'$kind' := debug, context := "callback", + #{?snk_kind := debug, context := "callback", function := "ServerStreamCallback", mark := ?QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE, tag := "event"}, 1000), ct:pal("stop listener"), From 506134cdc5f245515e58ce22eec9d2debfcd093b Mon Sep 17 00:00:00 2001 From: William Yang Date: Tue, 24 Aug 2021 17:54:02 +0200 Subject: [PATCH 7/7] chore: fix some code format --- src/quicer.erl | 92 ++++++++++++++++++++++++------------ src/quicer_conn_acceptor.erl | 9 ++-- src/quicer_listener.erl | 9 +++- src/quicer_listener_sup.erl | 4 +- src/quicer_nif.erl | 12 ++--- src/quicer_stream.erl | 14 +++--- 6 files changed, 91 insertions(+), 49 deletions(-) diff --git a/src/quicer.erl b/src/quicer.erl index 1611c80b..5408ec5a 100644 --- a/src/quicer.erl +++ b/src/quicer.erl @@ -74,6 +74,10 @@ -type connection_opts() :: proplists:proplist() | quicer_conn_acceptor:opts(). -type listener_opts() :: proplists:proplist() | quicer_listener:listener_opts(). +-type stream_shutdown_flags() :: non_neg_integer(). +-type conn_shutdown_flags() :: non_neg_integer(). +-type reason_int() :: non_neg_integer(). + -spec start_listener(atom(), inet:port_number(), {listener_opts(), connection_opts(), stream_opts()}) -> {ok, pid()} | {error, any()}. @@ -86,9 +90,9 @@ stop_listener(AppName) -> -spec listen(quicer_listener:listen_on(), proplists:proplists() | map()) -> {ok, listener_handler()} | {error, any()}. -listen(ListenOn, Opts) when is_list(Opts)-> +listen(ListenOn, Opts) when is_list(Opts) -> listen(ListenOn, maps:from_list(Opts)); -listen(ListenOn, Opts) when is_map(Opts)-> +listen(ListenOn, Opts) when is_map(Opts) -> quicer_nif:listen(ListenOn, Opts). -spec close_listener(listener_handler()) -> ok. @@ -103,7 +107,8 @@ connect(Host, Port, Opts, Timeout) when is_list(Opts) -> connect(Host, Port, Opts, Timeout) when is_tuple(Host) -> connect(inet:ntoa(Host), Port, Opts, Timeout); connect(Host, Port, Opts, _Timeout) when is_map(Opts) -> - case quicer_nif:async_connect(Host, Port, maps:merge(default_conn_opts(), Opts)) of + NewOpts = maps:merge(default_conn_opts(), Opts), + case quicer_nif:async_connect(Host, Port, NewOpts) of {ok, _H} -> receive {quic, connected, Ctx} -> @@ -146,7 +151,8 @@ accept(LSock, Opts, Timeout) when is_list(Opts) -> accept(LSock, maps:from_list(Opts), Timeout); accept(LSock, Opts, Timeout) -> % non-blocking - {ok, LSock} = quicer_nif:async_accept(LSock, maps:merge(default_conn_opts(), Opts)), + NewOpts = maps:merge(default_conn_opts(), Opts), + {ok, LSock} = quicer_nif:async_accept(LSock, NewOpts), receive {quic, new_conn, C} -> {ok, C}; @@ -164,11 +170,17 @@ close_connection(Conn) -> close_connection(Conn, Timeout) -> close_connection(Conn, ?QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0, Timeout). --spec close_connection(connection_handler(), non_neg_integer(), non_neg_integer()) -> ok. +-spec close_connection(connection_handler(), + conn_shutdown_flags(), + reason_int() + ) -> ok. close_connection(Conn, Flags, ErrorCode) -> close_connection(Conn, Flags, ErrorCode, 5000). --spec close_connection(connection_handler(), non_neg_integer(), non_neg_integer(), timer:timeout()) -> ok. +-spec close_connection(connection_handler(), + conn_shutdown_flags(), + reason_int(), + timer:timeout()) -> ok. close_connection(Conn, Flags, ErrorCode, Timeout) -> ok = async_close_connection(Conn, Flags, ErrorCode), %% @todo make_ref @@ -183,11 +195,13 @@ close_connection(Conn, Flags, ErrorCode, Timeout) -> async_close_connection(Conn) -> quicer_nif:async_close_connection(Conn, ?QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0). --spec async_close_connection(connection_handler(), non_neg_integer(), non_neg_integer()) -> ok. +-spec async_close_connection(connection_handler(), + conn_shutdown_flags(), + reason_int()) -> ok. async_close_connection(Conn, Flags, ErrorCode) -> quicer_nif:async_close_connection(Conn, Flags, ErrorCode). --spec accept_stream(connection_handler(), proplists:proplist() | map()) -> +-spec accept_stream(connection_handler(), stream_opts()) -> {ok, stream_handler()} | {error, any()}. accept_stream(Conn, Opts) -> accept_stream(Conn, Opts, infinity). @@ -196,7 +210,8 @@ accept_stream(Conn, Opts, Timeout) when is_list(Opts) -> accept_stream(Conn, Opts, Timeout) when is_map(Opts) -> % @todo make_ref % @todo error handling - case quicer_nif:async_accept_stream(Conn, maps:merge(default_stream_opts(), Opts)) of + NewOpts = maps:merge(default_stream_opts(), Opts), + case quicer_nif:async_accept_stream(Conn, NewOpts) of {ok, Conn} -> receive {quic, new_stream, Stream} -> @@ -204,22 +219,22 @@ accept_stream(Conn, Opts, Timeout) when is_map(Opts) -> after Timeout -> {error, timeout} end; - {error, _} = E-> + {error, _} = E -> E end. -spec async_accept_stream(connection_handler(), proplists:proplist() | map()) -> {ok, connection_handler()} | {error, any()}. -async_accept_stream(Conn, Opts) when is_list(Opts)-> +async_accept_stream(Conn, Opts) when is_list(Opts) -> async_accept_stream(Conn, maps:from_list(Opts)); async_accept_stream(Conn, Opts) when is_map(Opts) -> quicer_nif:async_accept_stream(Conn, maps:merge(default_stream_opts(), Opts)). -spec start_stream(connection_handler(), proplists:proplists() | map()) -> {ok, stream_handler()} | {error, any()}. -start_stream(Conn, Opts) when is_list(Opts)-> +start_stream(Conn, Opts) when is_list(Opts) -> start_stream(Conn, maps:from_list(Opts)); -start_stream(Conn, Opts) when is_map(Opts)-> +start_stream(Conn, Opts) when is_map(Opts) -> quicer_nif:start_stream(Conn, maps:merge(default_stream_opts(), Opts)). @@ -280,8 +295,11 @@ close_stream(Stream) -> close_stream(Stream, Timeout) -> close_stream(Stream, ?QUIC_STREAM_SHUTDOWN_FLAG_GRACEFUL, 0, Timeout). --spec close_stream(stream_handler(), non_neg_integer(), non_neg_integer(), time:timeout()) - -> ok | {error, any()}. +-spec close_stream(stream_handler(), + stream_shutdown_flags(), + reason_int(), + time:timeout()) -> + ok | {error, any()}. close_stream(Stream, Flags, ErrorCode, Timeout) -> case async_close_stream(Stream, Flags, ErrorCode) of ok -> @@ -295,12 +313,14 @@ close_stream(Stream, Flags, ErrorCode, Timeout) -> Err end. - -spec async_close_stream(stream_handler()) -> ok | {error, any()}. async_close_stream(Stream) -> quicer_nif:async_close_stream(Stream, ?QUIC_STREAM_SHUTDOWN_FLAG_GRACEFUL, 0). --spec async_close_stream(stream_handler(), non_neg_integer(), non_neg_integer()) -> ok | {error, any()}. +-spec async_close_stream(stream_handler(), + stream_shutdown_flags(), + reason_int()) + -> ok | {error, any()}. async_close_stream(Stream, Flags, Reason) -> quicer_nif:async_close_stream(Stream, Flags, Reason). @@ -309,13 +329,19 @@ async_close_stream(Stream, Flags, Reason) -> sockname(Conn) -> quicer_nif:sockname(Conn). --spec getopt(Handle::connection_handler() | stream_handler() | listener_handler(), - Optname::atom()) -> {ok, OptVal::any()} | {error, any()}. +-spec getopt(Handle::connection_handler() + | stream_handler() + | listener_handler(), + Optname::atom()) -> + {ok, OptVal::any()} | {error, any()}. getopt(Handle, Opt) -> quicer_nif:getopt(Handle, Opt, true). --spec getopt(Handle::connection_handler() | stream_handler() | listener_handler(), - Optname::atom(), IsRaw::boolean()) -> {ok, OptVal::any()} | {error, any()}. +-spec getopt(Handle::connection_handler() + | stream_handler() + | listener_handler(), + Optname::atom(), IsRaw::boolean()) + -> {ok, OptVal::any()} | {error, any()}. getopt(Handle, Opt, IsRaw) -> quicer_nif:getopt(Handle, Opt, IsRaw). @@ -324,11 +350,11 @@ setopt(Handle, Opt, Value) when is_list(Value) -> setopt(Handle, Opt, Value) -> quicer_nif:setopt(Handle, Opt, Value). --spec get_stream_id(Stream::stream_handler()) -> {ok, integer()} | {error, any()}. +-spec get_stream_id(Stream::stream_handler()) -> + {ok, integer()} | {error, any()}. get_stream_id(Stream) -> quicer_nif:getopt(Stream, param_stream_id, false). - -spec getstat(connection_handler(), [inet:stat_option()]) -> {ok, list()} | {error, any()}. getstat(Conn, Cnts) -> @@ -349,24 +375,30 @@ getstat(Conn, Cnts) -> peername(Handle) -> quicer_nif:getopt(Handle, param_conn_remote_address, false). --spec get_conn_rid(connection_handler()) -> {ok, non_neg_integer()} | {error, any()}. +-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()}. +-spec get_stream_rid(stream_handler()) -> + {ok, non_neg_integer()} | {error, any()}. get_stream_rid(Stream) -> quicer_nif:get_stream_rid(Stream). --spec listeners() -> [{{quicer_listener:listener_name(), quicer_listener:listen_on()}, pid()}]. +-spec listeners() -> [{{ quicer_listener:listener_name() + , quicer_listener:listen_on()}, + pid()}]. listeners() -> quicer_listener_sup:listeners(). -spec listener(quicer_listener:listener_name() - | {quicer_listener:listener_name(), quicer_listener:listen_on()}) -> pid(). + | {quicer_listener:listener_name(), + quicer_listener:listen_on()}) -> pid(). listener(Name) -> quicer_listener_sup:listener(Name). --spec controlling_process(stream_handler() | connection_handler(), pid()) -> ok | {error, any()}. +-spec controlling_process(stream_handler() | connection_handler(), + pid()) -> ok | {error, any()}. controlling_process(Handler, Pid) -> quicer_nif:controlling_process(Handler, Pid). @@ -384,10 +416,10 @@ stats_map(send_pend) -> stats_map(_) -> undefined. -default_stream_opts()-> +default_stream_opts() -> #{active => true}. -default_conn_opts()-> +default_conn_opts() -> #{ peer_bidi_stream_count => 1 , peer_unidi_stream_count => 1 }. diff --git a/src/quicer_conn_acceptor.erl b/src/quicer_conn_acceptor.erl index e189d278..0b280ddc 100644 --- a/src/quicer_conn_acceptor.erl +++ b/src/quicer_conn_acceptor.erl @@ -30,7 +30,9 @@ -record(state, { listener :: quicer:listener_handler() , sup :: pid() , conn = undefined - , opts :: {quicer_listener:listener_opts(), conn_opts(), quicer_steam:stream_opts()} + , opts :: {quicer_listener:listener_opts(), + conn_opts(), + quicer_steam:stream_opts()} , callback :: module() , callback_state :: map() , slow_start :: boolean() @@ -78,7 +80,7 @@ init([Listener, {_, #{conn_callback := CallbackModule} = COpts, SOpts} = Opts, S {ok, Listener} = quicer_nif:async_accept(Listener, COpts), {ok, #state{ listener = Listener , callback = CallbackModule - , callback_state = CallbackModule:init(COpts#{stream_opts => SOpts} ) + , callback_state = CallbackModule:init(COpts#{stream_opts => SOpts}) , opts = Opts , slow_start = not maps:get(fast_conn, COpts, false) , sup = Sup}}. @@ -127,7 +129,8 @@ handle_cast(_Request, State) -> {noreply, NewState :: term(), Timeout :: timeout()} | {noreply, NewState :: term(), hibernate} | {stop, Reason :: normal | term(), NewState :: term()}. -handle_info({quic, new_conn, C}, #state{callback = M, sup = Sup, callback_state = CBState} = State) -> +handle_info({quic, new_conn, C}, + #state{callback = M, sup = Sup, callback_state = CBState} = State) -> ?tp(quic_new_conn, #{module=>?MODULE, conn=>C}), %% I become the connection owner, I should start an new acceptor. supervisor:start_child(Sup, [Sup]), diff --git a/src/quicer_listener.erl b/src/quicer_listener.erl index 498bd2d5..2bf676f0 100644 --- a/src/quicer_listener.erl +++ b/src/quicer_listener.erl @@ -50,7 +50,11 @@ %%-------------------------------------------------------------------- -spec start_link(Name :: listener_name(), ListenOn :: listen_on(), - Options :: {listener_opts(), quicer_conn_acceptor:opts(), quicer_stream:stream_opts()} + Options :: + { listener_opts() + , quicer_conn_acceptor:opts() + , quicer_stream:stream_opts() + } ) -> {ok, Pid :: pid()} | {error, Error :: {already_started, pid()}} | {error, Error :: term()} | @@ -82,7 +86,8 @@ stop_listener(Name) -> init([Name, ListenOn, {LOpts, COpts, SOpts}]) when is_list(LOpts) -> init([Name, ListenOn, {maps:from_list(LOpts), COpts, SOpts}]); -init([Name, ListenOn, {#{conn_acceptors := N, alpn := Alpn} = LOpts, _COpts, _SOpts} = Opts]) -> +init([Name, ListenOn, { #{conn_acceptors := N, alpn := Alpn} = LOpts, + _COpts, _SOpts} = Opts]) -> process_flag(trap_exit, true), {ok, L} = quicer:listen(ListenOn, LOpts), {ok, ConnSup} = supervisor:start_link(quicer_conn_acceptor_sup, [L, Opts]), diff --git a/src/quicer_listener_sup.erl b/src/quicer_listener_sup.erl index 66bbad76..3b124953 100644 --- a/src/quicer_listener_sup.erl +++ b/src/quicer_listener_sup.erl @@ -71,7 +71,7 @@ listeners() -> -spec listener(atom() | {atom(), integer()|string()}) -> pid(). listener({Name, _ListenOn}) when is_atom(Name) -> listener(Name); -listener(Name) when is_atom(Name)-> +listener(Name) when is_atom(Name) -> [Target] = lists:filtermap( fun({?CHILD_ID(Id), Child, _Type, _Modules}) when Id =:= Name -> {true, Child}; @@ -105,7 +105,7 @@ init([]) -> %%%=================================================================== %%% Internal functions %%%=================================================================== -chid_spec(AppName, ListenOn, Options)-> +chid_spec(AppName, ListenOn, Options) -> #{ id => ?CHILD_ID(AppName) , start => {quicer_listener, start_link, [AppName, ListenOn, Options]} , restart => transient diff --git a/src/quicer_nif.erl b/src/quicer_nif.erl index b47cc0c1..9f73f1b8 100644 --- a/src/quicer_nif.erl +++ b/src/quicer_nif.erl @@ -69,25 +69,25 @@ reg_open() -> reg_close() -> erlang:nif_error(nif_library_not_loaded). -listen(_Port, _Options)-> +listen(_Port, _Options) -> erlang:nif_error(nif_library_not_loaded). close_listener(_Listener) -> erlang:nif_error(nif_library_not_loaded). -async_connect(_Host, _Port, _Opts)-> +async_connect(_Host, _Port, _Opts) -> erlang:nif_error(nif_library_not_loaded). async_accept(_Listener, _Opts) -> erlang:nif_error(nif_library_not_loaded). -async_handshake(_Connection)-> +async_handshake(_Connection) -> erlang:nif_error(nif_library_not_loaded). async_close_connection(_Conn, _Flags, _ErrorCode) -> erlang:nif_error(nif_library_not_loaded). -async_accept_stream(_Conn, _Opts)-> +async_accept_stream(_Conn, _Opts) -> erlang:nif_error(nif_library_not_loaded). start_stream(_Conn, _Opts) -> @@ -111,10 +111,10 @@ getopt(_Handle, _Optname, _IsRaw) -> setopt(_Handle, _Opt, _Value) -> erlang:nif_error(nif_library_not_loaded). -get_conn_rid(_Handle)-> +get_conn_rid(_Handle) -> erlang:nif_error(nif_library_not_loaded). -get_stream_rid(_Handle)-> +get_stream_rid(_Handle) -> erlang:nif_error(nif_library_not_loaded). controlling_process(_H, _P) -> diff --git a/src/quicer_stream.erl b/src/quicer_stream.erl index c7a702d9..306a0031 100644 --- a/src/quicer_stream.erl +++ b/src/quicer_stream.erl @@ -164,7 +164,8 @@ handle_info({quic, _Bin, StreamA, _, _, _}, #state{stream = StreamB} = State) ?tp(inval_stream_data, #{module=>?MODULE, stream_a=>StreamA, stream_b => StreamB}), {stop, wrong_stream, State}; -handle_info({quic, peer_send_aborted, Stream, Reason}, #state{stream = Stream, opts = Options} = State) -> +handle_info({quic, peer_send_aborted, Stream, Reason}, + #state{stream = Stream, opts = Options} = State) -> ?tp(peer_send_aborted, #{module=>?MODULE, stream=>Stream, reason=>Reason}), #{stream_callback := CallbackModule} = Options, case erlang:function_exported(CallbackModule, peer_send_aborted, 3) of @@ -175,7 +176,8 @@ handle_info({quic, peer_send_aborted, Stream, Reason}, #state{stream = Stream, o {noreply, State} end; -handle_info({quic, peer_send_shutdown, Stream}, #state{stream = Stream, opts = Options} = State) -> +handle_info({quic, peer_send_shutdown, Stream}, + #state{stream = Stream, opts = Options} = State) -> ?tp(peer_shutdown, #{module=>?MODULE, stream=>Stream}), #{stream_callback := CallbackModule} = Options, CallbackModule:shutdown(Stream), @@ -229,16 +231,16 @@ format_status(_Opt, Status) -> %%%=================================================================== %%% Internal functions %%%=================================================================== -error_code(normal)-> +error_code(normal) -> 'QUIC_ERROR_NO_ERROR'; -error_code(shutdown)-> +error_code(shutdown) -> 'QUIC_ERROR_NO_ERROR'; -error_code(_)-> +error_code(_) -> %% @todo mapping errors to error code %% for closing stream 'QUIC_ERROR_INTERNAL_ERROR'. -maybe_log_stracetrace(ST)-> +maybe_log_stracetrace(ST) -> logger:error("~p~n", [ST]), ok.