ranch.erl 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. %% Copyright (c) 2011-2012, 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. %% @doc Ranch API to start and stop listeners.
  15. -module(ranch).
  16. -export([start_listener/6]).
  17. -export([stop_listener/1]).
  18. -export([child_spec/6]).
  19. -export([accept_ack/1]).
  20. -export([remove_connection/1]).
  21. -export([get_port/1]).
  22. -export([get_max_connections/1]).
  23. -export([set_max_connections/2]).
  24. -export([get_protocol_options/1]).
  25. -export([set_protocol_options/2]).
  26. -export([filter_options/3]).
  27. -export([set_option_default/3]).
  28. -export([require/1]).
  29. -type max_conns() :: non_neg_integer() | infinity.
  30. -export_type([max_conns/0]).
  31. %% @doc Start a listener for the given transport and protocol.
  32. %%
  33. %% A listener is effectively a pool of <em>NbAcceptors</em> acceptors.
  34. %% Acceptors accept connections on the given <em>Transport</em> and forward
  35. %% connections to the given <em>Protocol</em> handler. Both transport and
  36. %% protocol modules can be given options through the <em>TransOpts</em> and
  37. %% the <em>ProtoOpts</em> arguments. Available options are documented in the
  38. %% <em>listen</em> transport function and in the protocol module of your choice.
  39. %%
  40. %% All acceptor and connection processes are supervised by the listener.
  41. %%
  42. %% It is recommended to set a large enough number of acceptors to improve
  43. %% performance. The exact number depends of course on your hardware, on the
  44. %% protocol used and on the number of expected simultaneous connections.
  45. %%
  46. %% The <em>Transport</em> option <em>max_connections</em> allows you to define
  47. %% the maximum number of simultaneous connections for this listener. It defaults
  48. %% to 1024. See <em>ranch_listener</em> for more details on limiting the number
  49. %% of connections.
  50. %%
  51. %% <em>Ref</em> can be used to stop the listener later on.
  52. %%
  53. %% This function will return `{error, badarg}` if and only if the transport
  54. %% module given doesn't appear to be correct.
  55. -spec start_listener(any(), non_neg_integer(), module(), any(), module(), any())
  56. -> {ok, pid()} | {error, badarg}.
  57. start_listener(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
  58. when is_integer(NbAcceptors) andalso is_atom(Transport)
  59. andalso is_atom(Protocol) ->
  60. _ = code:ensure_loaded(Transport),
  61. case erlang:function_exported(Transport, name, 0) of
  62. false ->
  63. {error, badarg};
  64. true ->
  65. Res = supervisor:start_child(ranch_sup, child_spec(Ref, NbAcceptors,
  66. Transport, TransOpts, Protocol, ProtoOpts)),
  67. Socket = proplists:get_value(socket, TransOpts),
  68. case Res of
  69. {ok, Pid} when Socket =/= undefined ->
  70. %% Give ownership of the socket to ranch_acceptors_sup
  71. %% to make sure the socket stays open as long as the
  72. %% listener is alive. If the socket closes however there
  73. %% will be no way to recover because we don't know how
  74. %% to open it again.
  75. Children = supervisor:which_children(Pid),
  76. {_, AcceptorsSup, _, _}
  77. = lists:keyfind(ranch_acceptors_sup, 1, Children),
  78. %%% Note: the catch is here because SSL crashes when you change
  79. %%% the controlling process of a listen socket because of a bug.
  80. %%% The bug will be fixed in R16.
  81. catch Transport:controlling_process(Socket, AcceptorsSup);
  82. _ ->
  83. ok
  84. end,
  85. Res
  86. end.
  87. %% @doc Stop a listener identified by <em>Ref</em>.
  88. %%
  89. %% Note that stopping the listener will close all currently running
  90. %% connections abruptly.
  91. -spec stop_listener(any()) -> ok | {error, not_found}.
  92. stop_listener(Ref) ->
  93. case supervisor:terminate_child(ranch_sup, {ranch_listener_sup, Ref}) of
  94. ok ->
  95. _ = supervisor:delete_child(ranch_sup, {ranch_listener_sup, Ref}),
  96. ranch_server:cleanup_listener_opts(Ref);
  97. {error, Reason} ->
  98. {error, Reason}
  99. end.
  100. %% @doc Return a child spec suitable for embedding.
  101. %%
  102. %% When you want to embed Ranch in another application, you can use this
  103. %% function to create a <em>ChildSpec</em> suitable for use in a supervisor.
  104. %% The parameters are the same as in <em>start_listener/6</em> but rather
  105. %% than hooking the listener to the Ranch internal supervisor, it just returns
  106. %% the spec.
  107. -spec child_spec(any(), non_neg_integer(), module(), any(), module(), any())
  108. -> supervisor:child_spec().
  109. child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
  110. when is_integer(NbAcceptors) andalso is_atom(Transport)
  111. andalso is_atom(Protocol) ->
  112. {{ranch_listener_sup, Ref}, {ranch_listener_sup, start_link, [
  113. Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts
  114. ]}, permanent, 5000, supervisor, [ranch_listener_sup]}.
  115. %% @doc Acknowledge the accepted connection.
  116. %%
  117. %% Effectively used to make sure the socket control has been given to
  118. %% the protocol process before starting to use it.
  119. -spec accept_ack(any()) -> ok.
  120. accept_ack(Ref) ->
  121. receive {shoot, Ref} -> ok end.
  122. %% @doc Remove the calling process' connection from the pool.
  123. %%
  124. %% Useful if you have long-lived connections that aren't taking up
  125. %% resources and shouldn't be counted in the limited number of running
  126. %% connections.
  127. -spec remove_connection(any()) -> ok.
  128. remove_connection(Ref) ->
  129. ConnsSup = ranch_server:get_connections_sup(Ref),
  130. ConnsSup ! {remove_connection, Ref},
  131. ok.
  132. %% @doc Return the listener's port.
  133. -spec get_port(any()) -> inet:port_number().
  134. get_port(Ref) ->
  135. ranch_server:get_port(Ref).
  136. %% @doc Return the max number of connections allowed concurrently.
  137. -spec get_max_connections(any()) -> max_conns().
  138. get_max_connections(Ref) ->
  139. ranch_server:get_max_connections(Ref).
  140. %% @doc Set the max number of connections allowed concurrently.
  141. -spec set_max_connections(any(), max_conns()) -> ok.
  142. set_max_connections(Ref, MaxConnections) ->
  143. ranch_server:set_max_connections(Ref, MaxConnections).
  144. %% @doc Return the current protocol options for the given listener.
  145. -spec get_protocol_options(any()) -> any().
  146. get_protocol_options(Ref) ->
  147. ranch_server:get_protocol_options(Ref).
  148. %% @doc Upgrade the protocol options for the given listener.
  149. %%
  150. %% The upgrade takes place at the acceptor level, meaning that only the
  151. %% newly accepted connections receive the new protocol options. This has
  152. %% no effect on the currently opened connections.
  153. -spec set_protocol_options(any(), any()) -> ok.
  154. set_protocol_options(Ref, Opts) ->
  155. ranch_server:set_protocol_options(Ref, Opts).
  156. %% @doc Filter a list of options and remove all unwanted values.
  157. %%
  158. %% It takes a list of options, a list of allowed keys and an accumulator.
  159. %% This accumulator can be used to set default options that should never
  160. %% be overriden.
  161. -spec filter_options([{atom(), any()}], [atom()], Acc)
  162. -> Acc when Acc :: [any()].
  163. filter_options([], _, Acc) ->
  164. Acc;
  165. filter_options([Opt = {Key, _}|Tail], AllowedKeys, Acc) ->
  166. case lists:member(Key, AllowedKeys) of
  167. true -> filter_options(Tail, AllowedKeys, [Opt|Acc]);
  168. false -> filter_options(Tail, AllowedKeys, Acc)
  169. end;
  170. filter_options([Opt = {raw, _, _, _}|Tail], AllowedKeys, Acc) ->
  171. case lists:member(raw, AllowedKeys) of
  172. true -> filter_options(Tail, AllowedKeys, [Opt|Acc]);
  173. false -> filter_options(Tail, AllowedKeys, Acc)
  174. end.
  175. %% @doc Add an option to a list, but only if it wasn't previously set.
  176. -spec set_option_default(Opts, atom(), any())
  177. -> Opts when Opts :: [{atom(), any()}].
  178. set_option_default(Opts, Key, Value) ->
  179. case lists:keymember(Key, 1, Opts) of
  180. true -> Opts;
  181. false -> [{Key, Value}|Opts]
  182. end.
  183. %% @doc Start the given applications if they were not already started.
  184. -spec require(list(module())) -> ok.
  185. require([]) ->
  186. ok;
  187. require([App|Tail]) ->
  188. case application:start(App) of
  189. ok -> ok;
  190. {error, {already_started, App}} -> ok
  191. end,
  192. require(Tail).