diff options
-rw-r--r-- | manual/ranch_protocol.md | 11 | ||||
-rw-r--r-- | src/ranch_protocol.erl | 3 | ||||
-rw-r--r-- | test/acceptor_SUITE.erl | 38 | ||||
-rw-r--r-- | test/supervisor_separate.erl | 16 |
4 files changed, 65 insertions, 3 deletions
diff --git a/manual/ranch_protocol.md b/manual/ranch_protocol.md index 3e8b62e..807d20a 100644 --- a/manual/ranch_protocol.md +++ b/manual/ranch_protocol.md @@ -12,7 +12,7 @@ None. Callbacks --------- -### start_link(Ref, Socket, Transport, ProtoOpts) -> {ok, pid()} +### start_link(Ref, Socket, Transport, ProtoOpts) -> {ok, pid()} | {ok, pid(), pid()} > Types: > * Ref = ranch:ref() @@ -27,9 +27,16 @@ Callbacks > then return the new pid. This function will always be called > from inside a supervisor. > +> This callback can also return two pids. The first pid is the +> pid of the process that will be supervised. The second pid is +> the pid of the process that will receive ownership of the +> socket. This second process must be a child of the first. This +> form is only available when `connection_type` is set to +> `supervisor`. +> > If any other value is returned, the supervisor will close the > socket and assume no process has been started. > -> Do not perform any operation in this callback, as this would +> Do not perform any operations in this callback, as this would > block the supervisor responsible for starting connection > processes and degrade performance severely. diff --git a/src/ranch_protocol.erl b/src/ranch_protocol.erl index 397b227..1f70962 100644 --- a/src/ranch_protocol.erl +++ b/src/ranch_protocol.erl @@ -20,4 +20,5 @@ Socket::any(), Transport::module(), ProtocolOptions::any()) - -> {ok, ConnectionPid::pid()}. + -> {ok, ConnectionPid::pid()} + | {ok, SupPid::pid(), ConnectionPid::pid()}. diff --git a/test/acceptor_SUITE.erl b/test/acceptor_SUITE.erl index 07d4016..af1ea5e 100644 --- a/test/acceptor_SUITE.erl +++ b/test/acceptor_SUITE.erl @@ -42,6 +42,8 @@ groups() -> ]}, {misc, [ misc_bad_transport ]}, {supervisor, [ + connection_type_supervisor, + connection_type_supervisor_separate_from_connection, supervisor_clean_child_restart, supervisor_clean_conns_sup_restart, supervisor_clean_restart, @@ -298,6 +300,42 @@ tcp_upgrade(_) -> %% Supervisor tests +connection_type_supervisor(_) -> + doc("The supervisor connection type must be reflected in the specifications."), + Name = connection_type_supervisor, + {ok, _} = ranch:start_listener(Name, 1, + ranch_tcp, [{connection_type, supervisor}], + echo_protocol, []), + Port = ranch:get_port(Name), + {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]), + ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>), + {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000), + ConnsSup = ranch_server:get_connections_sup(Name), + [{echo_protocol, _, supervisor, [echo_protocol]}] = supervisor:which_children(ConnsSup), + ok = ranch:stop_listener(Name), + {error, closed} = gen_tcp:recv(Socket, 0, 1000), + %% Make sure the listener stopped. + {'EXIT', _} = begin catch ranch:get_port(Name) end, + ok. + +connection_type_supervisor_separate_from_connection(_) -> + doc("The supervisor connection type allows separate supervised and connection processes."), + Name = connection_type_supervisor, + {ok, _} = ranch:start_listener(Name, 1, + ranch_tcp, [{connection_type, supervisor}], + supervisor_separate, []), + Port = ranch:get_port(Name), + {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]), + ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>), + {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000), + ConnsSup = ranch_server:get_connections_sup(Name), + [{supervisor_separate, _, supervisor, [supervisor_separate]}] = supervisor:which_children(ConnsSup), + ok = ranch:stop_listener(Name), + {error, closed} = gen_tcp:recv(Socket, 0, 1000), + %% Make sure the listener stopped. + {'EXIT', _} = begin catch ranch:get_port(Name) end, + ok. + supervisor_clean_child_restart(_) -> %% Then we verify that only parts of the supervision tree %% restarted in the case of failure. diff --git a/test/supervisor_separate.erl b/test/supervisor_separate.erl new file mode 100644 index 0000000..5f1f326 --- /dev/null +++ b/test/supervisor_separate.erl @@ -0,0 +1,16 @@ +-module(supervisor_separate). +-behavior(supervisor). +-behavior(ranch_protocol). + +-export([start_link/4]). +-export([init/1]). + +start_link(Ref, Socket, Transport, Opts) -> + {ok, SupPid} = supervisor:start_link(?MODULE, []), + {ok, ConnPid} = supervisor:start_child(SupPid, + {echo_protocol, {echo_protocol, start_link, [Ref, Socket, Transport, Opts]}, + temporary, 5000, worker, [echo_protocol]}), + {ok, SupPid, ConnPid}. + +init([]) -> + {ok, {{one_for_one, 1, 1}, []}}. |