Просмотр исходного кода

Use transport options in ranch_transport:listen/1 callbacks

The callback `ranch_transport:listen/1` has changed to accept a map
of transport options instead of socket options.
juhlig 6 лет назад
Родитель
Сommit
30604262b5

+ 5 - 0
doc/src/guide/upcoming_2.0_changes.asciidoc

@@ -5,6 +5,11 @@ The following changes will be done in Ranch 2.0. In most
 cases an alternative is already available in the most
 recent Ranch version.
 
+* The callback function `ranch_transport:listen/1` and its
+  implementations in `ranch_tcp` and `ranch_ssl` have changed
+  to accept a map of transport options instead of socket
+  options.
+
 * The function `ranch:start_listener/6` has been deprecated
   in favor of `ranch:start_listener/5`. The number of acceptors
   was removed and will be taken from the transport options.

+ 28 - 15
doc/src/manual/ranch.asciidoc

@@ -67,7 +67,30 @@ code.
 
 [source,erlang]
 ----
-opts() = any() | #{
+opts() = any() | transport_opts(any())
+----
+
+Transport or socket options.
+
+It is possible to give the full transport options in a map
+(see `transport_opts(SocketOpts)`), or only the socket options
+(assuming they are not a map and no Ranch-specific option
+needs to be given).
+
+=== ref()
+
+[source,erlang]
+----
+ref() = any()
+----
+
+Unique name used to refer to a listener.
+
+=== transport_opts(SocketOpts)
+
+[source,erlang]
+----
+transport_opts(SocketOpts) = #{
     connection_type   => worker | supervisor,
     handshake_timeout => timeout(),
     max_connections   => max_conns(),
@@ -75,16 +98,14 @@ opts() = any() | #{
     num_acceptors     => pos_integer(),
     num_conns_sups    => pos_integer(),
     shutdown          => timeout() | brutal_kill,
-    socket_opts       => any()
+    socket_opts       => SocketOpts
 }
 ----
 
 Transport options.
 
 The transport options are a combination of Ranch-specific
-options and socket options. Socket options may be given
-directly (assuming they are not a map and no Ranch-specific
-option needs to be given) or as part of `socket_opts`.
+options and transport-specific socket options.
 
 None of the options are required.
 
@@ -120,20 +141,12 @@ Maximum allowed time for children to stop on listener shutdown.
 
 socket_opts::
 
-Socket options given to `Transport:listen/1`. Please refer to the
+Socket options to be used by `Transport:listen/1`. Please refer to the
 documentation of the transport module you are using for more details.
 
-=== ref()
-
-[source,erlang]
-----
-ref() = any()
-----
-
-Unique name used to refer to a listener.
-
 == Changelog
 
+* *2.0*: The type `transport_opts(SocketOpts)` was added.
 * *2.0*: The function `ranch:accept_ack/1` was removed in favor of
          link:man:ranch:handshake(3)[ranch:handshake(3)].
 * *2.0*: The option `max_connections` is now per connection supervisor.

+ 5 - 2
doc/src/manual/ranch_transport.asciidoc

@@ -101,11 +101,12 @@ be upgraded to a `ranch_ssl` one using this function.
 
 [source,erlang]
 ----
-listen(SockOpts :: any())
+listen(TransportOpts :: ranch:transport_opts(any()))
     -> {ok, LSocket :: socket()} | {error, atom()}
 ----
 
-Create a socket that listens on the given port.
+Create a socket that listens on the port given in the
+socket options.
 
 The port may not be specified or may be set to 0, which
 means a random available port number will be chosen.
@@ -292,6 +293,8 @@ The exact type will vary depending on the transport module.
 
 == Changelog
 
+* *2.0*: The callback `listen/1` has changed to accept a map of
+         transport options instead of socket options.
 * *2.0*: The callback `messages/0` return value was updated to
          include the passive message for `{active, N}`.
 * *1.6*: The `socket()` type was added for documentation purposes.

