Browse Source

Added transport functions getopts/2, getstat/1 and getstat/2

Jan Uhlig 7 years ago
parent
commit
b6f5b70ddb

+ 23 - 0
doc/src/manual/ranch_transport.asciidoc

@@ -160,6 +160,29 @@ Change options for the given socket.
 This is mainly useful for switching to active or passive mode
 This is mainly useful for switching to active or passive mode
 or to set protocol-specific options.
 or to set protocol-specific options.
 
 
+=== getopts(CSocket, SockOpts) -> {ok, SockOptValues} | {error, atom()}
+
+CSocket = any():: Socket for this connection.
+SockOpts = [atom]:: Socket option names.
+SockOptValues = list():: Socket options.
+
+Get options for the given socket.
+
+=== getstat(CSocket) -> {ok, SockStatValues} | {error, atom()}
+
+CSocket = any():: Socket for this connection.
+SockStatValues = list():: Socket statistics.
+
+Get statistics for the given socket.
+
+=== getstat(CSocket, SockStats) -> {ok, SockStatValues} | {error, atom()}
+
+CSocket = any():: Socket for this connection.
+SockStats = [atom()]:: Socket statistic names.
+SockStatValues = list():: Socket statistics.
+
+Get statistics for the given socket.
+
 === shutdown(CSocket, How) -> ok | {error, atom()}
 === shutdown(CSocket, How) -> ok | {error, atom()}
 
 
 CSocket = any():: Socket for this connection.
 CSocket = any():: Socket for this connection.

+ 15 - 0
src/ranch_ssl.erl

@@ -30,6 +30,9 @@
 -export([sendfile/4]).
 -export([sendfile/4]).
 -export([sendfile/5]).
 -export([sendfile/5]).
 -export([setopts/2]).
 -export([setopts/2]).
+-export([getopts/2]).
+-export([getstat/1]).
+-export([getstat/2]).
 -export([controlling_process/2]).
 -export([controlling_process/2]).
 -export([peername/1]).
 -export([peername/1]).
 -export([sockname/1]).
 -export([sockname/1]).
@@ -192,6 +195,18 @@ sendfile(Socket, File, Offset, Bytes, Opts) ->
 setopts(Socket, Opts) ->
 setopts(Socket, Opts) ->
 	ssl:setopts(Socket, Opts).
 	ssl:setopts(Socket, Opts).
 
 
+-spec getopts(ssl:sslsocket(), [atom()]) -> {ok, list()} | {error, atom()}.
+getopts(Socket, Opts) ->
+        ssl:getopts(Socket, Opts).
+
+-spec getstat(ssl:sslsocket()) -> {ok, list()} | {error, atom()}.
+getstat(Socket) ->
+        ssl:getstat(Socket).
+
+-spec getstat(ssl:sslsocket(), [atom()]) -> {ok, list()} | {error, atom()}.
+getstat(Socket, OptionNames) ->
+        ssl:getstat(Socket, OptionNames).
+
 -spec controlling_process(ssl:sslsocket(), pid())
 -spec controlling_process(ssl:sslsocket(), pid())
 	-> ok | {error, closed | not_owner | atom()}.
 	-> ok | {error, closed | not_owner | atom()}.
 controlling_process(Socket, Pid) ->
 controlling_process(Socket, Pid) ->

+ 15 - 0
src/ranch_tcp.erl

@@ -30,6 +30,9 @@
 -export([sendfile/4]).
 -export([sendfile/4]).
 -export([sendfile/5]).
 -export([sendfile/5]).
 -export([setopts/2]).
 -export([setopts/2]).
+-export([getopts/2]).
+-export([getstat/1]).
+-export([getstat/2]).
 -export([controlling_process/2]).
 -export([controlling_process/2]).
 -export([peername/1]).
 -export([peername/1]).
 -export([sockname/1]).
 -export([sockname/1]).
@@ -174,6 +177,18 @@ sendfile(Socket, RawFile, Offset, Bytes, Opts) ->
 setopts(Socket, Opts) ->
 setopts(Socket, Opts) ->
 	inet:setopts(Socket, Opts).
 	inet:setopts(Socket, Opts).
 
 
