ranch.erl 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. %% Copyright (c) 2011-2017, 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).
  15. -export([start_listener/5]).
  16. -export([start_listener/6]).
  17. -export([stop_listener/1]).
  18. -export([child_spec/5]).
  19. -export([child_spec/6]).
  20. -export([accept_ack/1]).
  21. -export([remove_connection/1]).
  22. -export([get_addr/1]).
  23. -export([get_port/1]).
  24. -export([get_max_connections/1]).
  25. -export([set_max_connections/2]).
  26. -export([get_protocol_options/1]).
  27. -export([set_protocol_options/2]).
  28. -export([info/0]).
  29. -export([procs/2]).
  30. -export([filter_options/3]).
  31. -export([set_option_default/3]).
  32. -export([require/1]).
  33. -deprecated([start_listener/6, child_spec/6]).
  34. -type max_conns() :: non_neg_integer() | infinity.
  35. -export_type([max_conns/0]).
  36. -type opt() :: {ack_timeout, timeout()}
  37. | {connection_type, worker | supervisor}
  38. | {max_connections, max_conns()}
  39. | {num_acceptors, pos_integer()}
  40. | {shutdown, timeout() | brutal_kill}
  41. | {socket, any()}.
  42. -export_type([opt/0]).
  43. -type ref() :: any().
  44. -export_type([ref/0]).
  45. -spec start_listener(ref(), module(), any(), module(), any())
  46. -> supervisor:startchild_ret().
  47. start_listener(Ref, Transport, TransOpts, Protocol, ProtoOpts) ->
  48. NumAcceptors = proplists:get_value(num_acceptors, TransOpts, 10),
  49. start_listener(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts).
  50. -spec start_listener(ref(), non_neg_integer(), module(), any(), module(), any())
  51. -> supervisor:startchild_ret().
  52. start_listener(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
  53. when is_integer(NumAcceptors) andalso is_atom(Transport)
  54. andalso is_atom(Protocol) ->
  55. _ = code:ensure_loaded(Transport),
  56. case erlang:function_exported(Transport, name, 0) of
  57. false ->
  58. {error, badarg};
  59. true ->
  60. Res = supervisor:start_child(ranch_sup, child_spec(Ref, NumAcceptors,
  61. Transport, TransOpts, Protocol, ProtoOpts)),
  62. Socket = proplists:get_value(socket, TransOpts),
  63. case Res of
  64. {ok, Pid} when Socket =/= undefined ->
  65. %% Give ownership of the socket to ranch_acceptors_sup
  66. %% to make sure the socket stays open as long as the
  67. %% listener is alive. If the socket closes however there
  68. %% will be no way to recover because we don't know how
  69. %% to open it again.
  70. Children = supervisor:which_children(Pid),
  71. {_, AcceptorsSup, _, _}
  72. = lists:keyfind(ranch_acceptors_sup, 1, Children),
  73. %%% Note: the catch is here because SSL crashes when you change
  74. %%% the controlling process of a listen socket because of a bug.
  75. %%% The bug will be fixed in R16.
  76. catch Transport:controlling_process(Socket, AcceptorsSup);
  77. _ ->
  78. ok
  79. end,
  80. maybe_started(Res)
  81. end.
  82. maybe_started({error, {{shutdown,
  83. {failed_to_start_child, ranch_acceptors_sup,
  84. {listen_error, _, Reason}}}, _}} = Error) ->
  85. start_error(Reason, Error);
  86. maybe_started(Res) ->
  87. Res.
  88. start_error(E=eaddrinuse, _) -> {error, E};
  89. start_error(E=eacces, _) -> {error, E};
  90. start_error(E=no_cert, _) -> {error, E};
  91. start_error(_, Error) -> Error.
  92. -spec stop_listener(ref()) -> ok | {error, not_found}.
  93. stop_listener(Ref) ->
  94. case supervisor:terminate_child(ranch_sup, {ranch_listener_sup, Ref}) of
  95. ok ->
  96. _ = supervisor:delete_child(ranch_sup, {ranch_listener_sup, Ref}),
  97. ranch_server:cleanup_listener_opts(Ref);
  98. {error, Reason} ->
  99. {error, Reason}
  100. end.
  101. -spec child_spec(ref(), module(), any(), module(), any())
  102. -> supervisor:child_spec().
  103. child_spec(Ref, Transport, TransOpts, Protocol, ProtoOpts) ->
  104. NumAcceptors = proplists:get_value(num_acceptors, TransOpts, 10),
  105. child_spec(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts).
  106. -spec child_spec(ref(), non_neg_integer(), module(), any(), module(), any())
  107. -> supervisor:child_spec().
  108. child_spec(Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
  109. when is_integer(NumAcceptors) andalso is_atom(Transport)
  110. andalso is_atom(Protocol) ->
  111. {{ranch_listener_sup, Ref}, {ranch_listener_sup, start_link, [
  112. Ref, NumAcceptors, Transport, TransOpts, Protocol, ProtoOpts
  113. ]}, permanent, infinity, supervisor, [ranch_listener_sup]}.
  114. -spec accept_ack(ref()) -> ok.
  115. accept_ack(Ref) ->
  116. receive {shoot, Ref, Transport, Socket, AckTimeout} ->
  117. Transport:accept_ack(Socket, AckTimeout)
  118. end.
  119. -spec remove_connection(ref()) -> ok.
  120. remove_connection(Ref) ->
  121. ConnsSup = ranch_server:get_connections_sup(Ref),
  122. ConnsSup ! {remove_connection, Ref, self()},
  123. ok.
  124. -spec get_addr(ref()) -> {inet:ip_address(), inet:port_number()}.
  125. get_addr(Ref) ->
  126. ranch_server:get_addr(Ref).
  127. -spec get_port(ref()) -> inet:port_number().
  128. get_port(Ref) ->
  129. {_, Port} = get_addr(Ref),
  130. Port.
  131. -spec get_max_connections(ref()) -> max_conns().
  132. get_max_connections(Ref) ->
  133. ranch_server:get_max_connections(Ref).
  134. -spec set_max_connections(ref(), max_conns()) -> ok.
  135. set_max_connections(Ref, MaxConnections) ->
  136. ranch_server:set_max_connections(Ref, MaxConnections).
  137. -spec get_protocol_options(ref()) -> any().
  138. get_protocol_options(Ref) ->
  139. ranch_server:get_protocol_options(Ref).
  140. -spec set_protocol_options(ref(), any()) -> ok.
  141. set_protocol_options(Ref, Opts) ->
  142. ranch_server:set_protocol_options(Ref, Opts).
  143. -spec info() -> [{any(), [{atom(), any()}]}].
  144. info() ->
  145. Children = supervisor:which_children(ranch_sup),
  146. [{Ref, listener_info(Ref, Pid)}
  147. || {{ranch_listener_sup, Ref}, Pid, _, [_]} <- Children].
  148. listener_info(Ref, Pid) ->
  149. [_, NumAcceptors, Transport, TransOpts, Protocol, _] = listener_start_args(Ref),
  150. ConnsSup = ranch_server:get_connections_sup(Ref),
  151. {IP, Port} = get_addr(Ref),
  152. MaxConns = get_max_connections(Ref),
  153. ProtoOpts = get_protocol_options(Ref),
  154. [
  155. {pid, Pid},
  156. {ip, IP},
  157. {port, Port},
  158. {num_acceptors, NumAcceptors},
  159. {max_connections, MaxConns},
  160. {active_connections, ranch_conns_sup:active_connections(ConnsSup)},
  161. {all_connections, proplists:get_value(active, supervisor:count_children(ConnsSup))},
  162. {transport, Transport},
  163. {transport_options, TransOpts},
  164. {protocol, Protocol},
  165. {protocol_options, ProtoOpts}
  166. ].
  167. listener_start_args(Ref) ->
  168. case erlang:function_exported(supervisor, get_childspec, 2) of
  169. true ->
  170. %% Can't use map syntax before R18.
  171. {ok, Map} = supervisor:get_childspec(ranch_sup, {ranch_listener_sup, Ref}),
  172. {ranch_listener_sup, start_link, StartArgs} = maps:get(start, Map),
  173. StartArgs;
  174. false ->
  175. %% Awful solution for compatibility with R16 and R17.
  176. {status, _, _, [_, _, _, _, [_, _,
  177. {data, [{_, {state, _, _, Children, _, _, _, _, _, _}}]}]]}
  178. = sys:get_status(ranch_sup),
  179. [StartArgs] = [StartArgs || {child, _, {ranch_listener_sup, ChildRef},
  180. {ranch_listener_sup, start_link, StartArgs}, _, _, _, _}
  181. <- Children, ChildRef =:= Ref],
  182. StartArgs
  183. end.
  184. -spec procs(ref(), acceptors | connections) -> [pid()].
  185. procs(Ref, acceptors) ->
  186. procs1(Ref, ranch_acceptors_sup);
  187. procs(Ref, connections) ->
  188. procs1(Ref, ranch_conns_sup).
  189. procs1(Ref, Sup) ->
  190. {_, ListenerSup, _, _} = lists:keyfind({ranch_listener_sup, Ref}, 1,
  191. supervisor:which_children(ranch_sup)),
  192. {_, SupPid, _, _} = lists:keyfind(Sup, 1,
  193. supervisor:which_children(ListenerSup)),
  194. [Pid || {_, Pid, _, _} <- supervisor:which_children(SupPid)].
  195. -spec filter_options([inet | inet6 | {atom(), any()} | {raw, any(), any(), any()}],
  196. [atom()], Acc) -> Acc when Acc :: [any()].
  197. filter_options(UserOptions, DisallowedKeys, DefaultOptions) ->
  198. AllowedOptions = filter_user_options(UserOptions, DisallowedKeys),
  199. lists:foldl(fun merge_options/2, DefaultOptions, AllowedOptions).
  200. %% 2-tuple options.
  201. filter_user_options([Opt = {Key, _}|Tail], DisallowedKeys) ->
  202. case lists:member(Key, DisallowedKeys) of
  203. false ->
  204. [Opt|filter_user_options(Tail, DisallowedKeys)];
  205. true ->
  206. filter_options_warning(Opt),
  207. filter_user_options(Tail, DisallowedKeys)
  208. end;
  209. %% Special option forms.
  210. filter_user_options([inet|Tail], AllowedKeys) ->
  211. [inet|filter_user_options(Tail, AllowedKeys)];
  212. filter_user_options([inet6|Tail], AllowedKeys) ->
  213. [inet6|filter_user_options(Tail, AllowedKeys)];
  214. filter_user_options([Opt = {raw, _, _, _}|Tail], AllowedKeys) ->
  215. [Opt|filter_user_options(Tail, AllowedKeys)];
  216. filter_user_options([Opt|Tail], DisallowedKeys) ->
  217. filter_options_warning(Opt),
  218. filter_user_options(Tail, DisallowedKeys);
  219. filter_user_options([], _) ->
  220. [].
  221. filter_options_warning(Opt) ->
  222. error_logger:warning_msg("Transport option ~p unknown or invalid.~n", [Opt]).
  223. merge_options({Key, _} = Option, OptionList) ->
  224. lists:keystore(Key, 1, OptionList, Option);
  225. merge_options(Option, OptionList) ->
  226. [Option|OptionList].
  227. -spec set_option_default(Opts, atom(), any())
  228. -> Opts when Opts :: [{atom(), any()}].
  229. set_option_default(Opts, Key, Value) ->
  230. case lists:keymember(Key, 1, Opts) of
  231. true -> Opts;
  232. false -> [{Key, Value}|Opts]
  233. end.
  234. -spec require([atom()]) -> ok.
  235. require([]) ->
  236. ok;
  237. require([App|Tail]) ->
  238. case application:start(App) of
  239. ok -> ok;
  240. {error, {already_started, App}} -> ok
  241. end,
  242. require(Tail).