File 2524-ssh-Fix-port-leakage-for-daemons-failing-at-start.patch of Package erlang

From 9b8575437a3c84eab77453279d8844c52485216c Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Wed, 19 Dec 2018 18:07:20 +0100
Subject: [PATCH 2/2] ssh: Fix port leakage for daemons failing at start

---
 lib/ssh/src/ssh.erl | 60 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 41 insertions(+), 19 deletions(-)

diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 25d537c624..5f5ccee4f8 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -231,25 +231,38 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535,
     try
         {Host1, UserOptions} = handle_daemon_args(Host0, UserOptions0),
         #{} = Options0 = ssh_options:handle_options(server, UserOptions),
-
-        {{Host,Port}, ListenSocket} =
-            open_listen_socket(Host1, Port0, Options0),
-
-        %% Now Host,Port is what to use for the supervisor to register its name,
-        %% and ListenSocket is for listening on connections. But it is still owned
-        %% by self()...
-
-        finalize_start(Host, Port, ?GET_OPT(profile, Options0),
-                       ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options0),
-                       fun(Opts, Result) ->
-                               {_, Callback, _} = ?GET_OPT(transport, Opts),
-                               receive
-                                   {request_control, ListenSocket, ReqPid} ->
-                                       ok = Callback:controlling_process(ListenSocket, ReqPid),
-                                       ReqPid ! {its_yours,ListenSocket},
-                                       Result
-                               end
-                       end)
+        {open_listen_socket(Host1, Port0, Options0), Options0}
+    of
+        {{{Host,Port}, ListenSocket}, Options1} ->
+            try
+                %% Now Host,Port is what to use for the supervisor to register its name,
+                %% and ListenSocket is for listening on connections. But it is still owned
+                %% by self()...
+                finalize_start(Host, Port, ?GET_OPT(profile, Options1),
+                               ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options1),
+                               fun(Opts, Result) ->
+                                       {_, Callback, _} = ?GET_OPT(transport, Opts),
+                                       receive
+                                           {request_control, ListenSocket, ReqPid} ->
+                                               ok = Callback:controlling_process(ListenSocket, ReqPid),
+                                               ReqPid ! {its_yours,ListenSocket},
+                                               Result
+                                       end
+                               end)
+            of
+                {error,Err} ->
+                    close_listen_socket(ListenSocket, Options1),
+                    {error,Err};
+                OK ->
+                    OK
+            catch
+                error:Error ->
+                    close_listen_socket(ListenSocket, Options1),
+                    error(Error);
+                exit:Exit ->
+                    close_listen_socket(ListenSocket, Options1),
+                    exit(Exit)
+            end
     catch
         throw:bad_fd ->
             {error,bad_fd};
@@ -456,6 +469,15 @@ open_listen_socket(_Host0, Port0, Options0) ->
     {ok,{LHost,LPort}} = inet:sockname(LSock),
     {{LHost,LPort}, LSock}.
 
+%%%----------------------------------------------------------------
+close_listen_socket(ListenSocket, Options) ->
+    try
+        {_, Callback, _} = ?GET_OPT(transport, Options),
+        Callback:close(ListenSocket)
+    catch
+        _C:_E -> ok
+    end.
+
 %%%----------------------------------------------------------------
 finalize_start(Host, Port, Profile, Options0, F) ->
     try
-- 
2.16.4

openSUSE Build Service is sponsored by