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

Fix inherit listen options for accepted socket

Order of options in listen is undocumented but significant. Now user option will
replace default value if user set it.
Slava Yurin 11 лет назад
Родитель
Сommit
bac2faea84
3 измененных файлов с 49 добавлено и 10 удалено
  1. 18 9
      src/ranch.erl
  2. 16 1
      test/acceptor_SUITE.erl
  3. 15 0
      test/check_tcp_options.erl

+ 18 - 9
src/ranch.erl

@@ -120,18 +120,27 @@ set_protocol_options(Ref, Opts) ->
 
 -spec filter_options([{atom(), any()} | {raw, any(), any(), any()}],
 	[atom()], Acc) -> Acc when Acc :: [any()].
-filter_options([], _, Acc) ->
-	Acc;
-filter_options([Opt = {Key, _}|Tail], AllowedKeys, Acc) ->
+filter_options(UserOptions, AllowedKeys, DefaultOptions) ->
+	AllowedOptions = filter_user_options(UserOptions, AllowedKeys),
+	lists:foldl(fun merge_options/2, DefaultOptions, AllowedOptions).
+
+filter_user_options([Opt = {Key, _}|Tail], AllowedKeys) ->
 	case lists:member(Key, AllowedKeys) of
-		true -> filter_options(Tail, AllowedKeys, [Opt|Acc]);
-		false -> filter_options(Tail, AllowedKeys, Acc)
+		true -> [Opt|filter_user_options(Tail, AllowedKeys)];
+		false -> filter_user_options(Tail, AllowedKeys)
 	end;
-filter_options([Opt = {raw, _, _, _}|Tail], AllowedKeys, Acc) ->
+filter_user_options([Opt = {raw, _, _, _}|Tail], AllowedKeys) ->
 	case lists:member(raw, AllowedKeys) of
-		true -> filter_options(Tail, AllowedKeys, [Opt|Acc]);
-		false -> filter_options(Tail, AllowedKeys, Acc)
-	end.
+		true -> [Opt|filter_user_options(Tail, AllowedKeys)];
+		false -> filter_user_options(Tail, AllowedKeys)
+	end;
+filter_user_options([], _) ->
+	[].
+
+merge_options({Key, _} = Option, OptionList) ->
+	lists:keystore(Key, 1, OptionList, Option);
+merge_options(Option, OptionList) ->
+	[Option|OptionList].
 
 -spec set_option_default(Opts, atom(), any())
 	-> Opts when Opts :: [{atom(), any()}].

+ 16 - 1
test/acceptor_SUITE.erl

@@ -37,6 +37,7 @@
 -export([tcp_accept_socket/1]).
 -export([tcp_active_echo/1]).
 -export([tcp_echo/1]).
+-export([tcp_inherit_options/1]).
 -export([tcp_max_connections/1]).
 -export([tcp_max_connections_and_beyond/1]).
 -export([tcp_set_max_connections/1]).
@@ -66,7 +67,8 @@ groups() ->
 		tcp_max_connections_and_beyond,
 		tcp_set_max_connections,
 		tcp_clean_set_max_connections,
-		tcp_upgrade
+		tcp_upgrade,
+		tcp_inherit_options
 	]}, {ssl, [
 		ssl_accept_error,
 		ssl_accept_socket,
@@ -370,6 +372,19 @@ tcp_upgrade(_) ->
 	receive upgraded -> ok after 1000 -> error(timeout) end,
 	ranch:stop_listener(Name).
 
+tcp_inherit_options(_) ->
+	Name = tcp_inherit_options,
+	TcpOptions = [{nodelay, false}, {send_timeout_close, false}],
+	{ok, _} = ranch:start_listener(Name, 4, ranch_tcp,
+			[{port, 0} | TcpOptions],
+			check_tcp_options, [{pid, self()} | TcpOptions]),
+	Port = ranch:get_port(Name),
+	{ok, Socket} = gen_tcp:connect("localhost", Port,
+			[binary, {active, true}, {packet, raw}]),
+	receive checked -> ok after 1000 -> error(timeout) end,
+	ok = gen_tcp:close(Socket),
+	ranch:stop_listener(Name).
+
 %% Supervisor tests
 
 supervisor_clean_restart(_) ->

+ 15 - 0
test/check_tcp_options.erl

@@ -0,0 +1,15 @@
+-module(check_tcp_options).
+-behaviour(ranch_protocol).
+
+-export([start_link/4]).
+-export([init/3]).
+
+start_link(_, Socket, _, [{pid, TestPid}|TcpOptions]) ->
+	{ok, RealTcpOptions} =
+		inet:getopts(Socket, [Key || {Key, _} <- TcpOptions]),
+	Pid = spawn_link(?MODULE, init, [TestPid, RealTcpOptions, TcpOptions]),
+	{ok, Pid}.
+
+init(Pid, TcpOptions, TcpOptions) ->
+	Pid ! checked,
+	receive after 2500 -> ok end.