Skip to content

Commit

Permalink
Merge pull request #221 from qzhuyan/dev/william/track-listeners-in-reg
Browse files Browse the repository at this point in the history
track listeners in registration
  • Loading branch information
qzhuyan authored Sep 29, 2023
2 parents 42e896d + c711b6f commit 1f6c1a9
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 4 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ xref:

.PHONY: eunit
eunit:
$(REBAR) eunit -v -c --cover_export_name eunit
$(REBAR) eunit -v -c --cover_export_name eunit

.PHONY: ct
ct:
QUICER_USE_SNK=1 $(REBAR) as test ct -v
QUICER_USE_SNK=1 $(REBAR) as test ct -v --readable=true

.PHONY: cover
cover: eunit
Expand Down
22 changes: 22 additions & 0 deletions c_src/quicer_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ init_r_ctx()
r_ctx->env = enif_alloc_env();
r_ctx->Registration = NULL;
r_ctx->is_released = FALSE;
r_ctx->lock = enif_mutex_create("quicer:r_ctx");
CxPlatListInitializeHead(&r_ctx->Listeners);
CxPlatListInitializeHead(&r_ctx->Connections);
return r_ctx;
}

void
deinit_r_ctx(QuicerRegistrationCTX *r_ctx)
{
enif_free_env(r_ctx->env);
enif_mutex_destroy(r_ctx->lock);
}

void
Expand Down Expand Up @@ -67,6 +71,7 @@ init_l_ctx()
l_ctx->is_closed = TRUE;
l_ctx->allow_insecure = FALSE;
l_ctx->r_ctx = NULL;
CxPlatListInitializeHead(&l_ctx->RegistrationLink);
return l_ctx;
}

Expand All @@ -93,6 +98,23 @@ deinit_l_ctx(QuicerListenerCTX *l_ctx)
void
destroy_l_ctx(QuicerListenerCTX *l_ctx)
{
QuicerRegistrationCTX *r_ctx;
if (l_ctx->r_ctx)
{
r_ctx = l_ctx->r_ctx;
}
else
{
r_ctx = G_r_ctx;
}

if (r_ctx)
{
enif_mutex_lock(r_ctx->lock);
CxPlatListEntryRemove(&l_ctx->RegistrationLink);
enif_mutex_unlock(r_ctx->lock);
}

// @note, Destroy config asap as it holds rundown
// ref count in registration
destroy_config_ctx(l_ctx->config_resource);
Expand Down
4 changes: 4 additions & 0 deletions c_src/quicer_ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ typedef struct QuicerRegistrationCTX
HQUIC Registration;
BOOLEAN is_released;
char name[UINT8_MAX + 1];
ErlNifMutex *lock;
CXPLAT_LIST_ENTRY Listeners;
CXPLAT_LIST_ENTRY Connections;
} QuicerRegistrationCTX;

/*
Expand Down Expand Up @@ -65,6 +68,7 @@ typedef struct QuicerListenerCTX
BOOLEAN is_closed;
BOOLEAN is_stopped;
BOOLEAN allow_insecure;
CXPLAT_LIST_ENTRY RegistrationLink;
void *reserved1;
void *reserved2;
void *reserved3;
Expand Down
43 changes: 43 additions & 0 deletions c_src/quicer_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ listen2(ErlNifEnv *env, __unused_parm__ int argc, const ERL_NIF_TERM argv[])
HQUIC Registration = NULL;
char *cacertfile = NULL;

QuicerRegistrationCTX *target_r_ctx = NULL;

if (!enif_is_map(env, options))
{
return ERROR_TUPLE_2(ATOM_BADARG);
Expand Down Expand Up @@ -324,9 +326,12 @@ listen2(ErlNifEnv *env, __unused_parm__ int argc, const ERL_NIF_TERM argv[])
// quic_registration is set
enif_keep_resource(l_ctx->r_ctx);
Registration = l_ctx->r_ctx->Registration;
target_r_ctx = l_ctx->r_ctx;
}
else
{
target_r_ctx = G_r_ctx;

// quic_registration is not set, use global registration
// msquic should reject if global registration is NULL (closed)
if (G_r_ctx)
Expand Down Expand Up @@ -378,6 +383,13 @@ listen2(ErlNifEnv *env, __unused_parm__ int argc, const ERL_NIF_TERM argv[])
}
l_ctx->is_closed = FALSE;

// Link to registration
if (target_r_ctx)
{
enif_mutex_lock(target_r_ctx->lock);
CxPlatListInsertTail(&target_r_ctx->Listeners, &l_ctx->RegistrationLink);
enif_mutex_unlock(target_r_ctx->lock);
}
unsigned alpn_buffer_length = 0;
QUIC_BUFFER alpn_buffers[MAX_ALPN];

Expand Down Expand Up @@ -559,3 +571,34 @@ start_listener3(ErlNifEnv *env,

return ret;
}

ERL_NIF_TERM
get_listenersX(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
QuicerRegistrationCTX *r_ctx = NULL;
if (argc == 0)
{
r_ctx = G_r_ctx;
}
else
{
if (!enif_get_resource(env, argv[0], ctx_reg_t, (void **)&r_ctx))
{
return ERROR_TUPLE_2(ATOM_BADARG);
}
}
ERL_NIF_TERM res = enif_make_list(env, 0);

enif_mutex_lock(r_ctx->lock);
CXPLAT_LIST_ENTRY *Entry = r_ctx->Listeners.Flink;
while (Entry != &r_ctx->Listeners)
{
QuicerListenerCTX *l_ctx = CXPLAT_CONTAINING_RECORD(
Entry, QuicerListenerCTX, RegistrationLink);
res = enif_make_list_cell(env, enif_make_resource(env, l_ctx), res);
Entry = Entry->Flink;
}
enif_mutex_unlock(r_ctx->lock);

return res;
}
3 changes: 3 additions & 0 deletions c_src/quicer_listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ stop_listener1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM
close_listener1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);

ERL_NIF_TERM
get_listenersX(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);

#endif // __QUICER_LISTENER_H_
4 changes: 3 additions & 1 deletion c_src/quicer_nif.c
Original file line number Diff line number Diff line change
Expand Up @@ -1459,7 +1459,9 @@ static ErlNifFunc nif_funcs[] = {
{ "peercert", 1, peercert1, 0},
/* for DEBUG */
{ "get_conn_rid", 1, get_conn_rid1, 1},
{ "get_stream_rid", 1, get_stream_rid1, 1}
{ "get_stream_rid", 1, get_stream_rid1, 1},
{ "get_listeners", 0, get_listenersX, 0},
{ "get_listeners", 1, get_listenersX, 0}
// clang-format on
};

