summaryrefslogtreecommitdiff
path: root/lib/ssl/src/dtls_packet_demux.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/dtls_packet_demux.erl')
-rw-r--r--lib/ssl/src/dtls_packet_demux.erl148
1 files changed, 92 insertions, 56 deletions
diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl
index 19f1d2359c..c4cdb2eb01 100644
--- a/lib/ssl/src/dtls_packet_demux.erl
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2023. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -33,6 +33,8 @@
sockname/1,
close/1,
new_owner/1,
+ new_connection/2,
+ connection_setup/2,
get_all_opts/1,
set_all_opts/2,
get_sock_opts/2,
@@ -55,7 +57,6 @@
dtls_options,
emulated_options,
dtls_msq_queues = kv_new(),
- clients = set_new(),
dtls_processes = kv_new(),
accepters = queue:new(),
first,
@@ -85,6 +86,12 @@ close(PacketSocket) ->
new_owner(PacketSocket) ->
call(PacketSocket, new_owner).
+new_connection(PacketSocket, Client) ->
+ call(PacketSocket, {new_connection, Client, self()}).
+
+connection_setup(PacketSocket, Client) ->
+ gen_server:cast(PacketSocket, {connection_setup, Client}).
+
get_sock_opts(PacketSocket, SplitSockOpts) ->
call(PacketSocket, {get_sock_opts, SplitSockOpts}).
get_all_opts(PacketSocket) ->
@@ -146,6 +153,18 @@ handle_call(close, _, #state{dtls_processes = Processes,
end;
handle_call(new_owner, _, State) ->
{reply, ok, State#state{close = false, first = true}};
+handle_call({new_connection, Old, _Pid}, _,
+ #state{accepters = Accepters, dtls_msq_queues = MsgQs0} = State) ->
+ case queue:is_empty(Accepters) of
+ false ->
+ OldQueue = kv_get(Old, MsgQs0),
+ MsgQs1 = kv_delete(Old, MsgQs0),
+ MsgQs = kv_insert({old,Old}, OldQueue, MsgQs1),
+ {reply, true, State#state{dtls_msq_queues = MsgQs}};
+ true ->
+ {reply, false, State}
+ end;
+
handle_call({get_sock_opts, {SocketOptNames, EmOptNames}}, _, #state{listener = Socket,
emulated_options = EmOpts} = State) ->
case get_socket_opts(Socket, SocketOptNames) of
@@ -170,7 +189,16 @@ handle_call({getstat, Options}, _, #state{listener = Socket, transport = {Tran
handle_cast({active_once, Client, Pid}, State0) ->
State = handle_active_once(Client, Pid, State0),
- {noreply, State}.
+ {noreply, State};
+handle_cast({connection_setup, Client}, #state{dtls_msq_queues = MsgQueues} = State) ->
+ case kv_lookup({old, Client}, MsgQueues) of
+ none ->
+ {noreply, State};
+ {value, {Pid, _}} ->
+ Pid ! {socket_reused, Client},
+ %% Will be deleted when handling DOWN message
+ {noreply, State}
+ end.
handle_info({Transport, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket, transport = {_,Transport,_,_,_}} = State0) ->
State = handle_datagram({IP, InPortNo}, Msg, State0),
@@ -190,24 +218,40 @@ handle_info({udp_error, Socket, econnreset = Error}, #state{listener = Socket, t
?LOG_NOTICE(Report),
{noreply, State};
handle_info({ErrorTag, Socket, Error}, #state{listener = Socket, transport = {_,_,_, ErrorTag,_}} = State) ->
- Report = io_lib:format("SSL Packet muliplxer shutdown: Socket error: ~p ~n", [Error]),
+ Report = io_lib:format("SSL Packet muliplexer shutdown: Socket error: ~p ~n", [Error]),
?LOG_NOTICE(Report),
{noreply, State#state{close=true}};
-handle_info({'DOWN', _, process, Pid, _}, #state{clients = Clients,
- dtls_processes = Processes0,
- dtls_msq_queues = MsgQueues0,
- close = ListenClosed} = State) ->
+handle_info({'DOWN', _, process, Pid, _},
+ #state{dtls_processes = Processes0,
+ dtls_msq_queues = MsgQueues0,
+ close = ListenClosed} = State0) ->
Client = kv_get(Pid, Processes0),
Processes = kv_delete(Pid, Processes0),
- MsgQueues = kv_delete(Client, MsgQueues0),
+ State = case kv_lookup(Client, MsgQueues0) of
+ none ->
+ MsgQueues1 = kv_delete({old, Client}, MsgQueues0),
+ State0#state{dtls_processes = Processes, dtls_msq_queues = MsgQueues1};
+ {value, {Pid, _}} ->
+ MsgQueues1 = kv_delete(Client, MsgQueues0),
+ %% Restore old process if exists
+ case kv_lookup({old, Client}, MsgQueues1) of
+ none ->
+ State0#state{dtls_processes = Processes, dtls_msq_queues = MsgQueues1};
+ {value, Old} ->
+ MsgQueues2 = kv_delete({old, Client}, MsgQueues1),
+ MsgQueues = kv_insert(Client, Old, MsgQueues2),
+ State0#state{dtls_processes = Processes, dtls_msq_queues = MsgQueues}
+ end;
+ {value, _} -> %% Old process died (just delete its queue)
+ MsgQueues1 = kv_delete({old, Client}, MsgQueues0),
+ State0#state{dtls_processes = Processes, dtls_msq_queues = MsgQueues1}
+ end,
case ListenClosed andalso kv_empty(Processes) of
true ->
{stop, normal, State};
false ->
- {noreply, State#state{clients = set_delete(Client, Clients),
- dtls_processes = Processes,
- dtls_msq_queues = MsgQueues}}
+ {noreply, State}
end.
terminate(_Reason, _State) ->
@@ -219,55 +263,57 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
-handle_datagram(Client, Msg, #state{clients = Clients,
- accepters = AcceptorsQueue0} = State) ->
- case set_is_member(Client, Clients) of
- false ->
+handle_datagram(Client, Msg, #state{dtls_msq_queues = MsgQueues, accepters = AcceptorsQueue0} = State) ->
+ case kv_lookup(Client, MsgQueues) of
+ none ->
case queue:out(AcceptorsQueue0) of
- {{value, {UserPid, From}}, AcceptorsQueue} ->
- setup_new_connection(UserPid, From, Client, Msg,
+ {{value, {UserPid, From}}, AcceptorsQueue} ->
+ setup_new_connection(UserPid, From, Client, Msg,
State#state{accepters = AcceptorsQueue});
{empty, _} ->
%% Drop packet client will resend
State
end;
- true ->
- dispatch(Client, Msg, State)
+ {value, Queue} ->
+ dispatch(Queue, Client, Msg, State)
end.
-dispatch(Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) ->
- case kv_lookup(Client, MsgQueues) of
- {value, Queue0} ->
- case queue:out(Queue0) of
- {{value, Pid}, Queue} when is_pid(Pid) ->
- Pid ! Msg,
- State#state{dtls_msq_queues =
- kv_update(Client, Queue, MsgQueues)};
- {{value, _UDP}, _Queue} ->
- State#state{dtls_msq_queues =
- kv_update(Client, queue:in(Msg, Queue0), MsgQueues)};
- {empty, Queue} ->
- State#state{dtls_msq_queues =
- kv_update(Client, queue:in(Msg, Queue), MsgQueues)}
- end
+dispatch({Pid, Queue0}, Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) ->
+ case queue:out(Queue0) of
+ {{value, Pid}, Queue} when is_pid(Pid) ->
+ Pid ! Msg,
+ State#state{dtls_msq_queues =
+ kv_update(Client, {Pid, Queue}, MsgQueues)};
+ {{value, _UDP}, _Queue} ->
+ State#state{dtls_msq_queues =
+ kv_update(Client, {Pid, queue:in(Msg, Queue0)}, MsgQueues)};
+ {empty, Queue} ->
+ State#state{dtls_msq_queues =
+ kv_update(Client, {Pid, queue:in(Msg, Queue)}, MsgQueues)}
end.
+
next_datagram(Socket, N) ->
inet:setopts(Socket, [{active, N}]).
handle_active_once(Client, Pid, #state{dtls_msq_queues = MsgQueues} = State0) ->
- Queue0 = kv_get(Client, MsgQueues),
+ {Key, Queue0} = case kv_lookup(Client, MsgQueues) of
+ {value, {Pid, Q0}} -> {Client, Q0};
+ _ ->
+ OldKey = {old, Client},
+ {Pid, Q0} = kv_get(OldKey, MsgQueues),
+ {OldKey, Q0}
+ end,
case queue:out(Queue0) of
- {{value, Pid}, _} when is_pid(Pid) ->
- State0;
- {{value, Msg}, Queue} ->
- Pid ! Msg,
- State0#state{dtls_msq_queues = kv_update(Client, Queue, MsgQueues)};
- {empty, Queue0} ->
- State0#state{dtls_msq_queues = kv_update(Client, queue:in(Pid, Queue0), MsgQueues)}
+ {{value, Pid}, _} when is_pid(Pid) ->
+ State0;
+ {{value, Msg}, Queue} ->
+ Pid ! Msg,
+ State0#state{dtls_msq_queues = kv_update(Key, {Pid, Queue}, MsgQueues)};
+ {empty, Queue0} ->
+ State0#state{dtls_msq_queues = kv_update(Key, {Pid, queue:in(Pid, Queue0)}, MsgQueues)}
end.
setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes,
- clients = Clients,
dtls_msq_queues = MsgQueues,
dtls_options = DTLSOpts,
port = Port,
@@ -281,8 +327,7 @@ setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes,
erlang:monitor(process, Pid),
gen_server:reply(From, {ok, Pid, {Client, Socket}}),
Pid ! Msg,
- State#state{clients = set_insert(Client, Clients),
- dtls_msq_queues = kv_insert(Client, queue:new(), MsgQueues),
+ State#state{dtls_msq_queues = kv_insert(Client, {Pid, queue:new()}, MsgQueues),
dtls_processes = kv_insert(Pid, Client, Processes)};
{error, Reason} ->
gen_server:reply(From, {error, Reason}),
@@ -295,7 +340,7 @@ kv_lookup(Key, Store) ->
gb_trees:lookup(Key, Store).
kv_insert(Key, Value, Store) ->
gb_trees:insert(Key, Value, Store).
-kv_get(Key, Store) ->
+kv_get(Key, Store) ->
gb_trees:get(Key, Store).
kv_delete(Key, Store) ->
gb_trees:delete(Key, Store).
@@ -304,15 +349,6 @@ kv_new() ->
kv_empty(Store) ->
gb_trees:is_empty(Store).
-set_new() ->
- gb_sets:empty().
-set_insert(Item, Set) ->
- gb_sets:insert(Item, Set).
-set_delete(Item, Set) ->
- gb_sets:delete(Item, Set).
-set_is_member(Item, Set) ->
- gb_sets:is_member(Item, Set).
-
call(Server, Msg) ->
try
gen_server:call(Server, Msg, infinity)