From 9765f305e1f55f758a683bd95665fd0ab84a52c3 Mon Sep 17 00:00:00 2001 From: juhlig Date: Mon, 20 Apr 2020 17:03:17 +0200 Subject: Delete local socket file when a listener closes --- src/ranch.erl | 5 ++++- src/ranch_ssl.erl | 23 ++++++++++++++--------- src/ranch_tcp.erl | 23 ++++++++++++++--------- src/ranch_transport.erl | 1 + test/acceptor_SUITE.erl | 21 ++++++++++++++++----- 5 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/ranch.erl b/src/ranch.erl index a400798..7a03ef2 100644 --- a/src/ranch.erl +++ b/src/ranch.erl @@ -155,10 +155,13 @@ start_error(_, Error) -> Error. -spec stop_listener(ref()) -> ok | {error, not_found}. stop_listener(Ref) -> + [_, Transport, _, _, _] = ranch_server:get_listener_start_args(Ref), + TransOpts = get_transport_options(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); + ranch_server:cleanup_listener_opts(Ref), + Transport:cleanup(TransOpts); {error, Reason} -> {error, Reason} end. diff --git a/src/ranch_ssl.erl b/src/ranch_ssl.erl index cc51012..2c35c97 100644 --- a/src/ranch_ssl.erl +++ b/src/ranch_ssl.erl @@ -43,6 +43,7 @@ -export([sockname/1]). -export([shutdown/2]). -export([close/1]). +-export([cleanup/1]). -type ssl_opt() :: {alpn_preferred_protocols, [binary()]} | {beast_mitigation, one_n_minus_one | zero_n | disabled} @@ -107,6 +108,7 @@ messages() -> {ssl, ssl_closed, ssl_error, ssl_passive}. -spec listen(ranch:transport_opts(opts())) -> {ok, ssl:sslsocket()} | {error, atom()}. listen(TransOpts) -> + ok = cleanup(TransOpts), SocketOpts = maps:get(socket_opts, TransOpts, []), case lists:keymember(cert, 1, SocketOpts) orelse lists:keymember(certfile, 1, SocketOpts) @@ -124,15 +126,6 @@ do_listen(SocketOpts0, Logger) -> SocketOpts2 = ranch:set_option_default(SocketOpts1, nodelay, true), SocketOpts3 = ranch:set_option_default(SocketOpts2, send_timeout, 30000), SocketOpts = ranch:set_option_default(SocketOpts3, send_timeout_close, true), - %% In case of a local socket, we remove the socket file first. - %% It is possible to have multiple ip tuples in the socket options, - %% and the last one will be used (undocumented). - _ = case lists:keyfind(ip, 1, lists:reverse(SocketOpts0)) of - {ip, {local, SockFile}} -> - file:delete(SockFile); - _ -> - ok - end, %% We set the port to 0 because it is given in the Opts directly. %% The port in the options takes precedence over the one in the %% first argument. @@ -287,3 +280,15 @@ shutdown(Socket, How) -> -spec close(ssl:sslsocket()) -> ok. close(Socket) -> ssl:close(Socket). + +-spec cleanup(ranch:transport_opts(opts())) -> ok. +cleanup(#{socket_opts:=SocketOpts}) -> + case lists:keyfind(ip, 1, lists:reverse(SocketOpts)) of + {ip, {local, SockFile}} -> + _ = file:delete(SockFile), + ok; + _ -> + ok + end; +cleanup(_) -> + ok. diff --git a/src/ranch_tcp.erl b/src/ranch_tcp.erl index 4abd088..28d221c 100644 --- a/src/ranch_tcp.erl +++ b/src/ranch_tcp.erl @@ -43,6 +43,7 @@ -export([sockname/1]). -export([shutdown/2]). -export([close/1]). +-export([cleanup/1]). -type opt() :: {backlog, non_neg_integer()} | {buffer, non_neg_integer()} @@ -86,21 +87,13 @@ messages() -> {tcp, tcp_closed, tcp_error, tcp_passive}. -spec listen(ranch:transport_opts(opts())) -> {ok, inet:socket()} | {error, atom()}. listen(TransOpts) -> + ok = cleanup(TransOpts), Logger = maps:get(logger, TransOpts, logger), SocketOpts0 = maps:get(socket_opts, TransOpts, []), SocketOpts1 = ranch:set_option_default(SocketOpts0, backlog, 1024), SocketOpts2 = ranch:set_option_default(SocketOpts1, nodelay, true), SocketOpts3 = ranch:set_option_default(SocketOpts2, send_timeout, 30000), SocketOpts4 = ranch:set_option_default(SocketOpts3, send_timeout_close, true), - %% In case of a local socket, we remove the socket file first. - %% It is possible to have multiple ip tuples in the socket options, - %% and the last one will be used (undocumented). - _ = case lists:keyfind(ip, 1, lists:reverse(SocketOpts0)) of - {ip, {local, SockFile}} -> - file:delete(SockFile); - _ -> - ok - end, %% We set the port to 0 because it is given in the Opts directly. %% The port in the options takes precedence over the one in the %% first argument. @@ -271,3 +264,15 @@ shutdown(Socket, How) -> -spec close(inet:socket()) -> ok. close(Socket) -> gen_tcp:close(Socket). + +-spec cleanup(ranch:transport_opts(opts())) -> ok. +cleanup(#{socket_opts:=SocketOpts}) -> + case lists:keyfind(ip, 1, lists:reverse(SocketOpts)) of + {ip, {local, SockFile}} -> + _ = file:delete(SockFile), + ok; + _ -> + ok + end; +cleanup(_) -> + ok. diff --git a/src/ranch_transport.erl b/src/ranch_transport.erl index 5fd6242..23d9d5c 100644 --- a/src/ranch_transport.erl +++ b/src/ranch_transport.erl @@ -66,6 +66,7 @@ -callback shutdown(socket(), read | write | read_write) -> ok | {error, atom()}. -callback close(socket()) -> ok. +-callback cleanup(ranch:transport_opts(any())) -> ok. %% A fallback for transports that don't have a native sendfile implementation. %% Note that the ordering of arguments is different from file:sendfile/5 and diff --git a/test/acceptor_SUITE.erl b/test/acceptor_SUITE.erl index 19b7057..290d041 100644 --- a/test/acceptor_SUITE.erl +++ b/test/acceptor_SUITE.erl @@ -77,7 +77,7 @@ groups() -> misc_opts_logger, misc_set_transport_options, misc_wait_for_connections, - misc_multiple_ips_in_listen_opts + misc_multiple_ip_local_socket_opts ]}, {supervisor, [ connection_type_supervisor, connection_type_supervisor_separate_from_connection, @@ -405,15 +405,15 @@ do_expect_waiter(WaiterPid) -> end end. -misc_multiple_ips_in_listen_opts(_) -> +misc_multiple_ip_local_socket_opts(_) -> case do_os_supports_local_sockets() of true -> - do_misc_multiple_ips_in_listen_opts(); + do_misc_multiple_ip_local_socket_opts(); false -> {skip, "No local socket support."} end. -do_misc_multiple_ips_in_listen_opts() -> +do_misc_multiple_ip_local_socket_opts() -> doc("Ensure that a listener uses the expected ip option if multiple are given."), Name = name(), SockFile1 = do_tempname(), @@ -421,7 +421,14 @@ do_misc_multiple_ips_in_listen_opts() -> Opts = [{ip, {local, SockFile1}}, {ip, {local, SockFile2}}], {ok, _} = ranch:start_listener(Name, ranch_tcp, #{socket_opts => Opts}, echo_protocol, []), {local, SockFile2} = ranch:get_addr(Name), - ok = ranch:stop_listener(Name). + %% Make sure the socket file from the ignored ip option + %% has not been created. + {error, enoent} = file:read_file_info(SockFile1), + ok = ranch:stop_listener(Name), + %% Make sure the socket file from the accepted ip option + %% is removed. + {error, enoent} = file:read_file_info(SockFile2), + ok. %% ssl. @@ -607,6 +614,8 @@ do_ssl_local_echo() -> {error, closed} = ssl:recv(Socket, 0, 1000), %% Make sure the listener stopped. {'EXIT', _} = begin catch ranch:get_port(Name) end, + %% Make sure the socket file is removed. + {error, enoent} = file:read_file_info(SockFile), ok after file:delete(SockFile) @@ -900,6 +909,8 @@ do_tcp_local_echo() -> {error, closed} = gen_tcp:recv(Socket, 0, 1000), %% Make sure the listener stopped. {'EXIT', _} = begin catch ranch:get_port(Name) end, + %% Make sure the socket file is removed. + {error, enoent} = file:read_file_info(SockFile), ok after file:delete(SockFile) -- cgit v1.2.3