+-spec getopts(inet:socket(), [atom()]) -> {ok, list()} | {error, atom()}.
+getopts(Socket, Opts) ->
+        inet:getopts(Socket, Opts).
+
+-spec getstat(inet:socket()) -> {ok, list()} | {error, atom()}.
+getstat(Socket) ->
+        inet:getstat(Socket).
+
+-spec getstat(inet:socket(), [atom()]) -> {ok, list()} | {error, atom()}.
+getstat(Socket, OptionNames) ->
+        inet:getstat(Socket, OptionNames).
+
 -spec controlling_process(inet:socket(), pid())
 -spec controlling_process(inet:socket(), pid())
 	-> ok | {error, closed | not_owner | atom()}.
 	-> ok | {error, closed | not_owner | atom()}.
 controlling_process(Socket, Pid) ->
 controlling_process(Socket, Pid) ->

+ 4 - 0
src/ranch_transport.erl

@@ -18,6 +18,7 @@
 
 
 -type socket() :: any().
 -type socket() :: any().
 -type opts() :: any().
 -type opts() :: any().
+-type stats() :: any().
 -type sendfile_opts() :: [{chunk_size, non_neg_integer()}].
 -type sendfile_opts() :: [{chunk_size, non_neg_integer()}].
 -export_type([sendfile_opts/0]).
 -export_type([sendfile_opts/0]).
 
 
@@ -43,6 +44,9 @@
 		non_neg_integer(), sendfile_opts())
 		non_neg_integer(), sendfile_opts())
 	-> {ok, non_neg_integer()} | {error, atom()}.
 	-> {ok, non_neg_integer()} | {error, atom()}.
 -callback setopts(socket(), opts()) -> ok | {error, atom()}.
 -callback setopts(socket(), opts()) -> ok | {error, atom()}.
+-callback getopts(socket(), [atom()]) -> {ok, opts()} | {error, atom()}.
+-callback getstat(socket()) -> {ok, stats()} | {error, atom()}.
+-callback getstat(socket(), [atom()]) -> {ok, stats()} | {error, atom()}.
 -callback controlling_process(socket(), pid())
 -callback controlling_process(socket(), pid())
 	-> ok | {error, closed | not_owner | atom()}.
 	-> ok | {error, closed | not_owner | atom()}.
 -callback peername(socket())
 -callback peername(socket())

+ 70 - 0
test/acceptor_SUITE.erl

@@ -35,6 +35,8 @@ groups() ->
 		tcp_remove_connections,
 		tcp_remove_connections,
 		tcp_set_max_connections,
 		tcp_set_max_connections,
 		tcp_set_max_connections_clean,
 		tcp_set_max_connections_clean,
+		tcp_getopts_capability,
+		tcp_getstat_capability,
 		tcp_upgrade,
 		tcp_upgrade,
 		tcp_error_eaddrinuse,
 		tcp_error_eaddrinuse,
 		tcp_error_eacces
 		tcp_error_eacces
@@ -45,6 +47,8 @@ groups() ->
 		ssl_echo,
 		ssl_echo,
 		ssl_sni_echo,
 		ssl_sni_echo,
 		ssl_sni_fail,
 		ssl_sni_fail,
+		ssl_getopts_capability,
+		ssl_getstat_capability,
 		ssl_error_eaddrinuse,
 		ssl_error_eaddrinuse,
 		ssl_error_no_cert,
 		ssl_error_no_cert,
 		ssl_error_eacces
 		ssl_error_eacces
@@ -263,6 +267,44 @@ do_ssl_sni_fail() ->
 	{'EXIT', _} = begin catch ranch:get_port(Name) end,
 	{'EXIT', _} = begin catch ranch:get_port(Name) end,
 	ok.
 	ok.
 
 
