ranch.erl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. %% Copyright (c) 2011-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).
  15. -export([start_listener/5]).
  16. -export([normalize_opts/1]).
  17. -export([stop_listener/1]).
  18. -export([suspend_listener/1]).
  19. -export([resume_listener/1]).
  20. -export([child_spec/5]).
  21. -export([handshake/1]).
  22. -export([handshake/2]).
  23. -export([recv_proxy_header/2]).
  24. -export([remove_connection/1]).
  25. -export([get_status/1]).
  26. -export([get_addr/1]).
  27. -export([get_port/1]).
  28. -export([get_max_connections/1]).
  29. -export([set_max_connections/2]).
  30. -export([get_transport_options/1]).
  31. -export([set_transport_options/2]).
  32. -export([get_protocol_options/1]).
  33. -export([set_protocol_options/2]).
  34. -export([info/0]).
  35. -export([info/1]).
  36. -export([procs/2]).
  37. -export([wait_for_connections/3]).
  38. -export([wait_for_connections/4]).
  39. -export([filter_options/4]).
  40. -export([set_option_default/3]).
  41. -export([require/1]).
  42. -export([log/4]).
  43. -type max_conns() :: non_neg_integer() | infinity.
  44. -export_type([max_conns/0]).
  45. -type opts() :: any() | transport_opts(any()).
  46. -export_type([opts/0]).
  47. -type transport_opts(SocketOpts) :: #{
  48. connection_type => worker | supervisor,
  49. handshake_timeout => timeout(),
  50. max_connections => max_conns(),
  51. logger => module(),
  52. num_acceptors => pos_integer(),
  53. num_conns_sups => pos_integer(),
  54. num_listen_sockets => pos_integer(),
  55. shutdown => timeout() | brutal_kill,
  56. socket_opts => SocketOpts
  57. }.
  58. -export_type([transport_opts/1]).
  59. -type ref() :: any().
  60. -export_type([ref/0]).
  61. -spec start_listener(ref(), module(), opts(), module(), any())
  62. -> supervisor:startchild_ret().
  63. start_listener(Ref, Transport, TransOpts0, Protocol, ProtoOpts)
  64. when is_atom(Transport), is_atom(Protocol) ->
  65. TransOpts = normalize_opts(TransOpts0),
  66. _ = code:ensure_loaded(Transport),
  67. case {erlang:function_exported(Transport, name, 0), validate_transport_opts(TransOpts)} of
  68. {true, ok} ->
  69. maybe_started(supervisor:start_child(ranch_sup, child_spec(Ref,
  70. Transport, TransOpts, Protocol, ProtoOpts)));
  71. {false, _} ->
  72. {error, {bad_transport, Transport}};
  73. {_, TransOptsError} ->
  74. TransOptsError
  75. end.
  76. -spec normalize_opts(opts()) -> transport_opts(any()).
  77. normalize_opts(Map) when is_map(Map) ->
  78. Map;
  79. normalize_opts(Any) ->
  80. #{socket_opts => Any}.
  81. -spec validate_transport_opts(transport_opts(any())) -> ok | {error, any()}.
  82. validate_transport_opts(Opts) ->
  83. maps:fold(fun
  84. (Key, Value, ok) ->
  85. case validate_transport_opt(Key, Value, Opts) of
  86. true ->
  87. ok;
  88. false ->
  89. {error, {bad_option, Key}}
  90. end;
  91. (_, _, Acc) ->
  92. Acc
  93. end, ok, Opts).
  94. -spec validate_transport_opt(any(), any(), transport_opts(any())) -> boolean().
  95. validate_transport_opt(connection_type, worker, _) ->
  96. true;
  97. validate_transport_opt(connection_type, supervisor, _) ->
  98. true;
  99. validate_transport_opt(handshake_timeout, infinity, _) ->
  100. true;
  101. validate_transport_opt(handshake_timeout, Value, _) ->
  102. is_integer(Value) andalso Value >= 0;
  103. validate_transport_opt(max_connections, infinity, _) ->
  104. true;
  105. validate_transport_opt(max_connections, Value, _) ->
  106. is_integer(Value) andalso Value >= 0;
  107. validate_transport_opt(logger, Value, _) ->
  108. is_atom(Value);
  109. validate_transport_opt(num_acceptors, Value, _) ->
  110. is_integer(Value) andalso Value > 0;
  111. validate_transport_opt(num_conns_sups, Value, _) ->
  112. is_integer(Value) andalso Value > 0;
  113. validate_transport_opt(num_listen_sockets, Value, Opts) ->
  114. is_integer(Value) andalso Value > 0
  115. andalso Value =< maps:get(num_acceptors, Opts, 10);
  116. validate_transport_opt(shutdown, brutal_kill, _) ->
  117. true;
  118. validate_transport_opt(shutdown, infinity, _) ->
  119. true;
  120. validate_transport_opt(shutdown, Value, _) ->
  121. is_integer(Value) andalso Value >= 0;
  122. validate_transport_opt(socket_opts, _, _) ->
  123. true;
  124. validate_transport_opt(_, _, _) ->
  125. false.
  126. maybe_started({error, {{shutdown,
  127. {failed_to_start_child, ranch_acceptors_sup,
  128. {listen_error, _, Reason}}}, _}} = Error) ->
  129. start_error(Reason, Error);
  130. maybe_started(Res) ->
  131. Res.
  132. start_error(E=eaddrinuse, _) -> {error, E};
  133. start_error(E=eacces, _) -> {error, E};
  134. start_error(E=no_cert, _) -> {error, E};
  135. start_error(_, Error) -> Error.
  136. -spec stop_listener(ref()) -> ok | {error, not_found}.
  137. stop_listener(Ref) ->
  138. case supervisor:terminate_child(ranch_sup, {ranch_listener_sup, Ref}) of
  139. ok ->
  140. _ = supervisor:delete_child(ranch_sup, {ranch_listener_sup, Ref}),
  141. ranch_server:cleanup_listener_opts(Ref);
  142. {error, Reason} ->
  143. {error, Reason}
  144. end.
  145. -spec suspend_listener(ref()) -> ok | {error, any()}.
  146. suspend_listener(Ref) ->
  147. case get_status(Ref) of
  148. running ->
  149. ListenerSup = ranch_server:get_listener_sup(Ref),
  150. ok = ranch_server:set_addr(Ref, {undefined, undefined}),
  151. supervisor:terminate_child(ListenerSup, ranch_acceptors_sup);
  152. suspended ->
  153. ok
  154. end.
  155. -spec resume_listener(ref()) -> ok | {error, any()}.
  156. resume_listener(Ref) ->
  157. case get_status(Ref) of
  158. running ->
  159. ok;
  160. suspended ->
  161. ListenerSup = ranch_server:get_listener_sup(Ref),
  162. Res = supervisor:restart_child(ListenerSup, ranch_acceptors_sup),
  163. maybe_resumed(Res)
  164. end.
  165. maybe_resumed(Error={error, {listen_error, _, Reason}}) ->
  166. start_error(Reason, Error);
  167. maybe_resumed({ok, _}) ->
  168. ok;
  169. maybe_resumed({ok, _, _}) ->
  170. ok;
  171. maybe_resumed(Res) ->
  172. Res.
  173. -spec child_spec(ref(), module(), opts(), module(), any())
  174. -> supervisor:child_spec().
  175. child_spec(Ref, Transport, TransOpts0, Protocol, ProtoOpts) ->
  176. TransOpts = normalize_opts(TransOpts0),
  177. {{ranch_listener_sup, Ref}, {ranch_listener_sup, start_link, [
  178. Ref, Transport, TransOpts, Protocol, ProtoOpts
  179. ]}, permanent, infinity, supervisor, [ranch_listener_sup]}.
  180. -spec handshake(ref()) -> {ok, ranch_transport:socket()}.
  181. handshake(Ref) ->
  182. handshake(Ref, []).
  183. -spec handshake(ref(), any()) -> {ok, ranch_transport:socket()}.
  184. handshake(Ref, Opts) ->
  185. receive {handshake, Ref, Transport, CSocket, HandshakeTimeout} ->
  186. case Transport:handshake(CSocket, Opts, HandshakeTimeout) of
  187. OK = {ok, _} ->
  188. OK;
  189. %% Garbage was most likely sent to the socket, don't error out.
  190. {error, {tls_alert, _}} ->
  191. ok = Transport:close(CSocket),
  192. exit(normal);
  193. %% Socket most likely stopped responding, don't error out.
  194. {error, Reason} when Reason =:= timeout; Reason =:= closed ->
  195. ok = Transport:close(CSocket),
  196. exit(normal);
  197. {error, Reason} ->
  198. ok = Transport:close(CSocket),
  199. error(Reason)
  200. end
  201. end.
  202. %% Unlike handshake/2 this function always return errors because
  203. %% the communication between the proxy and the server are expected
  204. %% to be reliable. If there is a problem while receiving the proxy
  205. %% header, we probably want to know about it.
  206. -spec recv_proxy_header(ref(), timeout())
  207. -> {ok, ranch_proxy_header:proxy_info()}
  208. | {error, closed | atom()}
  209. | {error, protocol_error, atom()}.
  210. recv_proxy_header(Ref, Timeout) ->
  211. receive HandshakeState={handshake, Ref, Transport, CSocket, _} ->
  212. self() ! HandshakeState,
  213. Transport:recv_proxy_header(CSocket, Timeout)
  214. end.
  215. -spec remove_connection(ref()) -> ok.
  216. remove_connection(Ref) ->
  217. ListenerSup = ranch_server:get_listener_sup(Ref),
  218. {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1,
  219. supervisor:which_children(ListenerSup)),
  220. _ = [ConnsSup ! {remove_connection, Ref, self()} ||
  221. {_, ConnsSup, _, _} <- supervisor:which_children(ConnsSupSup)],
  222. ok.
  223. -spec get_status(ref()) -> running | suspended.
  224. get_status(Ref) ->
  225. ListenerSup = ranch_server:get_listener_sup(Ref),
  226. Children = supervisor:which_children(ListenerSup),
  227. case lists:keyfind(ranch_acceptors_sup, 1, Children) of
  228. {_, undefined, _, _} ->
  229. suspended;
  230. _ ->
  231. running
  232. end.
  233. -spec get_addr(ref()) -> {inet:ip_address(), inet:port_number()} |
  234. {local, binary()} | {undefined, undefined}.
  235. get_addr(Ref) ->
  236. ranch_server:get_addr(Ref).
  237. -spec get_port(ref()) -> inet:port_number() | undefined.
  238. get_port(Ref) ->
  239. case get_addr(Ref) of
  240. {local, _} ->
  241. undefined;
  242. {_, Port} ->
  243. Port
  244. end.
  245. -spec get_connections(ref(), active|all) -> non_neg_integer().
  246. get_connections(Ref, active) ->
  247. SupCounts = [ranch_conns_sup:active_connections(ConnsSup) ||
  248. {_, ConnsSup} <- ranch_server:get_connections_sups(Ref)],
  249. lists:sum(SupCounts);
  250. get_connections(Ref, all) ->
  251. SupCounts = [proplists:get_value(active, supervisor:count_children(ConnsSup)) ||
  252. {_, ConnsSup} <- ranch_server:get_connections_sups(Ref)],
  253. lists:sum(SupCounts).
  254. -spec get_max_connections(ref()) -> max_conns().
  255. get_max_connections(Ref) ->
  256. ranch_server:get_max_connections(Ref).
  257. -spec set_max_connections(ref(), max_conns()) -> ok.
  258. set_max_connections(Ref, MaxConnections) ->
  259. ranch_server:set_max_connections(Ref, MaxConnections).
  260. -spec get_transport_options(ref()) -> transport_opts(any()).
  261. get_transport_options(Ref) ->
  262. ranch_server:get_transport_options(Ref).
  263. -spec set_transport_options(ref(), opts()) -> ok | {error, running}.
  264. set_transport_options(Ref, TransOpts0) ->
  265. TransOpts = normalize_opts(TransOpts0),
  266. case get_status(Ref) of
  267. suspended ->
  268. ok = ranch_server:set_transport_options(Ref, TransOpts);
  269. running ->
  270. {error, running}
  271. end.
  272. -spec get_protocol_options(ref()) -> any().
  273. get_protocol_options(Ref) ->
  274. ranch_server:get_protocol_options(Ref).
  275. -spec set_protocol_options(ref(), any()) -> ok.
  276. set_protocol_options(Ref, Opts) ->
  277. ranch_server:set_protocol_options(Ref, Opts).
  278. -spec info() -> [{any(), [{atom(), any()}]}].
  279. info() ->
  280. [{Ref, listener_info(Ref, Pid)}
  281. || {Ref, Pid} <- ranch_server:get_listener_sups()].
  282. -spec info(ref()) -> [{atom(), any()}].
  283. info(Ref) ->
  284. Pid = ranch_server:get_listener_sup(Ref),
  285. listener_info(Ref, Pid).
  286. listener_info(Ref, Pid) ->
  287. [_, Transport, _, Protocol, _] = ranch_server:get_listener_start_args(Ref),
  288. Status = get_status(Ref),
  289. {IP, Port} = case get_addr(Ref) of
  290. Addr = {local, _} ->
  291. {Addr, undefined};
  292. Addr ->
  293. Addr
  294. end,
  295. MaxConns = get_max_connections(Ref),
  296. TransOpts = ranch_server:get_transport_options(Ref),
  297. ProtoOpts = get_protocol_options(Ref),
  298. [
  299. {pid, Pid},
  300. {status, Status},
  301. {ip, IP},
  302. {port, Port},
  303. {max_connections, MaxConns},
  304. {active_connections, get_connections(Ref, active)},
  305. {all_connections, get_connections(Ref, all)},
  306. {transport, Transport},
  307. {transport_options, TransOpts},
  308. {protocol, Protocol},
  309. {protocol_options, ProtoOpts}
  310. ].
  311. -spec procs(ref(), acceptors | connections) -> [pid()].
  312. procs(Ref, Type) ->
  313. ListenerSup = ranch_server:get_listener_sup(Ref),
  314. procs1(ListenerSup, Type).
  315. procs1(ListenerSup, acceptors) ->
  316. {_, SupPid, _, _} = lists:keyfind(ranch_acceptors_sup, 1,
  317. supervisor:which_children(ListenerSup)),
  318. try
  319. [Pid || {_, Pid, _, _} <- supervisor:which_children(SupPid)]
  320. catch exit:{noproc, _} ->
  321. []
  322. end;
  323. procs1(ListenerSup, connections) ->
  324. {_, SupSupPid, _, _} = lists:keyfind(ranch_conns_sup_sup, 1,
  325. supervisor:which_children(ListenerSup)),
  326. Conns=
  327. lists:map(fun ({_, SupPid, _, _}) ->
  328. [Pid || {_, Pid, _, _} <- supervisor:which_children(SupPid)]
  329. end,
  330. supervisor:which_children(SupSupPid)
  331. ),
  332. lists:flatten(Conns).
  333. -spec wait_for_connections
  334. (ref(), '>' | '>=' | '==' | '=<', non_neg_integer()) -> ok;
  335. (ref(), '<', pos_integer()) -> ok.
  336. wait_for_connections(Ref, Op, NumConns) ->
  337. wait_for_connections(Ref, Op, NumConns, 1000).
  338. -spec wait_for_connections
  339. (ref(), '>' | '>=' | '==' | '=<', non_neg_integer(), non_neg_integer()) -> ok;
  340. (ref(), '<', pos_integer(), non_neg_integer()) -> ok.
  341. wait_for_connections(Ref, Op, NumConns, Interval) ->
  342. validate_op(Op, NumConns),
  343. validate_num_conns(NumConns),
  344. validate_interval(Interval),
  345. wait_for_connections_loop(Ref, Op, NumConns, Interval).
  346. validate_op('>', _) -> ok;
  347. validate_op('>=', _) -> ok;
  348. validate_op('==', _) -> ok;
  349. validate_op('=<', _) -> ok;
  350. validate_op('<', NumConns) when NumConns > 0 -> ok;
  351. validate_op(_, _) -> error(badarg).
  352. validate_num_conns(NumConns) when is_integer(NumConns), NumConns >= 0 -> ok;
  353. validate_num_conns(_) -> error(badarg).
  354. validate_interval(Interval) when is_integer(Interval), Interval >= 0 -> ok;
  355. validate_interval(_) -> error(badarg).
  356. wait_for_connections_loop(Ref, Op, NumConns, Interval) ->
  357. CurConns = try
  358. get_connections(Ref, all)
  359. catch _:_ ->
  360. 0
  361. end,
  362. case erlang:Op(CurConns, NumConns) of
  363. true ->
  364. ok;
  365. false when Interval =:= 0 ->
  366. wait_for_connections_loop(Ref, Op, NumConns, Interval);
  367. false ->
  368. timer:sleep(Interval),
  369. wait_for_connections_loop(Ref, Op, NumConns, Interval)
  370. end.
  371. -spec filter_options([inet | inet6 | {atom(), any()} | {raw, any(), any(), any()}],
  372. [atom()], Acc, module()) -> Acc when Acc :: [any()].
  373. filter_options(UserOptions, DisallowedKeys, DefaultOptions, Logger) ->
  374. AllowedOptions = filter_user_options(UserOptions, DisallowedKeys, Logger),
  375. lists:foldl(fun merge_options/2, DefaultOptions, AllowedOptions).
  376. %% 2-tuple options.
  377. filter_user_options([Opt = {Key, _}|Tail], DisallowedKeys, Logger) ->
  378. case lists:member(Key, DisallowedKeys) of
  379. false ->
  380. [Opt|filter_user_options(Tail, DisallowedKeys, Logger)];
  381. true ->
  382. filter_options_warning(Opt, Logger),
  383. filter_user_options(Tail, DisallowedKeys, Logger)
  384. end;
  385. %% Special option forms.
  386. filter_user_options([inet|Tail], DisallowedKeys, Logger) ->
  387. [inet|filter_user_options(Tail, DisallowedKeys, Logger)];
  388. filter_user_options([inet6|Tail], DisallowedKeys, Logger) ->
  389. [inet6|filter_user_options(Tail, DisallowedKeys, Logger)];
  390. filter_user_options([Opt = {raw, _, _, _}|Tail], DisallowedKeys, Logger) ->
  391. [Opt|filter_user_options(Tail, DisallowedKeys, Logger)];
  392. filter_user_options([Opt|Tail], DisallowedKeys, Logger) ->
  393. filter_options_warning(Opt, Logger),
  394. filter_user_options(Tail, DisallowedKeys, Logger);
  395. filter_user_options([], _, _) ->
  396. [].
  397. filter_options_warning(Opt, Logger) ->
  398. log(warning,
  399. "Transport option ~p unknown or invalid.~n",
  400. [Opt], Logger).
  401. merge_options({Key, _} = Option, OptionList) ->
  402. lists:keystore(Key, 1, OptionList, Option);
  403. merge_options(Option, OptionList) ->
  404. [Option|OptionList].
  405. -spec set_option_default(Opts, atom(), any())
  406. -> Opts when Opts :: [{atom(), any()}].
  407. set_option_default(Opts, Key, Value) ->
  408. case lists:keymember(Key, 1, Opts) of
  409. true -> Opts;
  410. false -> [{Key, Value}|Opts]
  411. end.
  412. -spec require([atom()]) -> ok.
  413. require([]) ->
  414. ok;
  415. require([App|Tail]) ->
  416. case application:start(App) of
  417. ok -> ok;
  418. {error, {already_started, App}} -> ok
  419. end,
  420. require(Tail).
  421. -spec log(logger:level(), io:format(), list(), module() | #{logger => module()}) -> ok.
  422. log(Level, Format, Args, Logger) when is_atom(Logger) ->
  423. log(Level, Format, Args, #{logger => Logger});
  424. log(Level, Format, Args, #{logger := Logger})
  425. when Logger =/= error_logger ->
  426. _ = Logger:Level(Format, Args),
  427. ok;
  428. %% Because error_logger does not have all the levels
  429. %% we accept we have to do some mapping to error_logger functions.
  430. log(Level, Format, Args, _) ->
  431. Function = case Level of
  432. emergency -> error_msg;
  433. alert -> error_msg;
  434. critical -> error_msg;
  435. error -> error_msg;
  436. warning -> warning_msg;
  437. notice -> warning_msg;
  438. info -> info_msg;
  439. debug -> info_msg
  440. end,
  441. error_logger:Function(Format, Args).