Expand Down
6 changes: 6 additions & 0 deletions c_src/quicer_reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ deregistration(__unused_parm__ ErlNifEnv *env,
__unused_parm__ int argc,
__unused_parm__ const ERL_NIF_TERM argv[])
{
// @TODO error_code should be configurable
int error_code = 0;
if (!MsQuic)
{
Expand All @@ -96,6 +97,11 @@ deregistration(__unused_parm__ ErlNifEnv *env,
if (G_r_ctx && !G_r_ctx->is_released)
{
MsQuic->RegistrationShutdown(G_r_ctx->Registration, FALSE, error_code);
// Do not defer the closing the global registration
// to resource dealloc callback because a common scenario is to
// close the lib after close the global registration.
MsQuic->RegistrationClose(G_r_ctx->Registration);
G_r_ctx->Registration = NULL;
destroy_r_ctx(G_r_ctx);
G_r_ctx = NULL;
}
Expand Down
14 changes: 14 additions & 0 deletions src/quicer.erl
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@
-export([ get_conn_rid/1
, get_stream_rid/1
, open_connection/0
, get_listeners/0
, get_listeners/1
]).

-export([ spawn_listener/3 %% start application over quic
Expand Down Expand Up @@ -961,6 +963,18 @@ listeners() ->
listener(Name) ->
quicer_listener_sup:listener(Name).

%% @doc Get a list listeners under global registration
-spec get_listeners() -> quicer_nif:get_listeners().
get_listeners() ->
quicer_nif:get_listeners().

%% @doc Get a list of listeners under registration handle
-spec get_listeners(Reg | global) -> quicer_nif:get_listeners(Reg).
get_listeners(global) ->
quicer_nif:get_listeners();
get_listeners(Reg) ->
quicer_nif:get_listeners(Reg).

%% @doc set controlling process for Connection/Stream.
%% mimic {@link ssl:controlling_process/2}
%% @see wait_for_handoff/2
Expand Down
10 changes: 10 additions & 0 deletions src/quicer_nif.erl
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
%% For tests only
-export([ open_connection/0
, open_connection/1
, get_listeners/0
, get_listeners/1
]).

-on_load(init/0).
Expand Down Expand Up @@ -277,6 +279,14 @@ controlling_process(_H, _P) ->
peercert(_Handle) ->
erlang:nif_error(nif_library_not_loaded).

-spec get_listeners() -> [listener_handle()].
get_listeners() ->
erlang:nif_error(nif_library_not_loaded).

-spec get_listeners(reg_handle()) -> [listener_handle()] | {error, badarg}.
get_listeners(_RegHandle) ->
erlang:nif_error(nif_library_not_loaded).

%% Internals
-spec locate_lib(file:name(), file:name()) ->
{ok, file:filename()} | {error, not_found}.
Expand Down
2 changes: 2 additions & 0 deletions test/quicer_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ tc_nif_module_reload(_Config) ->
M = quicer_nif,
c:l(M),
{module, M} = c:l(M),
code:purge(M),
true = code:delete(M),
ok.

tc_open_lib_test(_Config) ->
Expand Down
12 changes: 11 additions & 1 deletion test/quicer_listener_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ init_per_testcase(_TestCase, Config) ->
%% Reason = term()
%% @end
%%--------------------------------------------------------------------
end_per_testcase(_TestCase, _Config) ->
end_per_testcase(_TestCase, Config) ->
RegH = proplists:get_value(quic_registration, Config, global),
[quicer:close_listener(L, 1000) || L <- quicer:get_listeners(RegH)],
ok.

%%--------------------------------------------------------------------
Expand Down Expand Up @@ -488,6 +490,14 @@ tc_verify_none_butwith_cacert(Config)->
quicer:terminate_listener(?FUNCTION_NAME),
ok.

tc_get_listeners_from_reg(Config) ->
Port = select_port(),
RegH = proplists:get_value(quic_registration, Config, global),
{ok, L1} = quicer:listen(Port, default_listen_opts(Config)),
Port2 = select_port(),
{ok, L2} = quicer:listen(Port2, default_listen_opts(Config)),
?assertEqual([L2, L1], quicer:get_listeners(RegH)).

select_port() ->
Port = select_free_port(quic),
timer:sleep(100),
Expand Down

0 comments on commit 1f6c1a9

Please sign in to comment.