+ssl_getopts_capability(_) ->
+	doc("Ensure getopts/2 capability."),
+	Name=name(),
+	Opts=ct_helper:get_certs_from_ets(),
+	{ok, _}=ranch:start_listener(Name, ranch_ssl, Opts, transport_capabilities_protocol, []),
+	Port=ranch:get_port(Name),
+	{ok, Socket}=ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
+	ok=ssl:send(Socket, <<"getopts/2">>),
+	{ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
+	ok=ranch:stop_listener(Name),
+	{error, closed}=ssl:recv(Socket, 0, 1000),
+	{'EXIT', _}=begin catch ranch:get_port(Name) end,
+	ok.
+
+ssl_getstat_capability(_) ->
+	case application:get_key(ssl, vsn) of
+		{ok, Vsn} when Vsn>="8.0" ->
+			do_ssl_getstat_capability();
+		_ ->
+			{skip, "No getstat/{1,2} support."}
+	end.
+
+do_ssl_getstat_capability() ->
+	doc("Ensure getstat/{1,2} capability."),
+	Name=name(),
+	Opts=ct_helper:get_certs_from_ets(),
+	{ok, _}=ranch:start_listener(Name, ranch_ssl, Opts, transport_capabilities_protocol, []),
+	Port=ranch:get_port(Name),
+	{ok, Socket}=ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
+	ok=ssl:send(Socket, <<"getstat/1">>),
+	{ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
+	ok=ssl:send(Socket, <<"getstat/2">>),
+	{ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
+	ok=ranch:stop_listener(Name),
+	{error, closed}=ssl:recv(Socket, 0, 1000),
+	{'EXIT', _}=begin catch ranch:get_port(Name) end,
+	ok.
+
 ssl_error_eaddrinuse(_) ->
 ssl_error_eaddrinuse(_) ->
 	doc("Ensure that failure due to an eaddrinuse returns a compact readable error."),
 	doc("Ensure that failure due to an eaddrinuse returns a compact readable error."),
 	Name = name(),
 	Name = name(),
@@ -471,6 +513,34 @@ do_tcp_set_max_connections_clean(_) ->
 	ok = clean_traces(),
 	ok = clean_traces(),
 	ok = ranch:stop_listener(Name).
 	ok = ranch:stop_listener(Name).
 
 
+tcp_getopts_capability(_) ->
+	doc("Ensure getopts/2 capability."),
+	Name=name(),
+	{ok, _}=ranch:start_listener(Name, ranch_tcp, [], transport_capabilities_protocol, []),
+	Port=ranch:get_port(Name),
+	{ok, Socket}=gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
+	ok=gen_tcp:send(Socket, <<"getopts/2">>),
+	{ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
+	ok=ranch:stop_listener(Name),
+	{error, closed}=gen_tcp:recv(Socket, 0, 1000),
+	{'EXIT', _}=begin catch ranch:get_port(Name) end,
+	ok.
+
+tcp_getstat_capability(_) ->
+	doc("Ensure getstat/{1,2} capability."),
+	Name=name(),
+	{ok, _}=ranch:start_listener(Name, ranch_tcp, [], transport_capabilities_protocol, []),
+	Port=ranch:get_port(Name),
+	{ok, Socket}=gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
+	ok=gen_tcp:send(Socket, <<"getstat/1">>),
+	{ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
+	ok=gen_tcp:send(Socket, <<"getstat/2">>),
+	{ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
+	ok=ranch:stop_listener(Name),
+	{error, closed}=gen_tcp:recv(Socket, 0, 1000),
+	{'EXIT', _}=begin catch ranch:get_port(Name) end,
+	ok.
+
 tcp_upgrade(_) ->
 tcp_upgrade(_) ->
 	doc("Ensure that protocol options can be updated."),
 	doc("Ensure that protocol options can be updated."),
 	Name = name(),
 	Name = name(),

+ 53 - 0
test/transport_capabilities_protocol.erl

@@ -0,0 +1,53 @@
+-module(transport_capabilities_protocol).
+-behaviour(ranch_protocol).
+
+-export([start_link/4]).
+-export([init/4]).
+
+start_link(Ref, Socket, Transport, Opts) ->
+	Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]),
+	{ok, Pid}.
+
+init(Ref, Socket, Transport, _Opts = []) ->
+	ok = ranch:accept_ack(Ref),
+	loop(Socket, Transport).
+
+loop(Socket, Transport) ->
+	case Transport:recv(Socket, 0, 5000) of
+		{ok, Data} ->
+			Reply =
+			case check(Socket, Transport, Data) of
+				ok ->
+					<<"OK">>;
+				error ->
+					<<"ERROR">>
+			end,
+			Transport:send(Socket, Reply),
+			loop(Socket, Transport);
+		_ ->
+			ok = Transport:close(Socket)
+	end.
+
+check(Socket, Transport, <<"getopts/2">>) ->
+	case catch Transport:getopts(Socket, []) of
+		{ok, _} ->
+			ok;
+		_ ->
+			error
+	end;
+
+check(Socket, Transport, <<"getstat/1">>) ->
+	case catch Transport:getstat(Socket) of
+		{ok, _} ->
+			ok;
+		_ ->
+			error
+	end;
+
+check(Socket, Transport, <<"getstat/2">>) ->
+	case catch Transport:getstat(Socket, []) of
+		{ok, _} ->
+			ok;
+		_ ->
+			error
+	end.