ranch.erl 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. %% Copyright (c) 2011-2015, 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/6]).
  16. -export([stop_listener/1]).
  17. -export([child_spec/6]).
  18. -export([accept_ack/1]).
  19. -export([remove_connection/1]).
  20. -export([get_addr/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 opt() :: {ack_timeout, timeout()}
  32. | {connection_type, worker | supervisor}
  33. | {max_connections, max_conns()}
  34. | {shutdown, timeout() | brutal_kill}
  35. | {socket, any()}.
  36. -export_type([opt/0]).
  37. -type ref() :: any().
  38. -export_type([ref/0]).
  39. -spec start_listener(ref(), non_neg_integer(), module(), any(), module(), any())
  40. -> supervisor:startchild_ret().
  41. start_listener(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
  42. when is_integer(NbAcceptors) andalso is_atom(Transport)
  43. andalso is_atom(Protocol) ->
  44. _ = code:ensure_loaded(Transport),
  45. case erlang:function_exported(Transport, name, 0) of
  46. false ->
  47. {error, badarg};
  48. true ->
  49. Res = supervisor:start_child(ranch_sup, child_spec(Ref, NbAcceptors,
  50. Transport, TransOpts, Protocol, ProtoOpts)),
  51. Socket = proplists:get_value(socket, TransOpts),
  52. case Res of
  53. {ok, Pid} when Socket =/= undefined ->
  54. %% Give ownership of the socket to ranch_acceptors_sup
  55. %% to make sure the socket stays open as long as the
  56. %% listener is alive. If the socket closes however there
  57. %% will be no way to recover because we don't know how
  58. %% to open it again.
  59. Children = supervisor:which_children(Pid),
  60. {_, AcceptorsSup, _, _}
  61. = lists:keyfind(ranch_acceptors_sup, 1, Children),
  62. %%% Note: the catch is here because SSL crashes when you change
  63. %%% the controlling process of a listen socket because of a bug.
  64. %%% The bug will be fixed in R16.
  65. catch Transport:controlling_process(Socket, AcceptorsSup);
  66. _ ->
  67. ok
  68. end,
  69. Res
  70. end.
  71. -spec stop_listener(ref()) -> ok | {error, not_found}.
  72. stop_listener(Ref) ->
  73. case supervisor:terminate_child(ranch_sup, {ranch_listener_sup, Ref}) of
  74. ok ->
  75. _ = supervisor:delete_child(ranch_sup, {ranch_listener_sup, Ref}),
  76. ranch_server:cleanup_listener_opts(Ref);
  77. {error, Reason} ->
  78. {error, Reason}
  79. end.
  80. -spec child_spec(ref(), non_neg_integer(), module(), any(), module(), any())
  81. -> supervisor:child_spec().
  82. child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
  83. when is_integer(NbAcceptors) andalso is_atom(Transport)
  84. andalso is_atom(Protocol) ->
  85. {{ranch_listener_sup, Ref}, {ranch_listener_sup, start_link, [
  86. Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts
  87. ]}, permanent, infinity, supervisor, [ranch_listener_sup]}.
  88. -spec accept_ack(ref()) -> ok.
  89. accept_ack(Ref) ->
  90. receive {shoot, Ref, Transport, Socket, AckTimeout} ->
  91. Transport:accept_ack(Socket, AckTimeout)
  92. end.
  93. -spec remove_connection(ref()) -> ok.
  94. remove_connection(Ref) ->
  95. ConnsSup = ranch_server:get_connections_sup(Ref),
  96. ConnsSup ! {remove_connection, Ref},
  97. ok.
  98. -spec get_addr(ref()) -> {inet:ip_address(), inet:port_number()}.
  99. get_addr(Ref) ->
  100. ranch_server:get_addr(Ref).
  101. -spec get_port(ref()) -> inet:port_number().
  102. get_port(Ref) ->
  103. {_, Port} = get_addr(Ref),
  104. Port.
  105. -spec get_max_connections(ref()) -> max_conns().
  106. get_max_connections(Ref) ->
  107. ranch_server:get_max_connections(Ref).
  108. -spec set_max_connections(ref(), max_conns()) -> ok.
  109. set_max_connections(Ref, MaxConnections) ->
  110. ranch_server:set_max_connections(Ref, MaxConnections).
  111. -spec get_protocol_options(ref()) -> any().
  112. get_protocol_options(Ref) ->
  113. ranch_server:get_protocol_options(Ref).
  114. -spec set_protocol_options(ref(), any()) -> ok.
  115. set_protocol_options(Ref, Opts) ->
  116. ranch_server:set_protocol_options(Ref, Opts).
  117. -spec filter_options([inet | inet6 | {atom(), any()} | {raw, any(), any(), any()}],
  118. [atom()], Acc) -> Acc when Acc :: [any()].
  119. filter_options(UserOptions, AllowedKeys, DefaultOptions) ->
  120. AllowedOptions = filter_user_options(UserOptions, AllowedKeys),
  121. lists:foldl(fun merge_options/2, DefaultOptions, AllowedOptions).
  122. %% 2-tuple options.
  123. filter_user_options([Opt = {Key, _}|Tail], AllowedKeys) ->
  124. case lists:member(Key, AllowedKeys) of
  125. true ->
  126. [Opt|filter_user_options(Tail, AllowedKeys)];
  127. false ->
  128. filter_options_warning(Opt),
  129. filter_user_options(Tail, AllowedKeys)
  130. end;
  131. %% Special option forms.
  132. filter_user_options([inet|Tail], AllowedKeys) ->
  133. [inet|filter_user_options(Tail, AllowedKeys)];
  134. filter_user_options([inet6|Tail], AllowedKeys) ->
  135. [inet6|filter_user_options(Tail, AllowedKeys)];
  136. filter_user_options([Opt = {raw, _, _, _}|Tail], AllowedKeys) ->
  137. [Opt|filter_user_options(Tail, AllowedKeys)];
  138. filter_user_options([Opt|Tail], AllowedKeys) ->
  139. filter_options_warning(Opt),
  140. filter_user_options(Tail, AllowedKeys);
  141. filter_user_options([], _) ->
  142. [].
  143. filter_options_warning(Opt) ->
  144. error_logger:warning_msg("Transport option ~p unknown or invalid.~n", [Opt]).
  145. merge_options({Key, _} = Option, OptionList) ->
  146. lists:keystore(Key, 1, OptionList, Option);
  147. merge_options(Option, OptionList) ->
  148. [Option|OptionList].
  149. -spec set_option_default(Opts, atom(), any())
  150. -> Opts when Opts :: [{atom(), any()}].
  151. set_option_default(Opts, Key, Value) ->
  152. case lists:keymember(Key, 1, Opts) of
  153. true -> Opts;
  154. false -> [{Key, Value}|Opts]
  155. end.
  156. -spec require([atom()]) -> ok.
  157. require([]) ->
  158. ok;
  159. require([App|Tail]) ->
  160. case application:start(App) of
  161. ok -> ok;
  162. {error, {already_started, App}} -> ok
  163. end,
  164. require(Tail).