From eabb029895c8345ccedc41ed28a023d0e75c7e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Mon, 6 Aug 2012 14:23:16 +0200 Subject: Check the accept/2 return value for errors Distinguish the errors from transport_accept and ssl_accept in ranch_ssl. {error, closed} for the first one means the listening socket got closed; for the second one it means the connection socket was. Ignore all errors except when the listening socket got closed, where we want to crash to allow opening the socket again. --- src/ranch_acceptor.erl | 18 ++++++++++++++---- src/ranch_ssl.erl | 6 +++--- test/acceptor_SUITE.erl | 17 +++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/ranch_acceptor.erl b/src/ranch_acceptor.erl index e03cde9..d208a7f 100644 --- a/src/ranch_acceptor.erl +++ b/src/ranch_acceptor.erl @@ -46,6 +46,11 @@ init(LSocket, Transport, Protocol, MaxConns, Opts, ListenerPid, ConnsSup) -> non_neg_integer(), any(), pid(), pid()) -> no_return(). loop(LSocket, Transport, Protocol, MaxConns, Opts, ListenerPid, ConnsSup) -> receive + %% We couldn't accept the socket but it's safe to continue. + {accept, continue} -> + ?MODULE:init(LSocket, Transport, Protocol, + MaxConns, Opts, ListenerPid, ConnsSup); + %% Found my sockets! {accept, CSocket} -> {ok, ConnPid} = supervisor:start_child(ConnsSup, [ListenerPid, CSocket, Transport, Protocol, Opts]), @@ -55,6 +60,7 @@ loop(LSocket, Transport, Protocol, MaxConns, Opts, ListenerPid, ConnsSup) -> maybe_wait(ListenerPid, MaxConns, NbConns), ?MODULE:init(LSocket, Transport, Protocol, MaxConns, Opts, ListenerPid, ConnsSup); + %% Upgrade the protocol options. {set_opts, Opts2} -> ?MODULE:loop(LSocket, Transport, Protocol, MaxConns, Opts2, ListenerPid, ConnsSup) @@ -72,9 +78,13 @@ maybe_wait(ListenerPid, MaxConns, _) -> async_accept(LSocket, Transport) -> AcceptorPid = self(), _ = spawn_link(fun() -> - %% @todo {error, closed} must be handled and other errors ignored. - {ok, CSocket} = Transport:accept(LSocket, infinity), - Transport:controlling_process(CSocket, AcceptorPid), - AcceptorPid ! {accept, CSocket} + case Transport:accept(LSocket, infinity) of + {ok, CSocket} -> + Transport:controlling_process(CSocket, AcceptorPid), + AcceptorPid ! {accept, CSocket}; + %% We want to crash if the listening socket got closed. + {error, Reason} when Reason =/= closed -> + AcceptorPid ! {accept, continue} + end end), ok. diff --git a/src/ranch_ssl.erl b/src/ranch_ssl.erl index 51ea128..d85c05f 100644 --- a/src/ranch_ssl.erl +++ b/src/ranch_ssl.erl @@ -111,7 +111,7 @@ listen(Opts) -> %% @see ssl:transport_accept/2 %% @see ssl:ssl_accept/2 -spec accept(ssl:sslsocket(), timeout()) - -> {ok, ssl:sslsocket()} | {error, closed | timeout | atom()}. + -> {ok, ssl:sslsocket()} | {error, closed | timeout | atom() | tuple()}. accept(LSocket, Timeout) -> case ssl:transport_accept(LSocket, Timeout) of {ok, CSocket} -> @@ -179,11 +179,11 @@ require([App|Tail]) -> require(Tail). -spec ssl_accept(ssl:sslsocket(), timeout()) - -> {ok, ssl:sslsocket()} | {error, closed | timeout | atom()}. + -> {ok, ssl:sslsocket()} | {error, {ssl_accept, atom()}}. ssl_accept(Socket, Timeout) -> case ssl:ssl_accept(Socket, Timeout) of ok -> {ok, Socket}; {error, Reason} -> - {error, Reason} + {error, {ssl_accept, Reason}} end. diff --git a/test/acceptor_SUITE.erl b/test/acceptor_SUITE.erl index 389f375..1c0931b 100644 --- a/test/acceptor_SUITE.erl +++ b/test/acceptor_SUITE.erl @@ -25,6 +25,7 @@ -export([end_per_group/2]). %% ssl. +-export([ssl_accept_error/1]). -export([ssl_echo/1]). %% tcp. @@ -45,6 +46,7 @@ groups() -> tcp_max_connections_and_beyond, tcp_upgrade ]}, {ssl, [ + ssl_accept_error, ssl_echo ]}]. @@ -74,6 +76,21 @@ end_per_group(_, _) -> %% ssl. +ssl_accept_error(Config) -> + {ok, _} = ranch:start_listener(ssl_accept_error, 1, + ranch_ssl, [{port, 0}, + {certfile, ?config(data_dir, Config) ++ "cert.pem"}], + echo_protocol, []), + Port = ranch:get_port(ssl_accept_error), + [AcceptorPid] = ets:lookup_element(ranch_server, + {acceptors, ssl_accept_error}, 2), + true = is_process_alive(AcceptorPid), + {ok, Socket} = gen_tcp:connect("localhost", Port, + [binary, {active, false}, {packet, raw}]), + ok = gen_tcp:close(Socket), + receive after 500 -> ok end, + true = is_process_alive(AcceptorPid). + ssl_echo(Config) -> {ok, _} = ranch:start_listener(ssl_echo, 1, ranch_ssl, [{port, 0}, -- cgit v1.2.3