File 0662-Monitor-dtls-listen-caller.patch of Package erlang

From 49b919521c3733926dc1c071b6ff7f041f50a167 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Wed, 20 Mar 2024 16:56:08 +0100
Subject: [PATCH 2/3] Monitor dtls listen caller

So we can cleanup if caller dies, otherwise we leak a process and a
socket.

Also fix ssl:close/2 on listen socket.

Fixes #7951
---
 lib/ssl/src/dtls_packet_demux.erl | 59 ++++++++++++++++++++-----------
 lib/ssl/src/dtls_socket.erl       | 13 ++++---
 lib/ssl/src/ssl.erl               |  4 +--
 3 files changed, 46 insertions(+), 30 deletions(-)

diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl
index 86282d9e54..19d181fe3e 100644
--- a/lib/ssl/src/dtls_packet_demux.erl
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -28,12 +28,12 @@
 -include_lib("kernel/include/logger.hrl").
 
 %% API
--export([start_link/5,
+-export([start_link/6,
          active_once/3,
          accept/2,
          sockname/1,
          close/1,
-         new_owner/1,
+         new_owner/2,
          new_connection/2,
          connection_setup/2,
          get_all_opts/1,
@@ -50,7 +50,7 @@
 	 terminate/2,
          code_change/3]).
 
--record(state, 
+-record(state,
 	{active_n,
          port,
 	 listener,
@@ -60,6 +60,7 @@
 	 dtls_msq_queues = kv_new(),
 	 dtls_processes = kv_new(),
 	 accepters  = queue:new(),
+         owner, %% Listen process owner
 	 first,
          close,
          session_id_tracker
@@ -69,8 +70,8 @@
 %%% API
 %%%===================================================================
 
-start_link(Port, TransportInfo, EmOpts, InetOptions, DTLSOptions) ->
-    gen_server:start_link(?MODULE, [Port, TransportInfo, EmOpts, InetOptions, DTLSOptions], []).
+start_link(Owner, Port, TransportInfo, EmOpts, InetOptions, DTLSOptions) ->
+    gen_server:start_link(?MODULE, [Owner, Port, TransportInfo, EmOpts, InetOptions, DTLSOptions], []).
 
 active_once(PacketSocket, Client, Pid) ->
     gen_server:cast(PacketSocket, {active_once, Client, Pid}).
@@ -84,8 +85,8 @@ sockname(PacketSocket) ->
 close(PacketSocket) ->
     call(PacketSocket, close).
 
-new_owner(PacketSocket) ->
-    call(PacketSocket, new_owner).
+new_owner(PacketSocket, Owner) ->
+    call(PacketSocket, {new_owner, Owner}).
 
 new_connection(PacketSocket, Client) ->
     call(PacketSocket, {new_connection, Client, self()}).
@@ -110,8 +111,9 @@ getstat(PacketSocket, Opts) ->
 %%% gen_server callbacks
 %%%===================================================================
 
-init([Port0, TransportInfo, EmOpts, DTLSOptions, Socket]) ->
+init([Owner, Port0, TransportInfo, EmOpts, DTLSOptions, Socket]) ->
     InternalActiveN = get_internal_active_n(),
+    erlang:monitor(process, Owner),
     {ok, SessionIdHandle} = session_id_tracker(Socket, DTLSOptions),
     {ok, #state{active_n = InternalActiveN,
                 port = Port0,
@@ -120,6 +122,7 @@ init([Port0, TransportInfo, EmOpts, DTLSOptions, Socket]) ->
                 dtls_options = DTLSOptions,
                 emulated_options = EmOpts,
                 listener = Socket,
+                owner = Owner,
                 close = false,
                 session_id_tracker = SessionIdHandle}}.
 
@@ -141,19 +144,15 @@ handle_call({accept, Accepter}, From, #state{accepters = Accepters} = State0) ->
 handle_call(sockname, _, #state{listener = Socket} = State) ->
     Reply = inet:sockname(Socket),
     {reply, Reply, State};
-handle_call(close, _, #state{dtls_processes = Processes,
-                             accepters = Accepters} = State) ->
-    case kv_empty(Processes) of
-        true ->
-            {stop, normal, ok, State#state{close=true}};
-        false -> 
-            lists:foreach(fun({_, From}) ->
-                                  gen_server:reply(From, {error, closed})
-                          end, queue:to_list(Accepters)),
-            {reply, ok,  State#state{close = true, accepters = queue:new()}}
+handle_call(close, _, State0) ->
+    case do_close(State0) of
+        {stop, State} ->
+            {stop, normal, ok, State};
+        {wait, State} ->
+            {reply, ok, State}
     end;
-handle_call(new_owner, _, State) ->
-    {reply, ok,  State#state{close = false, first = true}};
+handle_call({new_owner, Owner}, _, State) ->
+    {reply, ok,  State#state{close = false, first = true, owner = Owner}};
 handle_call({new_connection, Old, _Pid}, _,
             #state{accepters = Accepters, dtls_msq_queues = MsgQs0} = State) ->
     case queue:is_empty(Accepters) of
@@ -167,7 +166,7 @@ handle_call({new_connection, Old, _Pid}, _,
     end;
 
 handle_call({get_sock_opts, {SocketOptNames, EmOptNames}}, _, #state{listener = Socket,
-                                                               emulated_options = EmOpts} = State) ->
+                                                                     emulated_options = EmOpts} = State) ->
     case get_socket_opts(Socket, SocketOptNames) of
         {ok, Opts} ->
             {reply, {ok, emulated_opts_list(EmOpts, EmOptNames, []) ++ Opts}, State};
@@ -223,6 +222,13 @@ handle_info({ErrorTag, Socket, Error}, #state{listener = Socket, transport = {_,
     ?LOG_NOTICE(Report),
     {noreply, State#state{close=true}};
 
+handle_info({'DOWN', _, process, Owner, _}, #state{owner = Owner} = State0) ->
+    case do_close(State0) of
+        {stop, State} ->
+            {stop, normal, State};
+        {wait, State} ->
+            {noreply, State}
+    end;
 handle_info({'DOWN', _, process, Pid, _},
             #state{dtls_processes = Processes0,
                    dtls_msq_queues = MsgQueues0,
@@ -264,6 +270,17 @@ code_change(_OldVsn, State, _Extra) ->
 %%%===================================================================
 %%% Internal functions
 %%%===================================================================
+
+do_close(#state{dtls_processes = Processes, accepters = Accepters} = State) ->
+    case kv_empty(Processes) of
+        true ->
+            {stop, State#state{close=true}};
+        false ->
+            lists:foreach(fun({_, From}) -> gen_server:reply(From, {error, closed}) end,
+                          queue:to_list(Accepters)),
+            {wait, State#state{close = true, accepters = queue:new()}}
+    end.
+
 handle_datagram(Client, Msg, #state{dtls_msq_queues = MsgQueues, accepters = AcceptorsQueue0} = State) ->
     case kv_lookup(Client, MsgQueues) of
 	none ->
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
index fbb72f59ef..16f78d7d3c 100644
--- a/lib/ssl/src/dtls_socket.erl
+++ b/lib/ssl/src/dtls_socket.erl
@@ -53,9 +53,9 @@ listen(Port, #config{inet_ssl = SockOpts,
     IP = proplists:get_value(ip, SockOpts, default_ip(SockOpts)),
     case dtls_listener_sup:lookup_listener(IP, Port) of
         undefined ->
-            start_new_listener(IP, Port, Config);
+            start_new_listener(IP, Port, self(), Config);
         {ok, Listener} ->
-            dtls_packet_demux:new_owner(Listener),
+            dtls_packet_demux:new_owner(Listener, self()),
             dtls_packet_demux:set_all_opts(
               Listener, {Options,
                           emulated_socket_options(EmOpts,
@@ -287,7 +287,7 @@ get_real_port(Listener, Port0) when is_pid(Listener) andalso
             Port0
     end.
 
-start_new_listener(IP, Port0,
+start_new_listener(IP, Port0, Owner,
                    #config{transport_info = {TransportModule, _,_,_,_},
                            inet_user = Options} = Config) ->
     InetOptions = Options ++ internal_inet_values(),
@@ -300,7 +300,7 @@ start_new_listener(IP, Port0,
                        _ ->
                            Port0
                    end,
-            start_dtls_packet_demux(Config, IP, Port, Socket);
+            start_dtls_packet_demux(Config, IP, Port, Socket, Owner);
         {error, eaddrinuse} ->
             {error, already_listening};
         Error ->
@@ -311,10 +311,9 @@ start_dtls_packet_demux(#config{
                            transport_info =
                                {TransportModule, _,_,_,_} = TransportInfo,
                            emulated = EmOpts0,
-                           ssl = SslOpts} = Config, IP, Port, Socket) ->
+                           ssl = SslOpts} = Config, IP, Port, Socket, Owner) ->
     EmOpts = emulated_socket_options(EmOpts0, #socket_options{}),
-    case dtls_listener_sup:start_child([Port, TransportInfo, EmOpts,
-                                        SslOpts, Socket]) of
+    case dtls_listener_sup:start_child([Owner, Port, TransportInfo, EmOpts, SslOpts, Socket]) of
         {ok, Multiplexer} ->
             ok = TransportModule:controlling_process(Socket, Multiplexer),
             dtls_listener_sup:register_listener({self(), Multiplexer},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index cba37c6f33..38e9919fb5 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -875,8 +875,8 @@ close(#sslsocket{pid = [TLSPid|_]},
 close(#sslsocket{pid = [TLSPid|_]}, Timeout) when is_pid(TLSPid),
 					      (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
     ssl_gen_statem:close(TLSPid, {close, Timeout});
-close(#sslsocket{pid = {dtls = ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}, _) ->
-    dtls_socket:close(Transport, ListenSocket);    
+close(#sslsocket{pid = {dtls, #config{dtls_handler = {_, _}}}} = DTLSListen, _) ->
+    dtls_socket:close(DTLSListen);
 close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}, _) ->
     tls_socket:close(Transport, ListenSocket).
 
-- 
2.35.3

openSUSE Build Service is sponsored by