Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: list connections under registration #231

Merged
merged 1 commit into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions c_src/quicer_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ limitations under the License.
#include <unistd.h>

extern QuicerRegistrationCTX *G_r_ctx;
extern pthread_mutex_t GRegLock;

#if defined(DEBUG) && !defined(QUICER_LOGGING_STDOUT)
extern inline void
Expand Down Expand Up @@ -606,6 +607,15 @@ open_connectionX(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
}

CxPlatRefInitialize(&(c_ctx->ref_count));

// link to registration
if (r_ctx)
{
enif_mutex_lock(r_ctx->lock);
CxPlatListInsertTail(&r_ctx->Connections, &c_ctx->RegistrationLink);
enif_mutex_unlock(r_ctx->lock);
}

eHandle = enif_make_resource(env, c_ctx);
return SUCCESS(eHandle);

Expand Down Expand Up @@ -787,6 +797,13 @@ async_connect3(ErlNifEnv *env,
}
}
c_ctx->is_closed = FALSE; // connection opened.
//
if (!is_reuse_handle && r_ctx)
{
enif_mutex_lock(r_ctx->lock);
CxPlatListInsertTail(&r_ctx->Connections, &c_ctx->RegistrationLink);
enif_mutex_unlock(r_ctx->lock);
}

// optional set sslkeylogfile
parse_sslkeylogfile_option(env, eoptions, c_ctx);
Expand Down Expand Up @@ -1670,6 +1687,50 @@ parse_conn_event_mask(ErlNifEnv *env,
return ATOM_OK;
}

ERL_NIF_TERM
get_connectionsX(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
QuicerRegistrationCTX *r_ctx = NULL;
ERL_NIF_TERM res = enif_make_list(env, 0);
if (argc == 0) // use global registration
{
pthread_mutex_lock(&GRegLock);
if (!G_r_ctx)
{
pthread_mutex_unlock(&GRegLock);
return res;
}
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);
}
}
enif_mutex_lock(r_ctx->lock);
CXPLAT_LIST_ENTRY *Entry = r_ctx->Connections.Flink;
while (Entry != &r_ctx->Connections)
{
QuicerConnCTX *c_ctx
= CXPLAT_CONTAINING_RECORD(Entry, QuicerConnCTX, RegistrationLink);
if (get_conn_handle(c_ctx))
{
res = enif_make_list_cell(env, enif_make_resource(env, c_ctx), res);
put_conn_handle(c_ctx);
}
Entry = Entry->Flink;
}
enif_mutex_unlock(r_ctx->lock);

if (argc == 0) // use global registration
{
pthread_mutex_unlock(&GRegLock);
}
return res;
}

///_* Emacs
///====================================================================
/// Local Variables:
Expand Down
3 changes: 3 additions & 0 deletions c_src/quicer_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,7 @@ QUIC_STATUS continue_connection_handshake(QuicerConnCTX *c_ctx);
ERL_NIF_TERM
peercert1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);

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

#endif // __QUICER_CONNECTION_H_
16 changes: 16 additions & 0 deletions c_src/quicer_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ init_c_ctx()
c_ctx->is_closed = TRUE; // init
c_ctx->config_resource = NULL;
c_ctx->peer_cert = NULL;
CxPlatListInitializeHead(&c_ctx->RegistrationLink);
return c_ctx;
}

Expand Down Expand Up @@ -188,6 +189,21 @@ destroy_c_ctx(QuicerConnCTX *c_ctx)
X509_STORE_free(c_ctx->trusted);
c_ctx->trusted = NULL;
}

QuicerRegistrationCTX *r_ctx;
if (c_ctx->r_ctx)
{
r_ctx = c_ctx->r_ctx;
}
else
{
r_ctx = G_r_ctx;
}

enif_mutex_lock(r_ctx->lock);
CxPlatListEntryRemove(&c_ctx->RegistrationLink);
enif_mutex_unlock(r_ctx->lock);

