ranch.erl 8.2 KB

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