aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/src/guide/listeners.asciidoc52
-rw-r--r--doc/src/manual/ranch.asciidoc46
-rw-r--r--src/ranch.erl81
-rw-r--r--src/ranch_acceptors_sup.erl11
-rw-r--r--src/ranch_listener_sup.erl4
-rw-r--r--src/ranch_server.erl41
-rw-r--r--test/acceptor_SUITE.erl85
7 files changed, 296 insertions, 24 deletions
diff --git a/doc/src/guide/listeners.asciidoc b/doc/src/guide/listeners.asciidoc
index 97afa22..21a6838 100644
--- a/doc/src/guide/listeners.asciidoc
+++ b/doc/src/guide/listeners.asciidoc
@@ -91,6 +91,34 @@ named `tcp_echo`. We can now stop it.
[source,erlang]
ranch:stop_listener(tcp_echo).
+=== Suspending and resuming a listener
+
+Listeners can be suspended and resumed by calling
+`ranch:suspend_listener/1` and `ranch:resume_listener/1`,
+respectively, with the name of the listener as argument.
+
+Suspending a listener will cause it to stop listening and not accept
+new connections, but existing connection processes will not be stopped.
+
+.Suspending a listener
+
+[source,erlang]
+ranch:suspend_listener(tcp_echo).
+
+Resuming a listener will cause it to start listening and accept new
+connections again.
+It is worth mentioning, however, that if the listener is configured
+to listen on a random port, it will listen on a different port than
+before it was suspended.
+
+.Resuming a listener
+
+[source,erlang]
+ranch:resume_listener(tcp_echo).
+
+Whether a listener is currently running or suspended can be queried
+by calling `ranch:get_status/1` with the listener name as argument.
+
=== Default transport options
By default the socket will be set to return `binary` data, with the
@@ -296,6 +324,30 @@ calling `ranch:get_protocol_options/1`.
[source,erlang]
Opts = ranch:get_protocol_options(tcp_echo).
+=== Changing transport options
+
+Ranch allows you to change the transport options of a listener, for
+example to make it listen on a different port.
+
+To change transport options, the listener has to be suspended first.
+Then you are allowed to change the transport options by calling
+`ranch:set_transport_options/2` with the listener name and the new
+transport options as arguments.
+After that, you can resume the listener.
+
+.Changing the transport options
+
+[source,erlang]
+ranch:set_transport_options(tcp_echo, NewOpts).
+
+You can retrieve the current transport options by calling
+`ranch:get_transport_options/1`.
+
+.Retrieving the current transport options
+
+[source,erlang]
+Opts = ranch:get_transport_options(tcp_echo).
+
=== Obtaining information about listeners
Ranch provides two functions for retrieving information about the
diff --git a/doc/src/manual/ranch.asciidoc b/doc/src/manual/ranch.asciidoc
index e0244c8..b442f88 100644
--- a/doc/src/manual/ranch.asciidoc
+++ b/doc/src/manual/ranch.asciidoc
@@ -114,6 +114,19 @@ ProtoOpts = any():: Current protocol options.
Return the protocol options set for the given listener.
+=== get_status(Ref) -> running | suspended
+
+Ref = ref():: Listener name.
+
+Return the status of the given listener.
+
+=== get_transport_options(Ref) -> ProtoOpts
+
+Ref = ref():: Listener name.
+TransOpts = any():: Current transport options.
+
+Return the transport options set for the given listener.
+
=== info() -> [{Ref, [{Key, Value}]}]
Ref = ref():: Listener name.
@@ -155,6 +168,16 @@ without sacrificing the latency of the system.
This function may only be called from a connection process.
+=== resume_listener(Ref) -> ok
+
+Ref = ref():: Listener name.
+
+Resume the given listener if it is suspended.
+If the listener is already running, nothing will happen.
+
+The listener will be started with the transport options
+currently set for it.
+
=== set_max_connections(Ref, MaxConns) -> ok
Ref = ref():: Listener name.
@@ -176,6 +199,18 @@ Set the protocol options for the given listener.
The change will be applied immediately for all new connections.
Old connections will not receive the new options.
+=== set_transport_options(Ref, TransOpts) -> ok | {error, running}
+
+Ref = ref():: Listener name.
+ProtoOpts = any():: New transport options.
+
+Set the transport options for the given listener.
+
+The listener must be suspended for this call to succeed.
+If the listener is running, `{error, running}` will be returned.
+
+The change will take effect when the listener is being resumed.
+
=== start_listener(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts) -> {ok, pid()} | {error, badarg}
Ref = ref():: Listener name.
@@ -207,3 +242,14 @@ connection processes or give them some time to stop properly.
This function does not return until the listener is
completely stopped.
+
+=== suspend_listener(Ref) -> ok
+
+Ref = ref():: Listener name.
+
+Suspend the given listener if it is running.
+If the listener is already suspended, nothing will happen.
+
+The listener will stop listening and accepting connections by
+closing the listening port, but will not stop running connection
+processes.
diff --git a/src/ranch.erl b/src/ranch.erl
index 70fb64c..5af4b74 100644
--- a/src/ranch.erl
+++ b/src/ranch.erl
@@ -17,17 +17,23 @@
-export([start_listener/5]).
-export([start_listener/6]).
-export([stop_listener/1]).
+-export([suspend_listener/1]).
+-export([resume_listener/1]).
-export([child_spec/5]).
-export([child_spec/6]).
-export([accept_ack/1]).
-export([remove_connection/1]).
+-export([get_status/1]).
-export([get_addr/1]).
-export([get_port/1]).
-export([get_max_connections/1]).
-export([set_max_connections/2]).
+-export([get_transport_options/1]).
+-export([set_transport_options/2]).
-export([get_protocol_options/1]).
-export([set_protocol_options/2]).
-export([info/0]).
+-export([info/1]).
-export([procs/2]).
-export([filter_options/3]).
-export([set_option_default/3]).
@@ -110,6 +116,37 @@ stop_listener(Ref) ->
{error, Reason}
end.
+-spec suspend_listener(ref()) -> ok | {error, term()}.
+suspend_listener(Ref) ->
+ case get_status(Ref) of
+ running ->
+ ListenerSup = ranch_server:get_listener_sup(Ref),
+ ok = ranch_server:set_addr(Ref, {undefined, undefined}),
+ supervisor:terminate_child(ListenerSup, ranch_acceptors_sup);
+ suspended ->
+ ok
+ end.
+
+-spec resume_listener(ref()) -> ok | {error, term()}.
+resume_listener(Ref) ->
+ case get_status(Ref) of
+ running ->
+ ok;
+ suspended ->
+ ListenerSup = ranch_server:get_listener_sup(Ref),
+ Res = supervisor:restart_child(ListenerSup, ranch_acceptors_sup),
+ maybe_resumed(Res)
+ end.
+
+maybe_resumed(Error={error, {listen_error, _, Reason}}) ->
+ start_error(Reason, Error);
+maybe_resumed({ok, _}) ->
+ ok;
+maybe_resumed({ok, _, _}) ->
+ ok;
+maybe_resumed(Res) ->
+ Res.
+
-spec child_spec(ref(), module(), any(), module(), any())
-> supervisor:child_spec().
child_spec(Ref, Transport, TransOpts, Protocol, ProtoOpts) ->
@@ -137,11 +174,22 @@ remove_connection(Ref) ->
ConnsSup ! {remove_connection, Ref, self()},
ok.
--spec get_addr(ref()) -> {inet:ip_address(), inet:port_number()}.
+-spec get_status(ref()) -> running | suspended | restarting.
+get_status(Ref) ->
+ ListenerSup = ranch_server:get_listener_sup(Ref),
+ Children = supervisor:which_children(ListenerSup),
+ case lists:keyfind(ranch_acceptors_sup, 1, Children) of
+ {_, undefined, _, _} ->
+ suspended;
+ {_, AcceptorsSup, _, _} when is_pid(AcceptorsSup) ->
+ running
+ end.
+
+-spec get_addr(ref()) -> {inet:ip_address(), inet:port_number()} | {undefined, undefined}.
get_addr(Ref) ->
ranch_server:get_addr(Ref).
--spec get_port(ref()) -> inet:port_number().
+-spec get_port(ref()) -> inet:port_number() | undefined.
get_port(Ref) ->
{_, Port} = get_addr(Ref),
Port.
@@ -154,6 +202,19 @@ get_max_connections(Ref) ->
set_max_connections(Ref, MaxConnections) ->
ranch_server:set_max_connections(Ref, MaxConnections).
+-spec get_transport_options(ref()) -> any().
+get_transport_options(Ref) ->
+ ranch_server:get_transport_options(Ref).
+
+-spec set_transport_options(ref(), any()) -> ok | {error, running}.
+set_transport_options(Ref, TransOpts) ->
+ case get_status(Ref) of
+ suspended ->
+ ok = ranch_server:set_transport_options(Ref, TransOpts);
+ running ->
+ {error, running}
+ end.
+
-spec get_protocol_options(ref()) -> any().
get_protocol_options(Ref) ->
ranch_server:get_protocol_options(Ref).
@@ -167,14 +228,22 @@ info() ->
[{Ref, listener_info(Ref, Pid)}
|| {Ref, Pid} <- ranch_server:get_listener_sups()].
+-spec info(ref()) -> [{atom(), any()}].
+info(Ref) ->
+ Pid = ranch_server:get_listener_sup(Ref),
+ listener_info(Ref, Pid).
+
listener_info(Ref, Pid) ->
- [_, NumAcceptors, Transport, TransOpts, Protocol, _] = ranch_server:get_listener_start_args(Ref),
+ [_, NumAcceptors, Transport, _, Protocol, _] = ranch_server:get_listener_start_args(Ref),
ConnsSup = ranch_server:get_connections_sup(Ref),
+ Status = get_status(Ref),
{IP, Port} = get_addr(Ref),
MaxConns = get_max_connections(Ref),
+ TransOpts = ranch_server:get_transport_options(Ref),
ProtoOpts = get_protocol_options(Ref),
[
{pid, Pid},
+ {status, Status},
{ip, IP},
{port, Port},
{num_acceptors, NumAcceptors},
@@ -197,7 +266,11 @@ procs1(Ref, Sup) ->
ListenerSup = ranch_server:get_listener_sup(Ref),
{_, SupPid, _, _} = lists:keyfind(Sup, 1,
supervisor:which_children(ListenerSup)),
- [Pid || {_, Pid, _, _} <- supervisor:which_children(SupPid)].
+ try
+ [Pid || {_, Pid, _, _} <- supervisor:which_children(SupPid)]
+ catch exit:{noproc, _} when Sup =:= ranch_acceptors_sup ->
+ []
+ end.
-spec filter_options([inet | inet6 | {atom(), any()} | {raw, any(), any(), any()}],
[atom()], Acc) -> Acc when Acc :: [any()].
diff --git a/src/ranch_acceptors_sup.erl b/src/ranch_acceptors_sup.erl
index f4b2fd8..9e39f2d 100644
--- a/src/ranch_acceptors_sup.erl
+++ b/src/ranch_acceptors_sup.erl
@@ -15,16 +15,17 @@
-module(ranch_acceptors_sup).
-behaviour(supervisor).
--export([start_link/4]).
+-export([start_link/3]).
-export([init/1]).
--spec start_link(ranch:ref(), non_neg_integer(), module(), any())
+-spec start_link(ranch:ref(), non_neg_integer(), module())
-> {ok, pid()}.
-start_link(Ref, NumAcceptors, Transport, TransOpts) ->
- supervisor:start_link(?MODULE, [Ref, NumAcceptors, Transport, TransOpts]).
+start_link(Ref, NumAcceptors, Transport) ->
+ supervisor:start_link(?MODULE, [Ref, NumAcceptors, Transport]).
-init([Ref, NumAcceptors, Transport, TransOpts]) ->
+init([Ref, NumAcceptors, Transport]) ->
ConnsSup = ranch_server:get_connections_sup(Ref),
+ TransOpts = ranch_server:get_transport_options(Ref),
LSocket = case proplists:get_value(socket, TransOpts) of
undefined ->
TransOpts2 = proplists:delete(ack_timeout,
diff --git a/src/ranch_listener_sup.erl b/src/ranch_listener_sup.erl
index d3bc59d..502df44 100644
--- a/src/ranch_listener_sup.erl
+++ b/src/ranch_listener_sup.erl
@@ -22,7 +22,7 @@
-> {ok, pid()}.
start_link(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts) ->
MaxConns = proplists:get_value(max_connections, TransOpts, 1024),
- ranch_server:set_new_listener_opts(Ref, MaxConns, ProtoOpts,
+ ranch_server:set_new_listener_opts(Ref, MaxConns, TransOpts, ProtoOpts,
[Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts]),
supervisor:start_link(?MODULE, {
Ref, NumAcceptors, Transport, TransOpts, Protocol
@@ -38,7 +38,7 @@ init({Ref, NumAcceptors, Transport, TransOpts, Protocol}) ->
[Ref, ConnType, Shutdown, Transport, AckTimeout, Protocol]},
permanent, infinity, supervisor, [ranch_conns_sup]},
{ranch_acceptors_sup, {ranch_acceptors_sup, start_link,
- [Ref, NumAcceptors, Transport, TransOpts]},
+ [Ref, NumAcceptors, Transport]},
permanent, infinity, supervisor, [ranch_acceptors_sup]}
],
{ok, {{rest_for_one, 1, 5}, ChildSpecs}}.
diff --git a/src/ranch_server.erl b/src/ranch_server.erl
index 89c508c..80f82d6 100644
--- a/src/ranch_server.erl
+++ b/src/ranch_server.erl
@@ -17,7 +17,7 @@
%% API.
-export([start_link/0]).
--export([set_new_listener_opts/4]).
+-export([set_new_listener_opts/5]).
-export([cleanup_listener_opts/1]).
-export([set_connections_sup/2]).
-export([get_connections_sup/1]).
@@ -29,6 +29,8 @@
-export([get_addr/1]).
-export([set_max_connections/2]).
-export([get_max_connections/1]).
+-export([set_transport_options/2]).
+-export([get_transport_options/1]).
-export([set_protocol_options/2]).
-export([get_protocol_options/1]).
-export([get_listener_start_args/1]).
@@ -55,15 +57,16 @@
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
--spec set_new_listener_opts(ranch:ref(), ranch:max_conns(), any(), [any()]) -> ok.
-set_new_listener_opts(Ref, MaxConns, ProtoOpts, StartArgs) ->
- gen_server:call(?MODULE, {set_new_listener_opts, Ref, MaxConns, ProtoOpts, StartArgs}).
+-spec set_new_listener_opts(ranch:ref(), ranch:max_conns(), any(), any(), [any()]) -> ok.
+set_new_listener_opts(Ref, MaxConns, TransOpts, ProtoOpts, StartArgs) ->
+ gen_server:call(?MODULE, {set_new_listener_opts, Ref, MaxConns, TransOpts, ProtoOpts, StartArgs}).
-spec cleanup_listener_opts(ranch:ref()) -> ok.
cleanup_listener_opts(Ref) ->
_ = ets:delete(?TAB, {addr, Ref}),
_ = ets:delete(?TAB, {max_conns, Ref}),
- _ = ets:delete(?TAB, {opts, Ref}),
+ _ = ets:delete(?TAB, {trans_opts, Ref}),
+ _ = ets:delete(?TAB, {proto_opts, Ref}),
_ = ets:delete(?TAB, {listener_start_args, Ref}),
%% We also remove the pid of the connections supervisor.
%% Depending on the timing, it might already have been deleted
@@ -103,11 +106,11 @@ get_listener_sup(Ref) ->
get_listener_sups() ->
[{Ref, Pid} || [Ref, Pid] <- ets:match(?TAB, {{listener_sup, '$1'}, '$2'})].
--spec set_addr(ranch:ref(), {inet:ip_address(), inet:port_number()}) -> ok.
+-spec set_addr(ranch:ref(), {inet:ip_address(), inet:port_number()} | {undefined, undefined}) -> ok.
set_addr(Ref, Addr) ->
gen_server:call(?MODULE, {set_addr, Ref, Addr}).
--spec get_addr(ranch:ref()) -> {inet:ip_address(), inet:port_number()}.
+-spec get_addr(ranch:ref()) -> {inet:ip_address(), inet:port_number()} | {undefined, undefined}.
get_addr(Ref) ->
ets:lookup_element(?TAB, {addr, Ref}, 2).
@@ -119,13 +122,21 @@ set_max_connections(Ref, MaxConnections) ->
get_max_connections(Ref) ->
ets:lookup_element(?TAB, {max_conns, Ref}, 2).
+-spec set_transport_options(ranch:ref(), any()) -> ok.
+set_transport_options(Ref, TransOpts) ->
+ gen_server:call(?MODULE, {set_trans_opts, Ref, TransOpts}).
+
+-spec get_transport_options(ranch:ref()) -> any().
+get_transport_options(Ref) ->
+ ets:lookup_element(?TAB, {trans_opts, Ref}, 2).
+
-spec set_protocol_options(ranch:ref(), any()) -> ok.
set_protocol_options(Ref, ProtoOpts) ->
- gen_server:call(?MODULE, {set_opts, Ref, ProtoOpts}).
+ gen_server:call(?MODULE, {set_proto_opts, Ref, ProtoOpts}).
-spec get_protocol_options(ranch:ref()) -> any().
get_protocol_options(Ref) ->
- ets:lookup_element(?TAB, {opts, Ref}, 2).
+ ets:lookup_element(?TAB, {proto_opts, Ref}, 2).
-spec get_listener_start_args(ranch:ref()) -> [any()].
get_listener_start_args(Ref) ->
@@ -144,9 +155,10 @@ init([]) ->
[Ref, Pid] <- ets:match(?TAB, {{listener_sup, '$1'}, '$2'})],
{ok, #state{monitors=ConnMonitors++ListenerMonitors}}.
-handle_call({set_new_listener_opts, Ref, MaxConns, ProtoOpts, StartArgs}, _, State) ->
+handle_call({set_new_listener_opts, Ref, MaxConns, TransOpts, ProtoOpts, StartArgs}, _, State) ->
ets:insert(?TAB, {{max_conns, Ref}, MaxConns}),
- ets:insert(?TAB, {{opts, Ref}, ProtoOpts}),
+ ets:insert(?TAB, {{trans_opts, Ref}, TransOpts}),
+ ets:insert(?TAB, {{proto_opts, Ref}, ProtoOpts}),
ets:insert(?TAB, {{listener_start_args, Ref}, StartArgs}),
{reply, ok, State};
handle_call({set_connections_sup, Ref, Pid}, _,
@@ -177,8 +189,11 @@ handle_call({set_max_conns, Ref, MaxConns}, _, State) ->
ConnsSup = get_connections_sup(Ref),
ConnsSup ! {set_max_conns, MaxConns},
{reply, ok, State};
-handle_call({set_opts, Ref, Opts}, _, State) ->
- ets:insert(?TAB, {{opts, Ref}, Opts}),
+handle_call({set_trans_opts, Ref, Opts}, _, State) ->
+ ets:insert(?TAB, {{trans_opts, Ref}, Opts}),
+ {reply, ok, State};
+handle_call({set_proto_opts, Ref, Opts}, _, State) ->
+ ets:insert(?TAB, {{proto_opts, Ref}, Opts}),
ConnsSup = get_connections_sup(Ref),
ConnsSup ! {set_opts, Opts},
{reply, ok, State};
diff --git a/test/acceptor_SUITE.erl b/test/acceptor_SUITE.erl
index a8c6d23..e441b51 100644
--- a/test/acceptor_SUITE.erl
+++ b/test/acceptor_SUITE.erl
@@ -28,6 +28,7 @@ groups() ->
tcp_accept_socket,
tcp_active_echo,
tcp_echo,
+ tcp_graceful,
tcp_inherit_options,
tcp_max_connections,
tcp_max_connections_and_beyond,
@@ -45,6 +46,7 @@ groups() ->
ssl_accept_socket,
ssl_active_echo,
ssl_echo,
+ ssl_graceful,
ssl_sni_echo,
ssl_sni_fail,
ssl_getopts_capability,
@@ -113,6 +115,7 @@ misc_info(_) ->
[
{{misc_info, act}, [
{pid, Pid2},
+ {status, _},
{ip, _},
{port, Port2},
{num_acceptors, 2},
@@ -126,6 +129,7 @@ misc_info(_) ->
]},
{{misc_info, ssl}, [
{pid, Pid3},
+ {status, _},
{ip, _},
{port, Port3},
{num_acceptors, 3},
@@ -139,6 +143,7 @@ misc_info(_) ->
]},
{{misc_info, tcp}, [
{pid, Pid1},
+ {status, _},
{ip, _},
{port, Port1},
{num_acceptors, 1},
@@ -189,6 +194,7 @@ misc_info_embedded(_) ->
[
{{misc_info_embedded, act}, [
{pid, Pid2},
+ {status, _},
{ip, _},
{port, Port2},
{num_acceptors, 2},
@@ -202,6 +208,7 @@ misc_info_embedded(_) ->
]},
{{misc_info_embedded, ssl}, [
{pid, Pid3},
+ {status, _},
{ip, _},
{port, Port3},
{num_acceptors, 3},
@@ -215,6 +222,7 @@ misc_info_embedded(_) ->
]},
{{misc_info_embedded, tcp}, [
{pid, Pid1},
+ {status, _},
{ip, _},
{port, Port1},
{num_acceptors, 1},
@@ -364,6 +372,45 @@ do_ssl_sni_fail() ->
{'EXIT', _} = begin catch ranch:get_port(Name) end,
ok.
+ssl_graceful(_) ->
+ doc("Ensure suspending and resuming of listeners does not kill active connections."),
+ Name = name(),
+ Opts = ct_helper:get_certs_from_ets(),
+ {ok, _} = ranch:start_listener(Name, ranch_ssl, Opts, echo_protocol, []),
+ Port = ranch:get_port(Name),
+ %% Make sure connections with a fresh listener work.
+ running = ranch:get_status(Name),
+ {ok, Socket1} = ssl:connect("localhost", Port,
+ [binary, {active, false}, {packet, raw}]),
+ ok = ssl:send(Socket1, <<"SSL with fresh listener">>),
+ {ok, <<"SSL with fresh listener">>} = ssl:recv(Socket1, 23, 1000),
+ %% Make sure transport options cannot be changed on a running listener.
+ {error, running} = ranch:set_transport_options(Name, [{port, Port}|Opts]),
+ %% Suspend listener, make sure established connections keep running.
+ ok = ranch:suspend_listener(Name),
+ suspended = ranch:get_status(Name),
+ ok = ssl:send(Socket1, <<"SSL with suspended listener">>),
+ {ok, <<"SSL with suspended listener">>} = ssl:recv(Socket1, 27, 1000),
+ %% Make sure new connections are refused on the suspended listener.
+ {error, econnrefused} = ssl:connect("localhost", Port,
+ [binary, {active, false}, {packet, raw}]),
+ %% Make sure transport options can be changed when listener is suspended.
+ ok = ranch:set_transport_options(Name, [{port, Port}|Opts]),
+ %% Resume listener, make sure connections can be established again.
+ ok = ranch:resume_listener(Name),
+ running = ranch:get_status(Name),
+ {ok, Socket2} = ssl:connect("localhost", Port,
+ [binary, {active, false}, {packet, raw}]),
+ ok = ssl:send(Socket2, <<"SSL with resumed listener">>),
+ {ok, <<"SSL with resumed listener">>} = ssl:recv(Socket2, 25, 1000),
+ %% Make sure transport options cannot be changed on resumed listener.
+ {error, running} = ranch:set_transport_options(Name, [{port, Port}|Opts]),
+ ok = ranch:stop_listener(Name),
+ {error, closed} = ssl:recv(Socket1, 0, 1000),
+ {error, closed} = ssl:recv(Socket2, 0, 1000),
+ {'EXIT', _} = begin catch ranch:get_port(Name) end,
+ ok.
+
ssl_getopts_capability(_) ->
doc("Ensure getopts/2 capability."),
Name=name(),
@@ -478,6 +525,44 @@ tcp_echo(_) ->
{'EXIT', _} = begin catch ranch:get_port(Name) end,
ok.
+tcp_graceful(_) ->
+ doc("Ensure suspending and resuming of listeners does not kill active connections."),
+ Name = name(),
+ {ok, _} = ranch:start_listener(Name, ranch_tcp, [], echo_protocol, []),
+ Port = ranch:get_port(Name),
+ %% Make sure connections with a fresh listener work.
+ running = ranch:get_status(Name),
+ {ok, Socket1} = gen_tcp:connect("localhost", Port,
+ [binary, {active, false}, {packet, raw}]),
+ ok = gen_tcp:send(Socket1, <<"TCP with fresh listener">>),
+ {ok, <<"TCP with fresh listener">>} = gen_tcp:recv(Socket1, 23, 1000),
+ %% Make sure transport options cannot be changed on a running listener.
+ {error, running} = ranch:set_transport_options(Name, [{port, Port}]),
+ %% Suspend listener, make sure established connections keep running.
+ ok = ranch:suspend_listener(Name),
+ suspended = ranch:get_status(Name),
+ ok = gen_tcp:send(Socket1, <<"TCP with suspended listener">>),
+ {ok, <<"TCP with suspended listener">>} = gen_tcp:recv(Socket1, 27, 1000),
+ %% Make sure new connections are refused on the suspended listener.
+ {error, econnrefused} = gen_tcp:connect("localhost", Port,
+ [binary, {active, false}, {packet, raw}]),
+ %% Make sure transport options can be changed when listener is suspended.
+ ok = ranch:set_transport_options(Name, [{port, Port}]),
+ %% Resume listener, make sure connections can be established again.
+ ok = ranch:resume_listener(Name),
+ running = ranch:get_status(Name),
+ {ok, Socket2} = gen_tcp:connect("localhost", Port,
+ [binary, {active, false}, {packet, raw}]),
+ ok = gen_tcp:send(Socket2, <<"TCP with resumed listener">>),
+ {ok, <<"TCP with resumed listener">>} = gen_tcp:recv(Socket2, 25, 1000),
+ %% Make sure transport options cannot be changed on resumed listener.
+ {error, running} = ranch:set_transport_options(Name, [{port, Port}]),
+ ok = ranch:stop_listener(Name),
+ {error, closed} = gen_tcp:recv(Socket1, 0, 1000),
+ {error, closed} = gen_tcp:recv(Socket2, 0, 1000),
+ {'EXIT', _} = begin catch ranch:get_port(Name) end,
+ ok.
+
tcp_inherit_options(_) ->
doc("Ensure TCP options are inherited in the protocol."),
Name = name(),