+ 28 - 29
src/ranch.erl

@@ -38,7 +38,7 @@
 -export([procs/2]).
 -export([wait_for_connections/3]).
 -export([wait_for_connections/4]).
--export([filter_options/3]).
+-export([filter_options/4]).
 -export([set_option_default/3]).
 -export([require/1]).
 -export([log/4]).
@@ -46,7 +46,10 @@
 -type max_conns() :: non_neg_integer() | infinity.
 -export_type([max_conns/0]).
 
--type opts() :: any() | #{
+-type opts() :: any() | transport_opts(any()).
+-export_type([opts/0]).
+
+-type transport_opts(SocketOpts) :: #{
 	connection_type => worker | supervisor,
 	handshake_timeout => timeout(),
 	max_connections => max_conns(),
@@ -55,9 +58,9 @@
 	num_conns_sups => pos_integer(),
 	num_listen_sockets => pos_integer(),
 	shutdown => timeout() | brutal_kill,
-	socket_opts => any()
+	socket_opts => SocketOpts
 }.
--export_type([opts/0]).
+-export_type([transport_opts/1]).
 
 -type ref() :: any().
 -export_type([ref/0]).
@@ -76,7 +79,7 @@ start_listener(Ref, Transport, TransOpts0, Protocol, ProtoOpts)
 					Transport, TransOpts, Protocol, ProtoOpts)))
 	end.
 
--spec normalize_opts(opts()) -> opts().
+-spec normalize_opts(opts()) -> transport_opts(any()).
 normalize_opts(Map) when is_map(Map) ->
 	Map;
 normalize_opts(Any) ->
@@ -233,7 +236,7 @@ get_max_connections(Ref) ->
 set_max_connections(Ref, MaxConnections) ->
 	ranch_server:set_max_connections(Ref, MaxConnections).
 
--spec get_transport_options(ref()) -> any().
+-spec get_transport_options(ref()) -> transport_opts(any()).
 get_transport_options(Ref) ->
 	ranch_server:get_transport_options(Ref).
 
@@ -247,7 +250,7 @@ set_transport_options(Ref, TransOpts0) ->
 			{error, running}
 	end.
 
--spec get_protocol_options(ref()) -> opts().
+-spec get_protocol_options(ref()) -> any().
 get_protocol_options(Ref) ->
 	ranch_server:get_protocol_options(Ref).
 
@@ -360,38 +363,34 @@ wait_for_connections_loop(Ref, Op, NumConns, Interval) ->
 	end.
 
 -spec filter_options([inet | inet6 | {atom(), any()} | {raw, any(), any(), any()}],
-	[atom()], Acc) -> Acc when Acc :: [any()].
-filter_options(UserOptions, DisallowedKeys, DefaultOptions) ->
-	AllowedOptions = filter_user_options(UserOptions, DisallowedKeys),
+	[atom()], Acc, module()) -> Acc when Acc :: [any()].
+filter_options(UserOptions, DisallowedKeys, DefaultOptions, Logger) ->
+	AllowedOptions = filter_user_options(UserOptions, DisallowedKeys, Logger),
 	lists:foldl(fun merge_options/2, DefaultOptions, AllowedOptions).
 
 %% 2-tuple options.
-filter_user_options([Opt = {Key, _}|Tail], DisallowedKeys) ->
+filter_user_options([Opt = {Key, _}|Tail], DisallowedKeys, Logger) ->
 	case lists:member(Key, DisallowedKeys) of
 		false ->
-			[Opt|filter_user_options(Tail, DisallowedKeys)];
+			[Opt|filter_user_options(Tail, DisallowedKeys, Logger)];
 		true ->
-			filter_options_warning(Opt),
-			filter_user_options(Tail, DisallowedKeys)
+			filter_options_warning(Opt, Logger),
+			filter_user_options(Tail, DisallowedKeys, Logger)
 	end;
 %% Special option forms.
