Skip to content

Commit 1f933bc

Browse files
authored
Merge pull request #328 from qzhuyan/dev/william/dyn-acceptors-2
- Dynamic config listener acceptors - probe conn state with zero len datagram
2 parents a9687f4 + 93cc21c commit 1f933bc

26 files changed

+590
-121
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ proper:
4747
.PHONY: proper-cover
4848
proper-cover:
4949
mkdir -p coverage
50-
QUICER_TEST_COVER=1 $(REBAR) as test proper -c -n 1000
50+
QUICER_TEST_COVER=1 $(REBAR) as test proper -c -n 1000 --noshrink
5151
lcov -c --directory c_build/CMakeFiles/quicer_nif.dir/c_src/ \
5252
--exclude "${PWD}/msquic/src/inc/*" \
5353
--output-file ./coverage/proper-lcov.info

c_src/quicer_connection.c

+44-44
Original file line numberDiff line numberDiff line change
@@ -899,18 +899,13 @@ async_accept2(ErlNifEnv *env,
899899
const ERL_NIF_TERM argv[])
900900
{
901901
ERL_NIF_TERM listener = argv[0];
902-
ERL_NIF_TERM conn_opts = argv[1];
902+
// @NOTE: since 0.2, we ignore argv[1]
903903
QuicerListenerCTX *l_ctx = NULL;
904-
ERL_NIF_TERM active_val = ATOM_TRUE;
905904
if (!enif_get_resource(env, listener, ctx_listener_t, (void **)&l_ctx))
906905
{
907906
return ERROR_TUPLE_2(ATOM_BADARG);
908907
}
909908

910-
// Set parm active is optional
911-
enif_get_map_value(
912-
env, conn_opts, ATOM_QUIC_STREAM_OPTS_ACTIVE, &active_val);
913-
914909
ACCEPTOR *acceptor = AcceptorAlloc();
915910
if (!acceptor)
916911
{
@@ -923,24 +918,11 @@ async_accept2(ErlNifEnv *env,
923918
return ERROR_TUPLE_2(ATOM_BAD_PID);
924919
}
925920

926-
if (!set_owner_recv_mode(acceptor, env, active_val))
927-
{
928-
AcceptorDestroy(acceptor);
929-
return ERROR_TUPLE_2(ATOM_BADARG);
930-
}
931-
932-
if (!create_settings(env, &conn_opts, &acceptor->Settings))
933-
{
934-
AcceptorDestroy(acceptor);
935-
return ERROR_TUPLE_2(ATOM_PARAM_ERROR);
936-
}
937-
938921
AcceptorEnqueue(l_ctx->acceptor_queue, acceptor);
939922

940923
assert(enif_is_process_alive(env, &(acceptor->Pid)));
941924

942-
ERL_NIF_TERM listenHandle = enif_make_resource(env, l_ctx);
943-
return SUCCESS(listenHandle);
925+
return SUCCESS(listener);
944926
}
945927

946928
ERL_NIF_TERM
@@ -1084,40 +1066,28 @@ continue_connection_handshake(QuicerConnCTX *c_ctx)
10841066
{
10851067
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
10861068

1087-
if (!c_ctx)
1088-
{
1089-
return QUIC_STATUS_INTERNAL_ERROR;
1090-
}
1091-
1092-
if (!c_ctx->Connection)
1093-
{
1094-
return QUIC_STATUS_INVALID_STATE;
1095-
}
1096-
1097-
if (QUIC_FAILED(Status = MsQuic->ConnectionSetConfiguration(
1098-
c_ctx->Connection, c_ctx->config_ctx->Configuration)))
1099-
{
1100-
return Status;
1101-
}
1069+
CXPLAT_FRE_ASSERT(c_ctx);
1070+
CXPLAT_FRE_ASSERT(c_ctx->Connection);
11021071

1103-
// Apply connection owners' option overrides
1104-
Status = MsQuic->SetParam(c_ctx->Connection,
1105-
QUIC_PARAM_CONN_SETTINGS,
1106-
sizeof(QUIC_SETTINGS),
1107-
&c_ctx->owner->Settings);
1072+
Status = MsQuic->ConnectionSetConfiguration(
1073+
c_ctx->Connection, c_ctx->config_ctx->Configuration);
11081074
return Status;
11091075
}
11101076

11111077
ERL_NIF_TERM
1112-
async_handshake_1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
1078+
async_handshake_X(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
11131079

11141080
{
11151081
QuicerConnCTX *c_ctx;
11161082
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
11171083
ERL_NIF_TERM res = ATOM_OK;
1118-
CXPLAT_FRE_ASSERT(argc == 1);
1084+
CXPLAT_FRE_ASSERT(argc == 1 || argc == 2);
1085+
ERL_NIF_TERM econn = argv[0];
11191086

1120-
if (!enif_get_resource(env, argv[0], ctx_connection_t, (void **)&c_ctx))
1087+
QUIC_SETTINGS Settings = { 0 };
1088+
ERL_NIF_TERM active_val = ATOM_TRUE;
1089+
1090+
if (!enif_get_resource(env, econn, ctx_connection_t, (void **)&c_ctx))
11211091
{
11221092
return ERROR_TUPLE_2(ATOM_BADARG);
11231093
}
@@ -1129,11 +1099,41 @@ async_handshake_1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
11291099
return ERROR_TUPLE_2(ATOM_CLOSED);
11301100
}
11311101

1102+
if (argc > 1)
1103+
{
1104+
ERL_NIF_TERM econn_opts = argv[1];
1105+
// Set parm active is optional
1106+
enif_get_map_value(
1107+
env, econn_opts, ATOM_QUIC_STREAM_OPTS_ACTIVE, &active_val);
1108+
1109+
if (!create_settings(env, &econn_opts, &Settings))
1110+
{
1111+
res = ERROR_TUPLE_2(ATOM_PARAM_ERROR);
1112+
goto exit;
1113+
}
1114+
1115+
if (!set_owner_recv_mode(c_ctx->owner, env, active_val))
1116+
{
1117+
res = ERROR_TUPLE_2(ATOM_BADARG);
1118+
goto exit;
1119+
}
1120+
1121+
// Apply connection owners' option overrides
1122+
if (QUIC_FAILED(Status = MsQuic->SetParam(c_ctx->Connection,
1123+
QUIC_PARAM_CONN_SETTINGS,
1124+
sizeof(QUIC_SETTINGS),
1125+
&Settings)))
1126+
{
1127+
res = ERROR_TUPLE_2(ATOM_STATUS(Status));
1128+
goto exit;
1129+
}
1130+
}
1131+
11321132
if (QUIC_FAILED(Status = continue_connection_handshake(c_ctx)))
11331133
{
11341134
res = ERROR_TUPLE_2(ATOM_STATUS(Status));
11351135
}
1136-
1136+
exit:
11371137
put_conn_handle(c_ctx);
11381138
return res;
11391139
}

c_src/quicer_connection.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ ERL_NIF_TERM
4848
get_conn_rid1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
4949

5050
ERL_NIF_TERM
51-
async_handshake_1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
51+
async_handshake_X(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
5252

5353
QUIC_STATUS continue_connection_handshake(QuicerConnCTX *c_ctx);
5454

c_src/quicer_nif.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1746,7 +1746,8 @@ static ErlNifFunc nif_funcs[] = {
17461746
{ "open_connection", 1, open_connectionX, 0},
17471747
{ "async_connect", 3, async_connect3, 0},
17481748
{ "async_accept", 2, async_accept2, 0},
1749-
{ "async_handshake", 1, async_handshake_1, 0},
1749+
{ "async_handshake", 1, async_handshake_X, 0},
1750+
{ "async_handshake", 2, async_handshake_X, 0},
17501751
{ "async_shutdown_connection", 3, shutdown_connection3, 0},
17511752
{ "async_accept_stream", 2, async_accept_stream2, 0},
17521753
{ "start_stream", 2, async_start_stream2, 0},

c_src/quicer_queue.h

-3
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,7 @@ typedef struct ACCEPTOR
5555
ErlNifPid Pid;
5656
ACCEPTOR_RECV_MODE active;
5757
uint16_t active_count; /* counter for active_n */
58-
QUIC_SETTINGS Settings;
5958
void *reserved1;
60-
void *reserved2;
61-
void *reserved3;
6259
} ACCEPTOR;
6360

6461
typedef struct AcceptorsQueue

include/quicer.hrl

+7
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,11 @@
149149
-define(QUIC_CONGESTION_CONTROL_ALGORITHM_CUBIC, 0).
150150
-define(QUIC_CONGESTION_CONTROL_ALGORITHM_BBR, 1).
151151

152+
-record(probe_state, {
153+
final :: term() | undefined,
154+
sent_at :: integer() | undefined,
155+
suspect_lost_at :: integer() | undefined,
156+
final_at :: integer() | undefined
157+
}).
158+
152159
-endif. %% QUICER_HRL

include/quicer_types.hrl

+6
Original file line numberDiff line numberDiff line change
@@ -506,5 +506,11 @@
506506
dgram_max_len := uint64()
507507
}.
508508

509+
-type probe_state() :: #probe_state{}.
510+
-type probe_res() ::
511+
#probe_state{}
512+
| {error, dgram_send_error, atom()}
513+
| {error, atom()}.
514+
509515
%% QUICER_TYPES_HRL
510516
-endif.

src/quicer.erl

+68-21
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@
4545
async_connect/3,
4646
handshake/1,
4747
handshake/2,
48+
handshake/3,
4849
async_handshake/1,
50+
async_handshake/2,
4951
accept/2,
5052
accept/3,
5153
async_accept/2,
@@ -59,6 +61,7 @@
5961
close_connection/4,
6062
async_close_connection/1,
6163
async_close_connection/3,
64+
probe/2,
6265
accept_stream/2,
6366
accept_stream/3,
6467
async_accept_stream/2,
@@ -69,6 +72,7 @@
6972
async_send/2,
7073
async_send/3,
7174
recv/2,
75+
async_send_dgram/2,
7276
send_dgram/2,
7377
shutdown_stream/1,
7478
shutdown_stream/2,
@@ -174,7 +178,10 @@
174178
quicer_addr/0,
175179

176180
%% Registraion Profiles
177-
registration_profile/0
181+
registration_profile/0,
182+
183+
%% probes
184+
probe_res/0
178185
]).
179186

