aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--manual/ranch_protocol.md11
-rw-r--r--src/ranch_protocol.erl3
-rw-r--r--test/acceptor_SUITE.erl38
-rw-r--r--test/supervisor_separate.erl16
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}, []}}.