aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJan Uhlig <[email protected]>2024-06-25 10:30:28 +0200
committerLoïc Hoguin <[email protected]>2024-11-12 14:48:23 +0100
commitdb2fff96c60e740fc6ac6a505f1c6fb69af64645 (patch)
tree444443c30d4e5f69a102d006f33aec95038781e6 /src
parentddfd254de0e5d27de1a8dbc44e70185ef6a05c1a (diff)
downloadranch-db2fff96c60e740fc6ac6a505f1c6fb69af64645.tar.gz
ranch-db2fff96c60e740fc6ac6a505f1c6fb69af64645.tar.bz2
ranch-db2fff96c60e740fc6ac6a505f1c6fb69af64645.zip
Fix halfway-stopping of listeners
* if the process calling ranch:stop_listener crashes before finishing, the stopping procedure is still executed completely * if a listener is terminated but not deleted, calling ranch:stop_listener removes the remnant
Diffstat (limited to 'src')
-rw-r--r--src/ranch.erl44
1 files changed, 29 insertions, 15 deletions
diff --git a/src/ranch.erl b/src/ranch.erl
index d48c18a..85c2c73 100644
--- a/src/ranch.erl
+++ b/src/ranch.erl
@@ -193,24 +193,38 @@ start_error(_, Error) -> Error.
-spec stop_listener(ref()) -> ok | {error, not_found}.
stop_listener(Ref) ->
+ %% The stop procedure must be executed in a separate
+ %% process to make sure that it won't be interrupted
+ %% in the middle in case the calling process crashes.
+ %% We use erpc:call locally so we don't have to
+ %% implement a custom spawn/call mechanism.
+ %% We need to provide an integer timeout to erpc:call,
+ %% otherwise the function will be executed in the calling
+ %% process. 5 minutes should be enough.
+ erpc:call(node(), fun() -> stop_listener1(Ref) end, 300000).
+
+stop_listener1(Ref) ->
+ TransportAndOpts = maybe_get_transport_and_opts(Ref),
+ _ = supervisor:terminate_child(ranch_sup, {ranch_listener_sup, Ref}),
+ ok = ranch_server:cleanup_listener_opts(Ref),
+ Result = supervisor:delete_child(ranch_sup, {ranch_listener_sup, Ref}),
+ ok = stop_listener2(TransportAndOpts),
+ Result.
+
+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()}.