180187
-type connection_opts() :: proplists:proplist() | conn_opts().
@@ -447,14 +454,29 @@ async_connect(Host, Port, Opts) when is_map(Opts) ->
447454
handshake(Conn) ->
448455
handshake(Conn, 5000).
449456

457+
-spec handshake(connection_handle(), timeout()) ->
458+
{ok, connection_handle()} | {error, any()}.
459+
handshake(Conn, Timeout) ->
460+
case async_handshake(Conn) of
461+
{error, _} = E ->
462+
E;
463+
ok ->
464+
receive
465+
{quic, connected, Conn, _} -> {ok, Conn};
466+
{quic, closed, Conn, _Flags} -> {error, closed}
467+
after Timeout ->
468+
{error, timeout}
469+
end
470+
end.
471+
450472
%% @doc Complete TLS handshake after accepted a Connection
451473
%% @see handshake/2
452474
%% @see async_handshake/1
453-
-spec handshake(connection_handle(), timeout()) ->
475+
-spec handshake(connection_handle(), conn_opts(), timeout()) ->
454476
{ok, connection_handle()}
455477
| {error, any()}.
456-
handshake(Conn, Timeout) ->
457-
case async_handshake(Conn) of
478+
handshake(Conn, ConnOpts, Timeout) ->
479+
case async_handshake(Conn, ConnOpts) of
458480
{error, _} = E ->
459481
E;
460482
ok ->
@@ -467,13 +489,24 @@ handshake(Conn, Timeout) ->
467489
end.
468490

