ranch_server.erl 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. %% Copyright (c) 2012-2018, Loïc Hoguin <essen@ninenines.eu>
  2. %%
  3. %% Permission to use, copy, modify, and/or distribute this software for any
  4. %% purpose with or without fee is hereby granted, provided that the above
  5. %% copyright notice and this permission notice appear in all copies.
  6. %%
  7. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. -module(ranch_server).
  15. -behaviour(gen_server).
  16. %% API.
  17. -export([start_link/0]).
  18. -export([set_new_listener_opts/5]).
  19. -export([cleanup_listener_opts/1]).
  20. -export([set_connections_sup/2]).
  21. -export([get_connections_sup/1]).
  22. -export([get_connections_sups/0]).
  23. -export([set_listener_sup/2]).
  24. -export([get_listener_sup/1]).
  25. -export([get_listener_sups/0]).
  26. -export([set_addr/2]).
  27. -export([get_addr/1]).
  28. -export([set_max_connections/2]).
  29. -export([get_max_connections/1]).
  30. -export([set_transport_options/2]).
  31. -export([get_transport_options/1]).
  32. -export([set_protocol_options/2]).
  33. -export([get_protocol_options/1]).
  34. -export([get_listener_start_args/1]).
  35. -export([count_connections/1]).
  36. %% gen_server.
  37. -export([init/1]).
  38. -export([handle_call/3]).
  39. -export([handle_cast/2]).
  40. -export([handle_info/2]).
  41. -export([terminate/2]).
  42. -export([code_change/3]).
  43. -define(TAB, ?MODULE).
  44. -type monitors() :: [{{reference(), pid()}, any()}].
  45. -record(state, {
  46. monitors = [] :: monitors()
  47. }).
  48. %% API.
  49. -spec start_link() -> {ok, pid()}.
  50. start_link() ->
  51. gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
  52. -spec set_new_listener_opts(ranch:ref(), ranch:max_conns(), any(), any(), [any()]) -> ok.
  53. set_new_listener_opts(Ref, MaxConns, TransOpts, ProtoOpts, StartArgs) ->
  54. gen_server:call(?MODULE, {set_new_listener_opts, Ref, MaxConns, TransOpts, ProtoOpts, StartArgs}).
  55. -spec cleanup_listener_opts(ranch:ref()) -> ok.
  56. cleanup_listener_opts(Ref) ->
  57. _ = ets:delete(?TAB, {addr, Ref}),
  58. _ = ets:delete(?TAB, {max_conns, Ref}),
  59. _ = ets:delete(?TAB, {trans_opts, Ref}),
  60. _ = ets:delete(?TAB, {proto_opts, Ref}),
  61. _ = ets:delete(?TAB, {listener_start_args, Ref}),
  62. %% We also remove the pid of the connections supervisor.
  63. %% Depending on the timing, it might already have been deleted
  64. %% when we handled the monitor DOWN message. However, in some
  65. %% cases when calling stop_listener followed by get_connections_sup,
  66. %% we could end up with the pid still being returned, when we
  67. %% expected a crash (because the listener was stopped).
  68. %% Deleting it explictly here removes any possible confusion.
  69. _ = ets:delete(?TAB, {conns_sup, Ref}),
  70. %% Ditto for the listener supervisor.
  71. _ = ets:delete(?TAB, {listener_sup, Ref}),
  72. ok.
  73. -spec set_connections_sup(ranch:ref(), pid()) -> ok.
  74. set_connections_sup(Ref, Pid) ->
  75. true = gen_server:call(?MODULE, {set_connections_sup, Ref, Pid}),
  76. ok.
  77. -spec get_connections_sup(ranch:ref()) -> pid().
  78. get_connections_sup(Ref) ->
  79. ets:lookup_element(?TAB, {conns_sup, Ref}, 2).
  80. -spec get_connections_sups() -> [{ranch:ref(), pid()}].
  81. get_connections_sups() ->
  82. [{Ref, Pid} || [Ref, Pid] <- ets:match(?TAB, {{conns_sup, '$1'}, '$2'})].
  83. -spec set_listener_sup(ranch:ref(), pid()) -> ok.
  84. set_listener_sup(Ref, Pid) ->
  85. true = gen_server:call(?MODULE, {set_listener_sup, Ref, Pid}),
  86. ok.
  87. -spec get_listener_sup(ranch:ref()) -> pid().
  88. get_listener_sup(Ref) ->
  89. ets:lookup_element(?TAB, {listener_sup, Ref}, 2).
  90. -spec get_listener_sups() -> [{ranch:ref(), pid()}].
  91. get_listener_sups() ->
  92. [{Ref, Pid} || [Ref, Pid] <- ets:match(?TAB, {{listener_sup, '$1'}, '$2'})].
  93. -spec set_addr(ranch:ref(), {inet:ip_address(), inet:port_number()} | {undefined, undefined}) -> ok.
  94. set_addr(Ref, Addr) ->
  95. gen_server:call(?MODULE, {set_addr, Ref, Addr}).
  96. -spec get_addr(ranch:ref()) -> {inet:ip_address(), inet:port_number()} | {undefined, undefined}.
  97. get_addr(Ref) ->
  98. ets:lookup_element(?TAB, {addr, Ref}, 2).
  99. -spec set_max_connections(ranch:ref(), ranch:max_conns()) -> ok.
  100. set_max_connections(Ref, MaxConnections) ->
  101. gen_server:call(?MODULE, {set_max_conns, Ref, MaxConnections}).
  102. -spec get_max_connections(ranch:ref()) -> ranch:max_conns().
  103. get_max_connections(Ref) ->
  104. ets:lookup_element(?TAB, {max_conns, Ref}, 2).
  105. -spec set_transport_options(ranch:ref(), any()) -> ok.
  106. set_transport_options(Ref, TransOpts) ->
  107. gen_server:call(?MODULE, {set_trans_opts, Ref, TransOpts}).
  108. -spec get_transport_options(ranch:ref()) -> any().
  109. get_transport_options(Ref) ->
  110. ets:lookup_element(?TAB, {trans_opts, Ref}, 2).
  111. -spec set_protocol_options(ranch:ref(), any()) -> ok.
  112. set_protocol_options(Ref, ProtoOpts) ->
  113. gen_server:call(?MODULE, {set_proto_opts, Ref, ProtoOpts}).
  114. -spec get_protocol_options(ranch:ref()) -> any().
  115. get_protocol_options(Ref) ->
  116. ets:lookup_element(?TAB, {proto_opts, Ref}, 2).
  117. -spec get_listener_start_args(ranch:ref()) -> [any()].
  118. get_listener_start_args(Ref) ->
  119. ets:lookup_element(?TAB, {listener_start_args, Ref}, 2).
  120. -spec count_connections(ranch:ref()) -> non_neg_integer().
  121. count_connections(Ref) ->
  122. ranch_conns_sup:active_connections(get_connections_sup(Ref)).
  123. %% gen_server.
  124. init([]) ->
  125. ConnMonitors = [{{erlang:monitor(process, Pid), Pid}, {conns_sup, Ref}} ||
  126. [Ref, Pid] <- ets:match(?TAB, {{conns_sup, '$1'}, '$2'})],
  127. ListenerMonitors = [{{erlang:monitor(process, Pid), Pid}, {listener_sup, Ref}} ||
  128. [Ref, Pid] <- ets:match(?TAB, {{listener_sup, '$1'}, '$2'})],
  129. {ok, #state{monitors=ConnMonitors++ListenerMonitors}}.
  130. handle_call({set_new_listener_opts, Ref, MaxConns, TransOpts, ProtoOpts, StartArgs}, _, State) ->
  131. ets:insert_new(?TAB, {{max_conns, Ref}, MaxConns}),
  132. ets:insert_new(?TAB, {{trans_opts, Ref}, TransOpts}),
  133. ets:insert_new(?TAB, {{proto_opts, Ref}, ProtoOpts}),
  134. ets:insert_new(?TAB, {{listener_start_args, Ref}, StartArgs}),
  135. {reply, ok, State};
  136. handle_call({set_connections_sup, Ref, Pid}, _,
  137. State=#state{monitors=Monitors}) ->
  138. case ets:insert_new(?TAB, {{conns_sup, Ref}, Pid}) of
  139. true ->
  140. MonitorRef = erlang:monitor(process, Pid),
  141. {reply, true,
  142. State#state{monitors=[{{MonitorRef, Pid}, {conns_sup, Ref}}|Monitors]}};
  143. false ->
  144. {reply, false, State}
  145. end;
  146. handle_call({set_listener_sup, Ref, Pid}, _,
  147. State=#state{monitors=Monitors}) ->
  148. case ets:insert_new(?TAB, {{listener_sup, Ref}, Pid}) of
  149. true ->
  150. MonitorRef = erlang:monitor(process, Pid),
  151. {reply, true,
  152. State#state{monitors=[{{MonitorRef, Pid}, {listener_sup, Ref}}|Monitors]}};
  153. false ->
  154. {reply, false, State}
  155. end;
  156. handle_call({set_addr, Ref, Addr}, _, State) ->
  157. true = ets:insert(?TAB, {{addr, Ref}, Addr}),
  158. {reply, ok, State};
  159. handle_call({set_max_conns, Ref, MaxConns}, _, State) ->
  160. ets:insert(?TAB, {{max_conns, Ref}, MaxConns}),
  161. ConnsSup = get_connections_sup(Ref),
  162. ConnsSup ! {set_max_conns, MaxConns},
  163. {reply, ok, State};
  164. handle_call({set_trans_opts, Ref, Opts}, _, State) ->
  165. ets:insert(?TAB, {{trans_opts, Ref}, Opts}),
  166. {reply, ok, State};
  167. handle_call({set_proto_opts, Ref, Opts}, _, State) ->
  168. ets:insert(?TAB, {{proto_opts, Ref}, Opts}),
  169. ConnsSup = get_connections_sup(Ref),
  170. ConnsSup ! {set_opts, Opts},
  171. {reply, ok, State};
  172. handle_call(_Request, _From, State) ->
  173. {reply, ignore, State}.
  174. handle_cast(_Request, State) ->
  175. {noreply, State}.
  176. handle_info({'DOWN', MonitorRef, process, Pid, _},
  177. State=#state{monitors=Monitors}) ->
  178. {_, TypeRef} = lists:keyfind({MonitorRef, Pid}, 1, Monitors),
  179. _ = ets:delete(?TAB, TypeRef),
  180. Monitors2 = lists:keydelete({MonitorRef, Pid}, 1, Monitors),
  181. {noreply, State#state{monitors=Monitors2}};
  182. handle_info(_Info, State) ->
  183. {noreply, State}.
  184. terminate(_Reason, _State) ->
  185. ok.
  186. code_change(_OldVsn, State, _Extra) ->
  187. {ok, State}.