enif_demonitor_process(c_ctx->env, c_ctx, &c_ctx->owner_mon);
enif_release_resource(c_ctx);
}
Expand Down
1 change: 1 addition & 0 deletions c_src/quicer_ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ typedef struct QuicerConnCTX
// for client, alloc on its own
QuicerConfigCTX *config_resource;
QuicerRegistrationCTX *r_ctx;
CXPLAT_LIST_ENTRY RegistrationLink;
HQUIC Connection;
QUICER_ACCEPTOR_QUEUE *acceptor_queue;
ACCEPTOR *owner;
Expand Down
18 changes: 18 additions & 0 deletions c_src/quicer_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ ServerListenerCallback(__unused_parm__ HQUIC Listener,
// Note, c_ctx is newly init here, don't grab lock.
//
c_ctx = init_c_ctx();
c_ctx->r_ctx = l_ctx->r_ctx;
ErlNifEnv *env = c_ctx->env;

if (!c_ctx)
Expand Down Expand Up @@ -195,6 +196,23 @@ ServerListenerCallback(__unused_parm__ HQUIC Listener,
(void *)ServerConnectionCallback,
c_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);
CxPlatListInsertTail(&r_ctx->Connections, &c_ctx->RegistrationLink);
enif_mutex_unlock(r_ctx->lock);
}

c_ctx->is_closed = FALSE; // new connection
enif_clear_env(env);
break;
Expand Down
4 changes: 3 additions & 1 deletion c_src/quicer_nif.c
Original file line number Diff line number Diff line change
Expand Up @@ -1568,7 +1568,9 @@ static ErlNifFunc nif_funcs[] = {
{ "get_conn_rid", 1, get_conn_rid1, 1},
{ "get_stream_rid", 1, get_stream_rid1, 1},
{ "get_listeners", 0, get_listenersX, 0},
{ "get_listeners", 1, get_listenersX, 0}
{ "get_listeners", 1, get_listenersX, 0},
{ "get_connections", 0, get_connectionsX, 0},
{ "get_connections", 1, get_connectionsX, 0},
// clang-format on
};

Expand Down
15 changes: 15 additions & 0 deletions src/quicer.erl
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@
, open_connection/0
, get_listeners/0
, get_listeners/1
, get_connections/0
, get_connections/1
, close_registration/1
]).

Expand Down Expand Up @@ -990,6 +992,19 @@ get_listeners(global) ->
get_listeners(Reg) ->
quicer_nif:get_listeners(Reg).


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

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

%% @doc set controlling process for Connection/Stream.
%% mimic {@link ssl:controlling_process/2}
%% @see wait_for_handoff/2
Expand Down
12 changes: 11 additions & 1 deletion src/quicer_nif.erl
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
, open_connection/1
, get_listeners/0
, get_listeners/1
, get_connections/0
, get_connections/1
]).

-export([abi_version/0]).
Expand Down Expand Up @@ -310,7 +312,15 @@ get_listeners() ->
erlang:nif_error(nif_library_not_loaded).

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

-spec get_connections() -> [connection_handle()].
get_connections() ->
erlang:nif_error(nif_library_not_loaded).

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

%% Internals
Expand Down
33 changes: 33 additions & 0 deletions test/quicer_connection_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,39 @@ tc_conn_opt_local_uni_stream_count(Config) ->
ct:fail("listener_timeout")
end.

tc_conn_list(Config) ->
Port = select_port(),
Owner = self(),
{SPid, _Ref} = spawn_monitor(fun() -> echo_server(Owner, Config, Port) end),
Reg = proplists:get_value(quic_registration, Config, undefined),
receive
listener_ready ->
case Reg of
undefined ->
?assertEqual(0, length(quicer:get_connections()));
Reg ->
?assertEqual(0, length(quicer:get_connections(Reg)))
end
after 5000 ->
ct:fail("listener_timeout")
end,
{ok, Conn} = quicer:connect("127.0.0.1", Port, default_conn_opts(Config), 5000),
{ok, Stm} = quicer:start_stream(Conn, []),
{ok, 4} = quicer:send(Stm, <<"ping">>),
{ok, Cnt} = quicer:getopt(Conn, param_conn_local_unidi_stream_count),
?assert(is_integer(Cnt)),
Conns = case Reg of
undefined ->
quicer:get_connections();
Reg ->
quicer:get_connections(Reg)
end,
?assertEqual(2, length(Conns)),

{ok, ClientName} = quicer:sockname(Conn),
?assertMatch([{ok, ClientName}, {ok, {_, Port}}],
lists:map(fun quicer:peername/1, Conns)),
SPid ! done.

%%%
%%% Helpers
Expand Down
Loading