469491
%% @doc Complete TLS handshake after accepted a Connection.
470-
%% Caller should expect to receive ```{quic, connected, connection_handle()}'''
471492
%%
472493
%% @see handshake/2
494+
%% @see async_handshake/2
473495
-spec async_handshake(connection_handle()) -> ok | {error, any()}.
474496
async_handshake(Conn) ->
475497
quicer_nif:async_handshake(Conn).
476498

499+
%% @doc Complete TLS handshake after accepted a Connection.
500+
%% also set connection options which override the default listener options.
501+
%%
502+
%% @see handshake/2
503+
%% @see async_handshake/1
504+
-spec async_handshake(connection_handle(), conn_opts()) -> ok | {error, any()}.
505+
async_handshake(Conn, ConnOpts) when is_list(ConnOpts) ->
506+
async_handshake(Conn, maps:from_list(ConnOpts));
507+
async_handshake(Conn, ConnOpts) ->
508+
quicer_nif:async_handshake(Conn, ConnOpts).
509+
477510
%% @doc Accept new Connection (Server)
478511
%%
479512
%% Accept new connection from listener_handle().
@@ -816,35 +849,49 @@ do_recv(Stream, Count, Buff) ->
816849
E
817850
end.
818851

852+
%% @doc Sending Unreliable Datagram.
853+
%% Caller should handle the async signals for the send results
854+
%%
855+
%% ref: [https://datatracker.ietf.org/doc/html/rfc9221]
856+
%% @see send/2 send_dgram/2
857+
-spec async_send_dgram(connection_handle(), binary()) ->
858+
{ok, non_neg_integer()}
859+
| {error, badarg | not_enough_mem | invalid_parameter | closed}
860+
| {error, dgram_send_error, atom_reason()}.
861+
async_send_dgram(Conn, Data) ->
862+
quicer_nif:send_dgram(Conn, Data, _IsSyncRel = 1).
863+
819864
%% @doc Sending Unreliable Datagram
865+
%% return error only if sending could not be scheduled such as
866+
%% not_enough_mem, connection is already closed or wrong args.
867+
%% otherwise, it is fire and forget.
820868
%%
821-
%% ref: [https://datatracker.ietf.org/doc/html/draft-ietf-quic-datagram]
822-
%% @see send/2
869+
%% %% ref: [https://datatracker.ietf.org/doc/html/rfc9221]
870+
%% @see send/2, async_send_dgram/2
823871
-spec send_dgram(connection_handle(), binary()) ->
824-
{ok, BytesSent :: pos_integer()}
825-
| {error, badarg | not_enough_mem | closed}
872+
{ok, BytesSent :: non_neg_integer()}
873+
| {error, badarg | not_enough_mem | invalid_parameter | closed}
826874
| {error, dgram_send_error, atom_reason()}.
827875
send_dgram(Conn, Data) ->
828876
case quicer_nif:send_dgram(Conn, Data, _IsSync = 1) of
829-
%% @todo we need find tuned event mask
830877
{ok, _Len} = OK ->
831-
receive
832-
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_SENT}} ->
833-
receive
834-
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_ACKNOWLEDGED}} ->
835-
OK;
836-
{quic, dgram_send_state, Conn, #{state := Other}} ->
837-
{error, dgram_send_error, Other}
838-
end;
839-
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_ACKNOWLEDGED}} ->
878+
case quicer_lib:handle_dgram_send_states(Conn) of
879+
ok ->
840880
OK;
841-
{quic, dgram_send_state, Conn, #{state := Other}} ->
842-
{error, dgram_send_error, Other}
881+
{error, E} ->
882+
{error, dgram_send_error, E}
843883
end;
884+
{error, E} ->
885+
{error, E};
844886
E ->
845887
E
846888
end.
847889

890+
%% @doc Probe conn state with 0 len dgram.
891+
-spec probe(connection_handle(), timeout()) -> probe_res().
892+
probe(Conn, Timeout) ->
893+
quicer_lib:probe(Conn, Timeout).
894+
848895
%% @doc Shutdown stream gracefully, with infinity timeout
849896
%%
850897
%% @see shutdown_stream/1

src/quicer_conn_acceptor_sup.erl

+2-4
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,19 @@ start_link(ListenerH, ConnOpts) ->
6262
-spec init(Args :: term()) ->
6363
{ok, {SupFlags :: supervisor:sup_flags(), [ChildSpec :: supervisor:child_spec()]}}
6464
| ignore.
65-
init([ListenerH, Opts]) ->
65+
init([ListenerH, OptsTab]) ->
6666
SupFlags = #{
6767
strategy => simple_one_for_one,
6868
intensity => 1,
6969
period => 5
7070
},
71-
7271
OneChild = #{
7372
id => ignored,
74-
start => {quicer_connection, start_link, [undefined, ListenerH, Opts]},
73+
start => {quicer_connection, start_acceptor, [ListenerH, OptsTab]},
7574
restart => temporary,
7675
shutdown => 5000,
7776
type => worker
7877
},
79-
8078
{ok, {SupFlags, [OneChild]}}.
8179

8280
%%%===================================================================

0 commit comments

Comments
 (0)