Browse Source

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 years ago
parent
commit
bac2faea84
3 changed files with 49 additions and 10 deletions
  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.