-filter_user_options([inet|Tail], DisallowedKeys) ->
-	[inet|filter_user_options(Tail, DisallowedKeys)];
-filter_user_options([inet6|Tail], DisallowedKeys) ->
-	[inet6|filter_user_options(Tail, DisallowedKeys)];
-filter_user_options([Opt = {raw, _, _, _}|Tail], DisallowedKeys) ->
-	[Opt|filter_user_options(Tail, DisallowedKeys)];
-filter_user_options([Opt|Tail], DisallowedKeys) ->
-	filter_options_warning(Opt),
-	filter_user_options(Tail, DisallowedKeys);
-filter_user_options([], _) ->
+filter_user_options([inet|Tail], DisallowedKeys, Logger) ->
+	[inet|filter_user_options(Tail, DisallowedKeys, Logger)];
+filter_user_options([inet6|Tail], DisallowedKeys, Logger) ->
+	[inet6|filter_user_options(Tail, DisallowedKeys, Logger)];
+filter_user_options([Opt = {raw, _, _, _}|Tail], DisallowedKeys, Logger) ->
+	[Opt|filter_user_options(Tail, DisallowedKeys, Logger)];
+filter_user_options([Opt|Tail], DisallowedKeys, Logger) ->
+	filter_options_warning(Opt, Logger),
+	filter_user_options(Tail, DisallowedKeys, Logger);
+filter_user_options([], _, _) ->
 	[].
 
-filter_options_warning(Opt) ->
-	Logger = case get(logger) of
-		undefined -> logger;
-		Logger0 -> Logger0
-	end,
+filter_options_warning(Opt, Logger) ->
 	log(warning,
 		"Transport option ~p unknown or invalid.~n",
 		[Opt], Logger).

+ 19 - 18
src/ranch_acceptors_sup.erl

@@ -27,14 +27,11 @@ init([Ref, NumAcceptors, Transport]) ->
 	TransOpts = ranch_server:get_transport_options(Ref),
 	Logger = maps:get(logger, TransOpts, logger),
 	NumListenSockets = maps:get(num_listen_sockets, TransOpts, 1),
-	SocketOpts = maps:get(socket_opts, TransOpts, []),
 	%% We temporarily put the logger in the process dictionary
 	%% so that it can be used from ranch:filter_options. The
 	%% interface as it currently is does not allow passing it
 	%% down otherwise.
