From 7a3aa3b225845b007703621c408f02adb3d2699c Mon Sep 17 00:00:00 2001 From: Jan Uhlig Date: Tue, 25 Jun 2024 10:30:28 +0200 Subject: [PATCH] Fix halfway-stopping of listeners * if the process calling ranch:stop_listener crashes before finishing, the stopping is still exetuted completely * if a listener is terminated but not deleted, calling ranch:stop_listener removes the remnant --- src/ranch.erl | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/ranch.erl b/src/ranch.erl index d48c18a6fc..d909afd735 100644 --- a/src/ranch.erl +++ b/src/ranch.erl @@ -193,24 +193,42 @@ start_error(_, Error) -> Error. -spec stop_listener(ref()) -> ok | {error, not_found}. stop_listener(Ref) -> + Parent = self(), + Tag = make_ref(), + {StopperPid, StopperMon} = spawn_monitor(fun() -> Parent ! {Tag, stop_listener1(Ref)} end), + receive + {Tag, Result} -> + demonitor(StopperMon, [flush]), + Result; + {'DOWN', StopperMon, process, StopperPid, Error} -> + {error, Error} + end. + +stop_listener1(Ref) -> + TransportAndOpts = maybe_get_transport_and_opts(Ref), + case supervisor:terminate_child(ranch_sup, {ranch_listener_sup, Ref}) of + ok -> + _ = supervisor:delete_child(ranch_sup, {ranch_listener_sup, Ref}), + ranch_server:cleanup_listener_opts(Ref), + stop_listener2(TransportAndOpts); + {error, _} = Error -> + Error + end. + +stop_listener2({Transport, TransOpts}) -> + Transport:cleanup(TransOpts), + ok; +stop_listener2(undefined) -> + ok. + +maybe_get_transport_and_opts(Ref) -> try - [_, Transport0, _, _, _] = ranch_server:get_listener_start_args(Ref), - TransOpts0 = get_transport_options(Ref), - {Transport0, TransOpts0} - of - {Transport, TransOpts} -> - case supervisor:terminate_child(ranch_sup, {ranch_listener_sup, Ref}) of - ok -> - _ = supervisor:delete_child(ranch_sup, {ranch_listener_sup, Ref}), - ranch_server:cleanup_listener_opts(Ref), - Transport:cleanup(TransOpts), - ok; - {error, Reason} -> - {error, Reason} - end + [_, Transport, _, _, _] = ranch_server:get_listener_start_args(Ref), + TransOpts = get_transport_options(Ref), + {Transport, TransOpts} catch error:badarg -> - {error, not_found} + undefined end. -spec suspend_listener(ref()) -> ok | {error, any()}.