From fa608621bfedbb981657d2d09e2b321dddc0ad8e Mon Sep 17 00:00:00 2001 From: "j.uhlig" Date: Tue, 13 Mar 2018 09:31:20 +0100 Subject: Fix ranch:info/0 and ranch:procs/2 in embedded mode --- src/ranch.erl | 26 +++---------------- src/ranch_listener_sup.erl | 4 ++- src/ranch_server.erl | 64 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 59 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/ranch.erl b/src/ranch.erl index 52c5679..d4adee5 100644 --- a/src/ranch.erl +++ b/src/ranch.erl @@ -164,12 +164,11 @@ set_protocol_options(Ref, Opts) -> -spec info() -> [{any(), [{atom(), any()}]}]. info() -> - Children = supervisor:which_children(ranch_sup), [{Ref, listener_info(Ref, Pid)} - || {{ranch_listener_sup, Ref}, Pid, _, [_]} <- Children]. + || {Ref, Pid} <- ranch_server:get_listener_sups()]. listener_info(Ref, Pid) -> - [_, NumAcceptors, Transport, TransOpts, Protocol, _] = listener_start_args(Ref), + [_, NumAcceptors, Transport, TransOpts, Protocol, _] = ranch_server:get_listener_start_args(Ref), ConnsSup = ranch_server:get_connections_sup(Ref), {IP, Port} = get_addr(Ref), MaxConns = get_max_connections(Ref), @@ -188,24 +187,6 @@ listener_info(Ref, Pid) -> {protocol_options, ProtoOpts} ]. -listener_start_args(Ref) -> - case erlang:function_exported(supervisor, get_childspec, 2) of - true -> - %% Can't use map syntax before R18. - {ok, Map} = supervisor:get_childspec(ranch_sup, {ranch_listener_sup, Ref}), - {ranch_listener_sup, start_link, StartArgs} = maps:get(start, Map), - StartArgs; - false -> - %% Awful solution for compatibility with R16 and R17. - {status, _, _, [_, _, _, _, [_, _, - {data, [{_, {state, _, _, Children, _, _, _, _, _, _}}]}]]} - = sys:get_status(ranch_sup), - [StartArgs] = [StartArgs || {child, _, {ranch_listener_sup, ChildRef}, - {ranch_listener_sup, start_link, StartArgs}, _, _, _, _} - <- Children, ChildRef =:= Ref], - StartArgs - end. - -spec procs(ref(), acceptors | connections) -> [pid()]. procs(Ref, acceptors) -> procs1(Ref, ranch_acceptors_sup); @@ -213,8 +194,7 @@ procs(Ref, connections) -> procs1(Ref, ranch_conns_sup). procs1(Ref, Sup) -> - {_, ListenerSup, _, _} = lists:keyfind({ranch_listener_sup, Ref}, 1, - supervisor:which_children(ranch_sup)), + ListenerSup = ranch_server:get_listener_sup(Ref), {_, SupPid, _, _} = lists:keyfind(Sup, 1, supervisor:which_children(ListenerSup)), [Pid || {_, Pid, _, _} <- supervisor:which_children(SupPid)]. diff --git a/src/ranch_listener_sup.erl b/src/ranch_listener_sup.erl index f2ca6a1..584dc36 100644 --- a/src/ranch_listener_sup.erl +++ b/src/ranch_listener_sup.erl @@ -22,12 +22,14 @@ -> {ok, pid()}. start_link(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts) -> MaxConns = proplists:get_value(max_connections, TransOpts, 1024), - ranch_server:set_new_listener_opts(Ref, MaxConns, ProtoOpts), + ranch_server:set_new_listener_opts(Ref, MaxConns, ProtoOpts, + [Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts]), supervisor:start_link(?MODULE, { Ref, NumAcceptors, Transport, TransOpts, Protocol }). init({Ref, NumAcceptors, Transport, TransOpts, Protocol}) -> + ok = ranch_server:set_listener_sup(Ref, self()), AckTimeout = proplists:get_value(ack_timeout, TransOpts, 5000), ConnType = proplists:get_value(connection_type, TransOpts, worker), Shutdown = proplists:get_value(shutdown, TransOpts, 5000), diff --git a/src/ranch_server.erl b/src/ranch_server.erl index 8a17084..64f1f98 100644 --- a/src/ranch_server.erl +++ b/src/ranch_server.erl @@ -17,16 +17,21 @@ %% API. -export([start_link/0]). --export([set_new_listener_opts/3]). +-export([set_new_listener_opts/4]). -export([cleanup_listener_opts/1]). -export([set_connections_sup/2]). -export([get_connections_sup/1]). +-export([get_connections_sups/0]). +-export([set_listener_sup/2]). +-export([get_listener_sup/1]). +-export([get_listener_sups/0]). -export([set_addr/2]). -export([get_addr/1]). -export([set_max_connections/2]). -export([get_max_connections/1]). -export([set_protocol_options/2]). -export([get_protocol_options/1]). +-export([get_listener_start_args/1]). -export([count_connections/1]). %% gen_server. @@ -50,15 +55,16 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). --spec set_new_listener_opts(ranch:ref(), ranch:max_conns(), any()) -> ok. -set_new_listener_opts(Ref, MaxConns, Opts) -> - gen_server:call(?MODULE, {set_new_listener_opts, Ref, MaxConns, Opts}). +-spec set_new_listener_opts(ranch:ref(), ranch:max_conns(), any(), [any()]) -> ok. +set_new_listener_opts(Ref, MaxConns, ProtoOpts, StartArgs) -> + gen_server:call(?MODULE, {set_new_listener_opts, Ref, MaxConns, ProtoOpts, StartArgs}). -spec cleanup_listener_opts(ranch:ref()) -> ok. cleanup_listener_opts(Ref) -> _ = ets:delete(?TAB, {addr, Ref}), _ = ets:delete(?TAB, {max_conns, Ref}), _ = ets:delete(?TAB, {opts, Ref}), + _ = ets:delete(?TAB, {listener_start_args, Ref}), %% We also remove the pid of the connections supervisor. %% Depending on the timing, it might already have been deleted %% when we handled the monitor DOWN message. However, in some @@ -67,6 +73,8 @@ cleanup_listener_opts(Ref) -> %% expected a crash (because the listener was stopped). %% Deleting it explictly here removes any possible confusion. _ = ets:delete(?TAB, {conns_sup, Ref}), + %% Ditto for the listener supervisor. + _ = ets:delete(?TAB, {listener_sup, Ref}), ok. -spec set_connections_sup(ranch:ref(), pid()) -> ok. @@ -78,6 +86,23 @@ set_connections_sup(Ref, Pid) -> get_connections_sup(Ref) -> ets:lookup_element(?TAB, {conns_sup, Ref}, 2). +-spec get_connections_sups() -> [{ranch:ref(), pid()}]. +get_connections_sups() -> + [{Ref, Pid} || [Ref, Pid] <- ets:match(?TAB, {{conns_sup, '$1'}, '$2'})]. + +-spec set_listener_sup(ranch:ref(), pid()) -> ok. +set_listener_sup(Ref, Pid) -> + true = gen_server:call(?MODULE, {set_listener_sup, Ref, Pid}), + ok. + +-spec get_listener_sup(ranch:ref()) -> pid(). +get_listener_sup(Ref) -> + ets:lookup_element(?TAB, {listener_sup, Ref}, 2). + +-spec get_listener_sups() -> [{ranch:ref(), pid()}]. +get_listener_sups() -> + [{Ref, Pid} || [Ref, Pid] <- ets:match(?TAB, {{listener_sup, '$1'}, '$2'})]. + -spec set_addr(ranch:ref(), {inet:ip_address(), inet:port_number()}) -> ok. set_addr(Ref, Addr) -> gen_server:call(?MODULE, {set_addr, Ref, Addr}). @@ -102,6 +127,10 @@ set_protocol_options(Ref, ProtoOpts) -> get_protocol_options(Ref) -> ets:lookup_element(?TAB, {opts, Ref}, 2). +-spec get_listener_start_args(ranch:ref()) -> [any()]. +get_listener_start_args(Ref) -> + ets:lookup_element(?TAB, {listener_start_args, Ref}, 2). + -spec count_connections(ranch:ref()) -> non_neg_integer(). count_connections(Ref) -> ranch_conns_sup:active_connections(get_connections_sup(Ref)). @@ -109,13 +138,16 @@ count_connections(Ref) -> %% gen_server. init([]) -> - Monitors = [{{erlang:monitor(process, Pid), Pid}, Ref} || + ConnMonitors = [{{erlang:monitor(process, Pid), Pid}, {conns_sup, Ref}} || [Ref, Pid] <- ets:match(?TAB, {{conns_sup, '$1'}, '$2'})], - {ok, #state{monitors=Monitors}}. + ListenerMonitors = [{{erlang:monitor(process, Pid), Pid}, {listener_sup, Ref}} || + [Ref, Pid] <- ets:match(?TAB, {{listener_sup, '$1'}, '$2'})], + {ok, #state{monitors=ConnMonitors++ListenerMonitors}}. -handle_call({set_new_listener_opts, Ref, MaxConns, Opts}, _, State) -> +handle_call({set_new_listener_opts, Ref, MaxConns, ProtoOpts, StartArgs}, _, State) -> ets:insert(?TAB, {{max_conns, Ref}, MaxConns}), - ets:insert(?TAB, {{opts, Ref}, Opts}), + ets:insert(?TAB, {{opts, Ref}, ProtoOpts}), + ets:insert(?TAB, {{listener_start_args, Ref}, StartArgs}), {reply, ok, State}; handle_call({set_connections_sup, Ref, Pid}, _, State=#state{monitors=Monitors}) -> @@ -123,7 +155,17 @@ handle_call({set_connections_sup, Ref, Pid}, _, true -> MonitorRef = erlang:monitor(process, Pid), {reply, true, - State#state{monitors=[{{MonitorRef, Pid}, Ref}|Monitors]}}; + State#state{monitors=[{{MonitorRef, Pid}, {conns_sup, Ref}}|Monitors]}}; + false -> + {reply, false, State} + end; +handle_call({set_listener_sup, Ref, Pid}, _, + State=#state{monitors=Monitors}) -> + case ets:insert_new(?TAB, {{listener_sup, Ref}, Pid}) of + true -> + MonitorRef = erlang:monitor(process, Pid), + {reply, true, + State#state{monitors=[{{MonitorRef, Pid}, {listener_sup, Ref}}|Monitors]}}; false -> {reply, false, State} end; @@ -148,8 +190,8 @@ handle_cast(_Request, State) -> handle_info({'DOWN', MonitorRef, process, Pid, _}, State=#state{monitors=Monitors}) -> - {_, Ref} = lists:keyfind({MonitorRef, Pid}, 1, Monitors), - _ = ets:delete(?TAB, {conns_sup, Ref}), + {_, TypeRef} = lists:keyfind({MonitorRef, Pid}, 1, Monitors), + _ = ets:delete(?TAB, TypeRef), Monitors2 = lists:keydelete({MonitorRef, Pid}, 1, Monitors), {noreply, State#state{monitors=Monitors2}}; handle_info(_Info, State) -> -- cgit v1.2.3