-	put(logger, Logger),
-	LSockets = start_listen_sockets(Ref, NumListenSockets, Transport, SocketOpts, Logger),
-	erase(logger),
+	LSockets = start_listen_sockets(Ref, NumListenSockets, Transport, TransOpts, Logger),
 	Procs = [begin
 		LSocketId = (AcceptorId rem NumListenSockets) + 1,
 		{_, LSocket} = lists:keyfind(LSocketId, 1, LSockets),
@@ -46,46 +43,50 @@ init([Ref, NumAcceptors, Transport]) ->
 	end || AcceptorId <- lists:seq(1, NumAcceptors)],
 	{ok, {#{}, Procs}}.
 
--spec start_listen_sockets(any(), pos_integer(), module(), list(), module())
+-spec start_listen_sockets(any(), pos_integer(), module(), map(), module())
 	-> [{pos_integer(), inet:socket()}].
-start_listen_sockets(Ref, NumListenSockets, Transport, SocketOpts0, Logger) when NumListenSockets > 0 ->
-	BaseSocket = start_listen_socket(Ref, Transport, SocketOpts0, Logger),
+start_listen_sockets(Ref, NumListenSockets, Transport, TransOpts0, Logger) when NumListenSockets > 0 ->
+	BaseSocket = start_listen_socket(Ref, Transport, TransOpts0, Logger),
 	{ok, Addr} = Transport:sockname(BaseSocket),
 	ExtraSockets = case Addr of
 		{local, _} when NumListenSockets > 1 ->
-			listen_error(Ref, Transport, SocketOpts0, reuseport_local, Logger);
+			listen_error(Ref, Transport, TransOpts0, reuseport_local, Logger);
 		{local, _} ->
 			[];
 		{_, Port} ->
-			SocketOpts = case lists:keyfind(port, 1, SocketOpts0) of
+			SocketOpts = maps:get(socket_opts, TransOpts0, []),
+			SocketOpts1 = case lists:keyfind(port, 1, SocketOpts) of
 				{port, Port} ->
-					SocketOpts0;
+					SocketOpts;
 				_ ->
-					[{port, Port}|lists:keydelete(port, 1, SocketOpts0)]
+					[{port, Port}|lists:keydelete(port, 1, SocketOpts)]
 			end,
-			[{N, start_listen_socket(Ref, Transport, SocketOpts, Logger)}
+			TransOpts1 = TransOpts0#{socket_opts => SocketOpts1},
+			[{N, start_listen_socket(Ref, Transport, TransOpts1, Logger)}
 				|| N <- lists:seq(2, NumListenSockets)]
 	end,
 	ranch_server:set_addr(Ref, Addr),
 	[{1, BaseSocket}|ExtraSockets].
 
--spec start_listen_socket(any(), module(), list(), module()) -> inet:socket().
-start_listen_socket(Ref, Transport, SocketOpts, Logger) ->
-	case Transport:listen(SocketOpts) of
+-spec start_listen_socket(any(), module(), map(), module()) -> inet:socket().
+start_listen_socket(Ref, Transport, TransOpts, Logger) ->
+	case Transport:listen(TransOpts) of
 		{ok, Socket} ->
 			Socket;
 		{error, Reason} ->
-			listen_error(Ref, Transport, SocketOpts, Reason, Logger)
+			listen_error(Ref, Transport, TransOpts, Reason, Logger)
 	end.
 
 -spec listen_error(any(), module(), any(), atom(), module()) -> no_return().
-listen_error(Ref, Transport, SocketOpts0, Reason, Logger) ->
+listen_error(Ref, Transport, TransOpts0, Reason, Logger) ->
+	SocketOpts0 = maps:get(socket_opts, TransOpts0, []),
 	SocketOpts1 = [{cert, '...'}|proplists:delete(cert, SocketOpts0)],
 	SocketOpts2 = [{key, '...'}|proplists:delete(key, SocketOpts1)],
 	SocketOpts = [{cacerts, '...'}|proplists:delete(cacerts, SocketOpts2)],
+	TransOpts = TransOpts0#{socket_opts => SocketOpts},
 	ranch:log(error,
 		"Failed to start Ranch listener ~p in ~p:listen(~999999p) for reason ~p (~s)~n",
-		[Ref, Transport, SocketOpts, Reason, format_error(Reason)], Logger),
+		[Ref, Transport, TransOpts, Reason, format_error(Reason)], Logger),
 	exit({listen_error, Ref, Reason}).
 
 format_error(no_cert) ->

+ 16 - 14
src/ranch_ssl.erl

@@ -98,28 +98,30 @@ secure() ->
 
 messages() -> {ssl, ssl_closed, ssl_error, ssl_passive}.
 
--spec listen(opts()) -> {ok, ssl:sslsocket()} | {error, atom()}.
-listen(Opts) ->
-	case lists:keymember(cert, 1, Opts)
-			orelse lists:keymember(certfile, 1, Opts)
-			orelse lists:keymember(sni_fun, 1, Opts)
-			orelse lists:keymember(sni_hosts, 1, Opts) of
+-spec listen(ranch:transport_opts(opts())) -> {ok, ssl:sslsocket()} | {error, atom()}.
+listen(TransOpts) ->
+	SocketOpts = maps:get(socket_opts, TransOpts, []),
+	case lists:keymember(cert, 1, SocketOpts)
+			orelse lists:keymember(certfile, 1, SocketOpts)
+			orelse lists:keymember(sni_fun, 1, SocketOpts)
+			orelse lists:keymember(sni_hosts, 1, SocketOpts) of
 		true ->
-			do_listen(Opts);
+			Logger = maps:get(logger, TransOpts, logger),
+			do_listen(SocketOpts, Logger);
 		false ->
 			{error, no_cert}
 	end.
 
-do_listen(Opts0) ->
-	Opts1 = ranch:set_option_default(Opts0, backlog, 1024),
-	Opts2 = ranch:set_option_default(Opts1, nodelay, true),
-	Opts3 = ranch:set_option_default(Opts2, send_timeout, 30000),
-	Opts = ranch:set_option_default(Opts3, send_timeout_close, true),
+do_listen(SocketOpts0, Logger) ->
+	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),
+	SocketOpts = ranch:set_option_default(SocketOpts3, send_timeout_close, true),
 	%% 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.
-	ssl:listen(0, ranch:filter_options(Opts, disallowed_listen_options(),
-		[binary, {active, false}, {packet, raw}, {reuseaddr, true}])).
+	ssl:listen(0, ranch:filter_options(SocketOpts, disallowed_listen_options(),
+		[binary, {active, false}, {packet, raw}, {reuseaddr, true}], Logger)).
 
 %% 'binary' and 'list' are disallowed but they are handled
 %% specifically as they do not have 2-tuple equivalents.

+ 10 - 8
src/ranch_tcp.erl

@@ -78,17 +78,19 @@ secure() ->
 
 messages() -> {tcp, tcp_closed, tcp_error, tcp_passive}.
 
--spec listen(opts()) -> {ok, inet:socket()} | {error, atom()}.
-listen(Opts) ->
-	Opts2 = ranch:set_option_default(Opts, backlog, 1024),
-	Opts3 = ranch:set_option_default(Opts2, nodelay, true),
-	Opts4 = ranch:set_option_default(Opts3, send_timeout, 30000),
-	Opts5 = ranch:set_option_default(Opts4, send_timeout_close, true),
+-spec listen(ranch:transport_opts(opts())) -> {ok, inet:socket()} | {error, atom()}.
+listen(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),
 	%% 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.
-	gen_tcp:listen(0, ranch:filter_options(Opts5, disallowed_listen_options(),
-		[binary, {active, false}, {packet, raw}, {reuseaddr, true}])).
+	gen_tcp:listen(0, ranch:filter_options(SocketOpts4, disallowed_listen_options(),
+		[binary, {active, false}, {packet, raw}, {reuseaddr, true}], Logger)).
 
 %% 'binary' and 'list' are disallowed but they are handled
 %% specifically as they do not have 2-tuple equivalents.

+ 1 - 1
src/ranch_transport.erl

@@ -27,7 +27,7 @@
 -callback name() -> atom().
 -callback secure() -> boolean().
 -callback messages() -> {OK::atom(), Closed::atom(), Error::atom(), Passive::atom()}.
--callback listen(opts()) -> {ok, socket()} | {error, atom()}.
+-callback listen(ranch:transport_opts(any())) -> {ok, socket()} | {error, atom()}.
 -callback accept(socket(), timeout())
 	-> {ok, socket()} | {error, closed | timeout | atom()}.
 -callback handshake(socket(), opts(), timeout()) -> {ok, socket()} | {error, any()}.

+ 1 - 1
test/sendfile_SUITE.erl

@@ -270,7 +270,7 @@ do_ssl_chunk_size(Config) ->
 sockets(Config) ->
 	Transport = config(transport, Config),
 	TransportOpts = config(transport_opts, Config),
-	{ok, LSocket} = Transport:listen(TransportOpts),
+	{ok, LSocket} = Transport:listen(#{socket_opts => TransportOpts}),
 	{ok, {_, Port}} = Transport:sockname(LSocket),
 	Self = self(),
 	Fun = fun() ->