Skip to content

Commit 63f93fa

Browse files
committed
feat(dgram): improve send err handling
1 parent 9238cdd commit 63f93fa

File tree

3 files changed

+80
-20
lines changed

3 files changed

+80
-20
lines changed

src/quicer.erl

+25-18
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
async_send/2,
7272
async_send/3,
7373
recv/2,
74+
async_send_dgram/2,
7475
send_dgram/2,
7576
shutdown_stream/1,
7677
shutdown_stream/2,
@@ -844,33 +845,39 @@ do_recv(Stream, Count, Buff) ->
844845
E
845846
end.
846847

847-
%% @doc Sending Unreliable Datagram
848+
%% @doc Sending Unreliable Datagram.
849+
%% Caller should handle the async signals for the send results
848850
%%
849-
%% ref: [https://datatracker.ietf.org/doc/html/draft-ietf-quic-datagram]
850-
%% @see send/2
851+
%% ref: [https://datatracker.ietf.org/doc/html/rfc9221]
852+
%% @see send/2 send_dgram/2
853+
-spec async_send_dgram(connection_handle(), binary()) ->
854+
{ok, non_neg_integer()}
855+
| {error, badarg | not_enough_mem | closed}
856+
| {error, dgram_send_error, atom_reason()}.
857+
async_send_dgram(Conn, Data) ->
858+
quicer_nif:send_dgram(Conn, Data, _IsSyncRel = 1).
859+
860+
%% @doc Sending Unreliable Datagram, returns the end state.
861+
%%
862+
%% %% ref: [https://datatracker.ietf.org/doc/html/rfc9221]
863+
%% @see send/2, async_send_dgram
851864
-spec send_dgram(connection_handle(), binary()) ->
852-
{ok, BytesSent :: pos_integer()}
865+
{ok, BytesSent :: non_neg_integer()}
853866
| {error, badarg | not_enough_mem | closed}
854867
| {error, dgram_send_error, atom_reason()}.
855868
send_dgram(Conn, Data) ->
856869
case quicer_nif:send_dgram(Conn, Data, _IsSync = 1) of
857-
%% @todo we need find tuned event mask
858870
{ok, _Len} = OK ->
859-
receive
860-
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_SENT}} ->
861-
receive
862-
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_ACKNOWLEDGED}} ->
863-
OK;
864-
{quic, dgram_send_state, Conn, #{state := Other}} ->
865-
{error, dgram_send_error, Other}
866-
end;
867-
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_ACKNOWLEDGED}} ->
871+
case quicer_lib:handle_dgram_send_states(Conn) of
872+
ok ->
868873
OK;
869-
{quic, dgram_send_state, Conn, #{state := Other}} ->
870-
{error, dgram_send_error, Other}
874+
{error, E} ->
875+
{error, dgram_send_error, E}
871876
end;
872-
E ->
873-
E
877+
{error, _, _} = E ->
878+
E;
879+
{error, E} ->
880+
{error, dgram_send_error, E}
874881
end.
875882

876883
%% @doc Shutdown stream gracefully, with infinity timeout

src/quicer_lib.erl

+44-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@
4141

4242
-type action() :: hibernate | timeout() | {continue, Continue :: term()}.
4343

44-
-export([default_cb_ret/2]).
44+
-export([
45+
default_cb_ret/2,
46+
handle_dgram_send_states/1
47+
]).
4548

4649
-spec default_cb_ret(cb_ret(), State :: term()) ->
4750
{reply, NewState :: term()}
@@ -69,3 +72,43 @@ default_cb_ret({reply, Reply, NewCBState, Action}, State) ->
6972
{reply, Reply, State#{callback_state := NewCBState}, Action};
7073
default_cb_ret({reply, Reply, NewCBState}, State) ->
7174
{reply, Reply, State#{callback_state := NewCBState}}.
75+
76+
-spec handle_dgram_send_states(connection_handle()) ->
77+
ok
78+
| {error,
79+
dgram_send_canceled
80+
| dgram_send_unknown
81+
| dgram_send_lost_discarded}.
82+
handle_dgram_send_states(Conn) ->
83+
handle_dgram_send_states(init, Conn).
84+
handle_dgram_send_states(init, Conn) ->
85+
receive
86+
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_SENT}} ->
87+
handle_dgram_send_states(sent, Conn);
88+
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_ACKNOWLEDGED}} ->
89+
%% @TODO unsure if it will hit here
90+
ok;
91+
{quic, dgram_send_state, Conn, #{state := E}} ->
92+
{error, E}
93+
end;
94+
handle_dgram_send_states(sent, Conn) ->
95+
receive
96+
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_ACKNOWLEDGED}} ->
97+
%% Happy Track
98+
ok;
99+
{quic, dgram_send_state, Conn, #{state := ?QUIC_DATAGRAM_SEND_LOST_SUSPECT}} ->
100+
%% Lost suspected
101+
receive
102+
{quic, dgram_send_state, Conn, #{
103+
state := ?QUIC_DATAGRAM_SEND_ACKNOWLEDGED_SPURIOUS
104+
}} ->
105+
%% Lost recovered
106+
ok;
107+
{quic, dgram_send_state, Conn, #{state := EState}} ->
108+
%% Unrecoverable Errors.
109+
{error, EState}
110+
end;
111+
{quic, dgram_send_state, Conn, #{state := EState}} ->
112+
%% Unrecoverable Errors.
113+
{error, EState}
114+
end.

test/quicer_SUITE.erl

+11-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575

7676
tc_dgram_client_send/1,
7777
tc_dgram_client_send_iolist/1,
78+
tc_dgram_client_send_fail/1,
7879

7980
% , tc_getopt_raw/1
8081
tc_getopt/1,
@@ -859,7 +860,7 @@ tc_stream_controlling_process_demon(Config) ->
859860
ok = quicer:setopt(Stm, active, true),
860861
{ok, _Len} = quicer:send(Stm, <<"owner_changed">>),
861862
receive
862-
{quic, <<"owner_changed">>, Stm, _} ->
863+
{quic, <<"owner_changed">>, _Stm, _} ->
863864
ok
864865
end,
865866
%% Set controlling_process again
@@ -883,6 +884,15 @@ tc_stream_controlling_process_demon(Config) ->
883884
ct:fail("timeout")
884885
end.
885886

887+
tc_dgram_client_send_fail(_) ->
888+
Opts = default_conn_opts() ++ [{datagram_receive_enabled, 1}],
889+
{ok, Conn} = quicer:async_connect("localhost", 65535, Opts),
890+
?assertEqual(
891+
{error, dgram_send_error, dgram_send_canceled},
892+
quicer:send_dgram(Conn, <<"ping">>)
893+
),
894+
ok.
895+
886896
tc_dgram_client_send(Config) ->
887897
Port = select_port(),
888898
Owner = self(),

0 commit comments

Comments
 (0)