acceptor_SUITE.erl 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  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(acceptor_SUITE).
  15. -compile(export_all).
  16. -import(ct_helper, [doc/1]).
  17. -import(ct_helper, [name/0]).
  18. %% ct.
  19. all() ->
  20. [{group, tcp}, {group, ssl}, {group, misc}, {group, supervisor}].
  21. groups() ->
  22. [{tcp, [
  23. tcp_accept_socket,
  24. tcp_active_echo,
  25. tcp_echo,
  26. tcp_graceful,
  27. tcp_inherit_options,
  28. tcp_max_connections,
  29. tcp_max_connections_and_beyond,
  30. tcp_max_connections_infinity,
  31. tcp_remove_connections,
  32. tcp_set_max_connections,
  33. tcp_set_max_connections_clean,
  34. tcp_getopts_capability,
  35. tcp_getstat_capability,
  36. tcp_upgrade,
  37. tcp_error_eaddrinuse,
  38. tcp_error_eacces
  39. ]}, {ssl, [
  40. ssl_accept_error,
  41. ssl_accept_socket,
  42. ssl_active_echo,
  43. ssl_echo,
  44. ssl_graceful,
  45. ssl_sni_echo,
  46. ssl_sni_fail,
  47. ssl_getopts_capability,
  48. ssl_getstat_capability,
  49. ssl_error_eaddrinuse,
  50. ssl_error_no_cert,
  51. ssl_error_eacces
  52. ]}, {misc, [
  53. misc_bad_transport,
  54. misc_bad_transport_options,
  55. misc_info,
  56. misc_info_embedded
  57. ]}, {supervisor, [
  58. connection_type_supervisor,
  59. connection_type_supervisor_separate_from_connection,
  60. supervisor_changed_options_restart,
  61. supervisor_clean_child_restart,
  62. supervisor_clean_conns_sup_restart,
  63. supervisor_clean_restart,
  64. supervisor_conns_alive,
  65. supervisor_protocol_start_link_crash,
  66. supervisor_server_recover_state,
  67. supervisor_unexpected_message
  68. ]}].
  69. %% misc.
  70. misc_bad_transport(_) ->
  71. doc("Reject invalid transport modules."),
  72. {error, badarg} = ranch:start_listener(misc_bad_transport,
  73. bad_transport, [], echo_protocol, []),
  74. ok.
  75. misc_bad_transport_options(_) ->
  76. doc("Ignore invalid transport options."),
  77. {ok, _} = ranch:start_listener(misc_bad_transport,
  78. ranch_tcp, [binary, {packet, 4}, <<"garbage">>, raw, backlog], echo_protocol, []),
  79. ok.
  80. misc_info(_) ->
  81. doc("Information about listeners."),
  82. %% Open a listener with a few connections.
  83. {ok, Pid1} = ranch:start_listener({misc_info, tcp},
  84. ranch_tcp, [{num_acceptors, 1}],
  85. remove_conn_and_wait_protocol, [{remove, true, 2500}]),
  86. Port1 = ranch:get_port({misc_info, tcp}),
  87. %% Open a few more listeners with different arguments.
  88. {ok, Pid2} = ranch:start_listener({misc_info, act},
  89. ranch_tcp, [{num_acceptors, 2}], active_echo_protocol, {}),
  90. Port2 = ranch:get_port({misc_info, act}),
  91. ranch:set_max_connections({misc_info, act}, infinity),
  92. Opts = ct_helper:get_certs_from_ets(),
  93. {ok, Pid3} = ranch:start_listener({misc_info, ssl},
  94. ranch_ssl, [{num_acceptors, 3}|Opts], echo_protocol, [{}]),
  95. Port3 = ranch:get_port({misc_info, ssl}),
  96. %% Open 5 connections, 3 removed from the count.
  97. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  98. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  99. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  100. receive after 250 -> ok end,
  101. ranch:set_protocol_options({misc_info, tcp}, [{remove, false, 2500}]),
  102. receive after 250 -> ok end,
  103. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  104. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  105. receive after 250 -> ok end,
  106. %% Confirm the info returned by Ranch is correct.
  107. [
  108. {{misc_info, act}, [
  109. {pid, Pid2},
  110. {status, _},
  111. {ip, _},
  112. {port, Port2},
  113. {num_acceptors, 2},
  114. {max_connections, infinity}, %% Option was modified.
  115. {active_connections, 0},
  116. {all_connections, 0},
  117. {transport, ranch_tcp},
  118. {transport_options, [{num_acceptors, 2}]},
  119. {protocol, active_echo_protocol},
  120. {protocol_options, {}}
  121. ]},
  122. {{misc_info, ssl}, [
  123. {pid, Pid3},
  124. {status, _},
  125. {ip, _},
  126. {port, Port3},
  127. {num_acceptors, 3},
  128. {max_connections, 1024},
  129. {active_connections, 0},
  130. {all_connections, 0},
  131. {transport, ranch_ssl},
  132. {transport_options, [{num_acceptors, 3}|Opts]},
  133. {protocol, echo_protocol},
  134. {protocol_options, [{}]}
  135. ]},
  136. {{misc_info, tcp}, [
  137. {pid, Pid1},
  138. {status, _},
  139. {ip, _},
  140. {port, Port1},
  141. {num_acceptors, 1},
  142. {max_connections, 1024},
  143. {active_connections, 2},
  144. {all_connections, 5},
  145. {transport, ranch_tcp},
  146. {transport_options, [{num_acceptors, 1}]},
  147. {protocol, remove_conn_and_wait_protocol},
  148. {protocol_options, [{remove, false, 2500}]} %% Option was modified.
  149. ]}
  150. ] = do_get_listener_info(misc_info),
  151. %% Get acceptors.
  152. [_] = ranch:procs({misc_info, tcp}, acceptors),
  153. [_, _] = ranch:procs({misc_info, act}, acceptors),
  154. [_, _, _] = ranch:procs({misc_info, ssl}, acceptors),
  155. %% Get connections.
  156. [_, _, _, _, _] = ranch:procs({misc_info, tcp}, connections),
  157. [] = ranch:procs({misc_info, act}, connections),
  158. [] = ranch:procs({misc_info, ssl}, connections),
  159. ok.
  160. misc_info_embedded(_) ->
  161. doc("Information about listeners in embedded mode."),
  162. {ok, SupPid} = embedded_sup:start_link(),
  163. %% Open a listener with a few connections.
  164. {ok, Pid1} = embedded_sup:start_listener(SupPid, {misc_info_embedded, tcp}, ranch_tcp, [{num_acceptors, 1}], remove_conn_and_wait_protocol, [{remove, true, 2500}]),
  165. Port1 = ranch:get_port({misc_info_embedded, tcp}),
  166. %% Open a few more listeners with different arguments.
  167. {ok, Pid2} = embedded_sup:start_listener(SupPid, {misc_info_embedded, act}, ranch_tcp, [{num_acceptors, 2}], active_echo_protocol, {}),
  168. Port2 = ranch:get_port({misc_info_embedded, act}),
  169. ranch:set_max_connections({misc_info_embedded, act}, infinity),
  170. Opts = ct_helper:get_certs_from_ets(),
  171. {ok, Pid3} = embedded_sup:start_listener(SupPid, {misc_info_embedded, ssl},
  172. ranch_ssl, [{num_acceptors, 3}|Opts], echo_protocol, [{}]),
  173. Port3 = ranch:get_port({misc_info_embedded, ssl}),
  174. %% Open 5 connections, 3 removed from the count.
  175. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  176. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  177. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  178. receive after 250 -> ok end,
  179. ranch:set_protocol_options({misc_info_embedded, tcp}, [{remove, false, 2500}]),
  180. receive after 250 -> ok end,
  181. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  182. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  183. receive after 250 -> ok end,
  184. %% Confirm the info returned by Ranch is correct.
  185. [
  186. {{misc_info_embedded, act}, [
  187. {pid, Pid2},
  188. {status, _},
  189. {ip, _},
  190. {port, Port2},
  191. {num_acceptors, 2},
  192. {max_connections, infinity}, %% Option was modified.
  193. {active_connections, 0},
  194. {all_connections, 0},
  195. {transport, ranch_tcp},
  196. {transport_options, [{num_acceptors, 2}]},
  197. {protocol, active_echo_protocol},
  198. {protocol_options, {}}
  199. ]},
  200. {{misc_info_embedded, ssl}, [
  201. {pid, Pid3},
  202. {status, _},
  203. {ip, _},
  204. {port, Port3},
  205. {num_acceptors, 3},
  206. {max_connections, 1024},
  207. {active_connections, 0},
  208. {all_connections, 0},
  209. {transport, ranch_ssl},
  210. {transport_options, [{num_acceptors, 3}|Opts]},
  211. {protocol, echo_protocol},
  212. {protocol_options, [{}]}
  213. ]},
  214. {{misc_info_embedded, tcp}, [
  215. {pid, Pid1},
  216. {status, _},
  217. {ip, _},
  218. {port, Port1},
  219. {num_acceptors, 1},
  220. {max_connections, 1024},
  221. {active_connections, 2},
  222. {all_connections, 5},
  223. {transport, ranch_tcp},
  224. {transport_options, [{num_acceptors, 1}]},
  225. {protocol, remove_conn_and_wait_protocol},
  226. {protocol_options, [{remove, false, 2500}]} %% Option was modified.
  227. ]}
  228. ] = do_get_listener_info(misc_info_embedded),
  229. %% Get acceptors.
  230. [_] = ranch:procs({misc_info_embedded, tcp}, acceptors),
  231. [_, _] = ranch:procs({misc_info_embedded, act}, acceptors),
  232. [_, _, _] = ranch:procs({misc_info_embedded, ssl}, acceptors),
  233. %% Get connections.
  234. [_, _, _, _, _] = ranch:procs({misc_info_embedded, tcp}, connections),
  235. [] = ranch:procs({misc_info_embedded, act}, connections),
  236. [] = ranch:procs({misc_info_embedded, ssl}, connections),
  237. %% Stop embedded tcp listener and ensure it is gone.
  238. ok = embedded_sup:stop_listener(SupPid, {misc_info_embedded, tcp}),
  239. timer:sleep(500),
  240. [{{misc_info_embedded, act}, _}, {{misc_info_embedded, ssl}, _}] =
  241. do_get_listener_info(misc_info_embedded),
  242. %% Stop embedded act listener and ensure it is gone.
  243. ok = embedded_sup:stop_listener(SupPid, {misc_info_embedded, act}),
  244. timer:sleep(500),
  245. [{{misc_info_embedded, ssl}, _}] =
  246. do_get_listener_info(misc_info_embedded),
  247. %% Stop embedded ssl listener and ensure it is gone.
  248. ok = embedded_sup:stop_listener(SupPid, {misc_info_embedded, ssl}),
  249. timer:sleep(500),
  250. [] = do_get_listener_info(misc_info_embedded),
  251. %% Stop embedded supervisor.
  252. embedded_sup:stop(SupPid),
  253. ok.
  254. do_get_listener_info(ListenerGroup) ->
  255. lists:sort([L || L={{G, _}, _} <- ranch:info(), G=:=ListenerGroup]).
  256. %% ssl.
  257. ssl_accept_error(_) ->
  258. doc("Acceptor must not crash if client disconnects in the middle of SSL handshake."),
  259. Name = name(),
  260. Opts = ct_helper:get_certs_from_ets(),
  261. {ok, ListenerSup} = ranch:start_listener(Name,
  262. ranch_ssl, [{num_acceptors, 1}|Opts], echo_protocol, []),
  263. Port = ranch:get_port(Name),
  264. ListenerSupChildren = supervisor:which_children(ListenerSup),
  265. {_, AcceptorsSup, _, _} = lists:keyfind(ranch_acceptors_sup, 1, ListenerSupChildren),
  266. [{{acceptor, _, _}, AcceptorPid, _, _}] = supervisor:which_children(AcceptorsSup),
  267. true = is_process_alive(AcceptorPid),
  268. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  269. ok = gen_tcp:close(Socket),
  270. receive after 500 -> ok end,
  271. true = is_process_alive(AcceptorPid),
  272. ok = ranch:stop_listener(Name).
  273. ssl_accept_socket(_) ->
  274. doc("Ensure that listener can use an externally opened SSL listen socket."),
  275. Name = name(),
  276. Opts = ct_helper:get_certs_from_ets(),
  277. {ok, S} = ssl:listen(0, [binary, {active, false}, {packet, raw}, {reuseaddr, true}|Opts]),
  278. {ok, _} = ranch:start_listener(Name, ranch_ssl, [{socket, S}], echo_protocol, []),
  279. Port = ranch:get_port(Name),
  280. {ok, Socket} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  281. ok = ssl:send(Socket, <<"TCP Ranch is working!">>),
  282. {ok, <<"TCP Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  283. ok = ranch:stop_listener(Name),
  284. {error, closed} = ssl:recv(Socket, 0, 1000),
  285. %% Make sure the listener stopped.
  286. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  287. ok.
  288. ssl_active_echo(_) ->
  289. doc("Ensure that active mode works with SSL transport."),
  290. Name = name(),
  291. Opts = ct_helper:get_certs_from_ets(),
  292. {ok, _} = ranch:start_listener(Name, ranch_ssl, Opts, active_echo_protocol, []),
  293. Port = ranch:get_port(Name),
  294. {ok, Socket} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  295. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  296. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  297. ok = ranch:stop_listener(Name),
  298. {error, closed} = ssl:recv(Socket, 0, 1000),
  299. %% Make sure the listener stopped.
  300. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  301. ok.
  302. ssl_echo(_) ->
  303. doc("Ensure that passive mode works with SSL transport."),
  304. Name = name(),
  305. Opts = ct_helper:get_certs_from_ets(),
  306. {ok, _} = ranch:start_listener(Name, ranch_ssl, Opts, echo_protocol, []),
  307. Port = ranch:get_port(Name),
  308. {ok, Socket} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  309. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  310. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  311. ok = ranch:stop_listener(Name),
  312. {error, closed} = ssl:recv(Socket, 0, 1000),
  313. %% Make sure the listener stopped.
  314. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  315. ok.
  316. ssl_sni_echo(_) ->
  317. case application:get_key(ssl, vsn) of
  318. {ok, Vsn} when Vsn >= "7.0" ->
  319. do_ssl_sni_echo();
  320. _ ->
  321. {skip, "No SNI support."}
  322. end.
  323. do_ssl_sni_echo() ->
  324. doc("Ensure that SNI works with SSL transport."),
  325. Name = name(),
  326. Opts = ct_helper:get_certs_from_ets(),
  327. {ok, _} = ranch:start_listener(Name, ranch_ssl, [{sni_hosts, [{"localhost", Opts}]}], echo_protocol, []),
  328. Port = ranch:get_port(Name),
  329. {ok, Socket} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  330. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  331. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  332. ok = ranch:stop_listener(Name),
  333. {error, closed} = ssl:recv(Socket, 0, 1000),
  334. %% Make sure the listener stopped.
  335. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  336. ok.
  337. ssl_sni_fail(_) ->
  338. case application:get_key(ssl, vsn) of
  339. {ok, Vsn} when Vsn >= "7.0" ->
  340. do_ssl_sni_fail();
  341. _ ->
  342. {skip, "No SNI support."}
  343. end.
  344. do_ssl_sni_fail() ->
  345. doc("Ensure that connection fails when host is not in SNI list."),
  346. Name = name(),
  347. Opts = ct_helper:get_certs_from_ets(),
  348. {ok, _} = ranch:start_listener(Name, ranch_ssl, [{sni_hosts, [{"pouet", Opts}]}], echo_protocol, []),
  349. Port = ranch:get_port(Name),
  350. {error, _} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  351. ok = ranch:stop_listener(Name),
  352. %% Make sure the listener stopped.
  353. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  354. ok.
  355. ssl_graceful(_) ->
  356. doc("Ensure suspending and resuming of listeners does not kill active connections."),
  357. Name = name(),
  358. Opts = ct_helper:get_certs_from_ets(),
  359. {ok, _} = ranch:start_listener(Name, ranch_ssl, Opts, echo_protocol, []),
  360. Port = ranch:get_port(Name),
  361. %% Make sure connections with a fresh listener work.
  362. running = ranch:get_status(Name),
  363. {ok, Socket1} = ssl:connect("localhost", Port,
  364. [binary, {active, false}, {packet, raw}]),
  365. ok = ssl:send(Socket1, <<"SSL with fresh listener">>),
  366. {ok, <<"SSL with fresh listener">>} = ssl:recv(Socket1, 23, 1000),
  367. %% Make sure transport options cannot be changed on a running listener.
  368. {error, running} = ranch:set_transport_options(Name, [{port, Port}|Opts]),
  369. %% Suspend listener, make sure established connections keep running.
  370. ok = ranch:suspend_listener(Name),
  371. suspended = ranch:get_status(Name),
  372. ok = ssl:send(Socket1, <<"SSL with suspended listener">>),
  373. {ok, <<"SSL with suspended listener">>} = ssl:recv(Socket1, 27, 1000),
  374. %% Make sure new connections are refused on the suspended listener.
  375. {error, econnrefused} = ssl:connect("localhost", Port,
  376. [binary, {active, false}, {packet, raw}]),
  377. %% Make sure transport options can be changed when listener is suspended.
  378. ok = ranch:set_transport_options(Name, [{port, Port}|Opts]),
  379. %% Resume listener, make sure connections can be established again.
  380. ok = ranch:resume_listener(Name),
  381. running = ranch:get_status(Name),
  382. {ok, Socket2} = ssl:connect("localhost", Port,
  383. [binary, {active, false}, {packet, raw}]),
  384. ok = ssl:send(Socket2, <<"SSL with resumed listener">>),
  385. {ok, <<"SSL with resumed listener">>} = ssl:recv(Socket2, 25, 1000),
  386. %% Make sure transport options cannot be changed on resumed listener.
  387. {error, running} = ranch:set_transport_options(Name, [{port, Port}|Opts]),
  388. ok = ranch:stop_listener(Name),
  389. {error, closed} = ssl:recv(Socket1, 0, 1000),
  390. {error, closed} = ssl:recv(Socket2, 0, 1000),
  391. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  392. ok.
  393. ssl_getopts_capability(_) ->
  394. doc("Ensure getopts/2 capability."),
  395. Name=name(),
  396. Opts=ct_helper:get_certs_from_ets(),
  397. {ok, _}=ranch:start_listener(Name, ranch_ssl, Opts, transport_capabilities_protocol, []),
  398. Port=ranch:get_port(Name),
  399. {ok, Socket}=ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  400. ok=ssl:send(Socket, <<"getopts/2">>),
  401. {ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
  402. ok=ranch:stop_listener(Name),
  403. {error, closed}=ssl:recv(Socket, 0, 1000),
  404. {'EXIT', _}=begin catch ranch:get_port(Name) end,
  405. ok.
  406. ssl_getstat_capability(_) ->
  407. case application:get_key(ssl, vsn) of
  408. {ok, Vsn} when Vsn>="8.0" ->
  409. do_ssl_getstat_capability();
  410. _ ->
  411. {skip, "No getstat/{1,2} support."}
  412. end.
  413. do_ssl_getstat_capability() ->
  414. doc("Ensure getstat/{1,2} capability."),
  415. Name=name(),
  416. Opts=ct_helper:get_certs_from_ets(),
  417. {ok, _}=ranch:start_listener(Name, ranch_ssl, Opts, transport_capabilities_protocol, []),
  418. Port=ranch:get_port(Name),
  419. {ok, Socket}=ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  420. ok=ssl:send(Socket, <<"getstat/1">>),
  421. {ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
  422. ok=ssl:send(Socket, <<"getstat/2">>),
  423. {ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
  424. ok=ranch:stop_listener(Name),
  425. {error, closed}=ssl:recv(Socket, 0, 1000),
  426. {'EXIT', _}=begin catch ranch:get_port(Name) end,
  427. ok.
  428. ssl_error_eaddrinuse(_) ->
  429. doc("Ensure that failure due to an eaddrinuse returns a compact readable error."),
  430. Name = name(),
  431. Opts = ct_helper:get_certs_from_ets(),
  432. {ok, _} = ranch:start_listener(Name, ranch_ssl, Opts, active_echo_protocol, []),
  433. Port = ranch:get_port(Name),
  434. {error, eaddrinuse} = ranch:start_listener({Name, fails},
  435. ranch_ssl, [{port, Port}|Opts], active_echo_protocol, []),
  436. ok = ranch:stop_listener(Name),
  437. %% Make sure the listener stopped.
  438. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  439. ok.
  440. ssl_error_no_cert(_) ->
  441. doc("Ensure that failure due to missing certificate returns a compact readable error."),
  442. {error, no_cert} = ranch:start_listener(name(), ranch_ssl, [], active_echo_protocol, []),
  443. ok.
  444. ssl_error_eacces(_) ->
  445. case os:type() of
  446. {win32, nt} ->
  447. doc("There are no privileged ports on Windows.");
  448. _ ->
  449. doc("Ensure that failure due to an eacces returns a compact readable error."),
  450. Name = name(),
  451. Opts = ct_helper:get_certs_from_ets(),
  452. {error, eacces} = ranch:start_listener(Name,
  453. ranch_ssl, [{port, 283}|Opts], active_echo_protocol, []),
  454. ok
  455. end.
  456. %% tcp.
  457. tcp_accept_socket(_) ->
  458. doc("Ensure that listener can use an externally opened TCP listen socket."),
  459. Name = name(),
  460. {ok, S} = gen_tcp:listen(0, [binary, {active, false}, {packet, raw}, {reuseaddr, true}]),
  461. {ok, _} = ranch:start_listener(Name, ranch_tcp, [{socket, S}], echo_protocol, []),
  462. Port = ranch:get_port(Name),
  463. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  464. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  465. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  466. ok = ranch:stop_listener(Name),
  467. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  468. %% Make sure the listener stopped.
  469. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  470. ok.
  471. tcp_active_echo(_) ->
  472. doc("Ensure that active mode works with TCP transport."),
  473. Name = name(),
  474. {ok, _} = ranch:start_listener(Name, ranch_tcp, [], active_echo_protocol, []),
  475. Port = ranch:get_port(Name),
  476. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  477. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  478. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  479. ok = ranch:stop_listener(Name),
  480. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  481. %% Make sure the listener stopped.
  482. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  483. ok.
  484. tcp_echo(_) ->
  485. doc("Ensure that passive mode works with TCP transport."),
  486. Name = name(),
  487. {ok, _} = ranch:start_listener(Name, ranch_tcp, [], echo_protocol, []),
  488. Port = ranch:get_port(Name),
  489. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  490. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  491. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  492. ok = ranch:stop_listener(Name),
  493. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  494. %% Make sure the listener stopped.
  495. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  496. ok.
  497. tcp_graceful(_) ->
  498. doc("Ensure suspending and resuming of listeners does not kill active connections."),
  499. Name = name(),
  500. {ok, _} = ranch:start_listener(Name, ranch_tcp, [], echo_protocol, []),
  501. Port = ranch:get_port(Name),
  502. %% Make sure connections with a fresh listener work.
  503. running = ranch:get_status(Name),
  504. {ok, Socket1} = gen_tcp:connect("localhost", Port,
  505. [binary, {active, false}, {packet, raw}]),
  506. ok = gen_tcp:send(Socket1, <<"TCP with fresh listener">>),
  507. {ok, <<"TCP with fresh listener">>} = gen_tcp:recv(Socket1, 23, 1000),
  508. %% Make sure transport options cannot be changed on a running listener.
  509. {error, running} = ranch:set_transport_options(Name, [{port, Port}]),
  510. %% Suspend listener, make sure established connections keep running.
  511. ok = ranch:suspend_listener(Name),
  512. suspended = ranch:get_status(Name),
  513. ok = gen_tcp:send(Socket1, <<"TCP with suspended listener">>),
  514. {ok, <<"TCP with suspended listener">>} = gen_tcp:recv(Socket1, 27, 1000),
  515. %% Make sure new connections are refused on the suspended listener.
  516. {error, econnrefused} = gen_tcp:connect("localhost", Port,
  517. [binary, {active, false}, {packet, raw}]),
  518. %% Make sure transport options can be changed when listener is suspended.
  519. ok = ranch:set_transport_options(Name, [{port, Port}]),
  520. %% Resume listener, make sure connections can be established again.
  521. ok = ranch:resume_listener(Name),
  522. running = ranch:get_status(Name),
  523. {ok, Socket2} = gen_tcp:connect("localhost", Port,
  524. [binary, {active, false}, {packet, raw}]),
  525. ok = gen_tcp:send(Socket2, <<"TCP with resumed listener">>),
  526. {ok, <<"TCP with resumed listener">>} = gen_tcp:recv(Socket2, 25, 1000),
  527. %% Make sure transport options cannot be changed on resumed listener.
  528. {error, running} = ranch:set_transport_options(Name, [{port, Port}]),
  529. ok = ranch:stop_listener(Name),
  530. {error, closed} = gen_tcp:recv(Socket1, 0, 1000),
  531. {error, closed} = gen_tcp:recv(Socket2, 0, 1000),
  532. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  533. ok.
  534. tcp_inherit_options(_) ->
  535. doc("Ensure TCP options are inherited in the protocol."),
  536. Name = name(),
  537. Opts = [{nodelay, false}, {send_timeout_close, false}],
  538. {ok, _} = ranch:start_listener(Name, ranch_tcp, Opts, check_tcp_options, [{pid, self()} | Opts]),
  539. Port = ranch:get_port(Name),
  540. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, true}, {packet, raw}]),
  541. receive checked -> ok after 1000 -> error(timeout) end,
  542. ok = gen_tcp:close(Socket),
  543. ok = ranch:stop_listener(Name).
  544. tcp_max_connections(_) ->
  545. doc("Ensure the max_connections option actually limits connections."),
  546. Name = name(),
  547. {ok, _} = ranch:start_listener(Name,
  548. ranch_tcp, [{max_connections, 10}, {num_acceptors, 1}],
  549. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  550. Port = ranch:get_port(Name),
  551. ok = connect_loop(Port, 11, 150),
  552. 10 = ranch_server:count_connections(Name),
  553. 10 = receive_loop(connected, 400),
  554. 1 = receive_loop(connected, 1000),
  555. ok = ranch:stop_listener(Name).
  556. tcp_max_connections_and_beyond(_) ->
  557. doc("Ensure the max_connections option works when connections are removed from the count."),
  558. Name = name(),
  559. {ok, _} = ranch:start_listener(Name,
  560. ranch_tcp, [{max_connections, 10}, {num_acceptors, 1}],
  561. remove_conn_and_wait_protocol, [{remove, true, 2500}]),
  562. Port = ranch:get_port(Name),
  563. ok = connect_loop(Port, 10, 0),
  564. receive after 250 -> ok end,
  565. 0 = ranch_server:count_connections(Name),
  566. 10 = length(supervisor:which_children(ranch_server:get_connections_sup(Name))),
  567. Counts = supervisor:count_children(ranch_server:get_connections_sup(Name)),
  568. {_, 1} = lists:keyfind(specs, 1, Counts),
  569. {_, 0} = lists:keyfind(supervisors, 1, Counts),
  570. {_, 10} = lists:keyfind(active, 1, Counts),
  571. {_, 10} = lists:keyfind(workers, 1, Counts),
  572. ranch:set_protocol_options(Name, [{remove, false, 2500}]),
  573. receive after 250 -> ok end,
  574. ok = connect_loop(Port, 10, 0),
  575. receive after 250 -> ok end,
  576. 10 = ranch_server:count_connections(Name),
  577. 20 = length(supervisor:which_children(ranch_server:get_connections_sup(Name))),
  578. Counts2 = supervisor:count_children(ranch_server:get_connections_sup(Name)),
  579. {_, 20} = lists:keyfind(active, 1, Counts2),
  580. {_, 20} = lists:keyfind(workers, 1, Counts2),
  581. ok = ranch:stop_listener(Name).
  582. tcp_max_connections_infinity(_) ->
  583. doc("Set the max_connections option from 10 to infinity and back to 10."),
  584. Name = name(),
  585. {ok, _} = ranch:start_listener(Name,
  586. ranch_tcp, [{max_connections, 10}, {num_acceptors, 1}],
  587. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  588. Port = ranch:get_port(Name),
  589. ok = connect_loop(Port, 20, 0),
  590. 10 = ranch_server:count_connections(Name),
  591. 10 = receive_loop(connected, 1000),
  592. 10 = ranch_server:count_connections(Name),
  593. 10 = ranch:get_max_connections(Name),
  594. ranch:set_max_connections(Name, infinity),
  595. receive after 250 -> ok end,
  596. 20 = ranch_server:count_connections(Name),
  597. infinity = ranch:get_max_connections(Name),
  598. ranch:set_max_connections(Name, 10),
  599. 20 = ranch_server:count_connections(Name),
  600. 10 = receive_loop(connected, 1000),
  601. ok = ranch:stop_listener(Name).
  602. tcp_remove_connections(_) ->
  603. doc("Ensure that removed connections are only removed once."),
  604. Name = name(),
  605. {ok, _} = ranch:start_listener(Name,
  606. ranch_tcp, [],
  607. remove_conn_and_wait_protocol, [{remove, true, 0}]),
  608. Port = ranch:get_port(Name),
  609. ok = connect_loop(Port, 10, 0),
  610. receive after 250 -> ok end,
  611. 0 = ranch_server:count_connections(Name),
  612. ok = ranch:stop_listener(Name).
  613. tcp_set_max_connections(_) ->
  614. doc("Ensure that changing the max_connections option to a larger value allows for more connections."),
  615. Name = name(),
  616. {ok, _} = ranch:start_listener(Name,
  617. ranch_tcp, [{max_connections, 10}, {num_acceptors, 1}],
  618. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  619. Port = ranch:get_port(Name),
  620. ok = connect_loop(Port, 20, 0),
  621. 10 = ranch_server:count_connections(Name),
  622. 10 = receive_loop(connected, 1000),
  623. 10 = ranch:get_max_connections(Name),
  624. ranch:set_max_connections(Name, 20),
  625. 10 = receive_loop(connected, 1000),
  626. 20 = ranch:get_max_connections(Name),
  627. ok = ranch:stop_listener(Name).
  628. tcp_set_max_connections_clean(Config) ->
  629. case code:is_module_native(?MODULE) of
  630. true -> doc("This test uses tracing and is not compatible with native code.");
  631. false -> do_tcp_set_max_connections_clean(Config)
  632. end.
  633. do_tcp_set_max_connections_clean(_) ->
  634. doc("Ensure that setting max_connections does not crash any process."),
  635. Name = name(),
  636. {ok, ListSupPid} = ranch:start_listener(Name, ranch_tcp,
  637. [{max_connections, 4}],
  638. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  639. Children = supervisor:which_children(ListSupPid),
  640. {_, AccSupPid, _, _} = lists:keyfind(ranch_acceptors_sup, 1, Children),
  641. 1 = erlang:trace(ListSupPid, true, [procs]),
  642. 1 = erlang:trace(AccSupPid, true, [procs]),
  643. Port = ranch:get_port(Name),
  644. N = 20,
  645. ok = connect_loop(Port, N*5, 0),
  646. %% Randomly set max_connections.
  647. [spawn(ranch, set_max_connections, [Name, Max]) ||
  648. Max <- lists:flatten(lists:duplicate(N, [6, 4, 8, infinity]))],
  649. receive
  650. {trace, _, spawn, _, _} ->
  651. error(dirty_set_max_connections)
  652. after
  653. 2000 -> ok
  654. end,
  655. _ = erlang:trace(all, false, [all]),
  656. ok = clean_traces(),
  657. ok = ranch:stop_listener(Name).
  658. tcp_getopts_capability(_) ->
  659. doc("Ensure getopts/2 capability."),
  660. Name=name(),
  661. {ok, _}=ranch:start_listener(Name, ranch_tcp, [], transport_capabilities_protocol, []),
  662. Port=ranch:get_port(Name),
  663. {ok, Socket}=gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  664. ok=gen_tcp:send(Socket, <<"getopts/2">>),
  665. {ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
  666. ok=ranch:stop_listener(Name),
  667. {error, closed}=gen_tcp:recv(Socket, 0, 1000),
  668. {'EXIT', _}=begin catch ranch:get_port(Name) end,
  669. ok.
  670. tcp_getstat_capability(_) ->
  671. doc("Ensure getstat/{1,2} capability."),
  672. Name=name(),
  673. {ok, _}=ranch:start_listener(Name, ranch_tcp, [], transport_capabilities_protocol, []),
  674. Port=ranch:get_port(Name),
  675. {ok, Socket}=gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  676. ok=gen_tcp:send(Socket, <<"getstat/1">>),
  677. {ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
  678. ok=gen_tcp:send(Socket, <<"getstat/2">>),
  679. {ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
  680. ok=ranch:stop_listener(Name),
  681. {error, closed}=gen_tcp:recv(Socket, 0, 1000),
  682. {'EXIT', _}=begin catch ranch:get_port(Name) end,
  683. ok.
  684. tcp_upgrade(_) ->
  685. doc("Ensure that protocol options can be updated."),
  686. Name = name(),
  687. {ok, _} = ranch:start_listener(Name,
  688. ranch_tcp, [],
  689. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  690. Port = ranch:get_port(Name),
  691. ok = connect_loop(Port, 1, 0),
  692. receive connected -> ok after 1000 -> error(timeout) end,
  693. ranch:set_protocol_options(Name, [{msg, upgraded}, {pid, self()}]),
  694. ok = connect_loop(Port, 1, 0),
  695. receive upgraded -> ok after 1000 -> error(timeout) end,
  696. ok = ranch:stop_listener(Name).
  697. tcp_error_eaddrinuse(_) ->
  698. doc("Ensure that failure due to an eaddrinuse returns a compact readable error."),
  699. Name = name(),
  700. {ok, _} = ranch:start_listener(Name, ranch_tcp, [], active_echo_protocol, []),
  701. Port = ranch:get_port(Name),
  702. {error, eaddrinuse} = ranch:start_listener({Name, fails},
  703. ranch_tcp, [{port, Port}], active_echo_protocol, []),
  704. ok = ranch:stop_listener(Name),
  705. %% Make sure the listener stopped.
  706. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  707. ok.
  708. tcp_error_eacces(_) ->
  709. case os:type() of
  710. {win32, nt} ->
  711. doc("There are no privileged ports on Windows.");
  712. _ ->
  713. doc("Ensure that failure due to an eacces returns a compact readable error."),
  714. Name = name(),
  715. {error, eacces} = ranch:start_listener(Name,
  716. ranch_tcp, [{port, 283}], active_echo_protocol, []),
  717. ok
  718. end.
  719. %% Supervisor tests
  720. connection_type_supervisor(_) ->
  721. doc("The supervisor connection type must be reflected in the specifications."),
  722. Name = name(),
  723. {ok, _} = ranch:start_listener(Name,
  724. ranch_tcp, [{connection_type, supervisor}],
  725. echo_protocol, []),
  726. Port = ranch:get_port(Name),
  727. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  728. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  729. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  730. ConnsSup = ranch_server:get_connections_sup(Name),
  731. [{echo_protocol, _, supervisor, [echo_protocol]}] = supervisor:which_children(ConnsSup),
  732. ok = ranch:stop_listener(Name),
  733. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  734. %% Make sure the listener stopped.
  735. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  736. ok.
  737. connection_type_supervisor_separate_from_connection(_) ->
  738. doc("The supervisor connection type allows separate supervised and connection processes."),
  739. Name = name(),
  740. {ok, _} = ranch:start_listener(Name,
  741. ranch_tcp, [{connection_type, supervisor}],
  742. supervisor_separate, []),
  743. Port = ranch:get_port(Name),
  744. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  745. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  746. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  747. ConnsSup = ranch_server:get_connections_sup(Name),
  748. [{supervisor_separate, _, supervisor, [supervisor_separate]}] = supervisor:which_children(ConnsSup),
  749. ok = ranch:stop_listener(Name),
  750. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  751. %% Make sure the listener stopped.
  752. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  753. ok.
  754. supervisor_changed_options_restart(_) ->
  755. doc("Ensure that a listener is restarted with changed transport options."),
  756. Name = name(),
  757. %% Start a listener using send_timeout as option change marker.
  758. {ok, ListenerSupPid1} = ranch:start_listener(Name,
  759. ranch_tcp, [{send_timeout, 300000}],
  760. echo_protocol, []),
  761. %% Ensure send_timeout is really set to initial value.
  762. {ok, [{send_timeout, 300000}]}
  763. = inet:getopts(do_get_listener_socket(ListenerSupPid1), [send_timeout]),
  764. %% Change send_timeout option.
  765. ok = ranch:suspend_listener(Name),
  766. ok = ranch:set_transport_options(Name, [{send_timeout, 300001}]),
  767. ok = ranch:resume_listener(Name),
  768. %% Ensure send_timeout is really set to the changed value.
  769. {ok, [{send_timeout, 300001}]}
  770. = inet:getopts(do_get_listener_socket(ListenerSupPid1), [send_timeout]),
  771. %% Crash the listener_sup process, allow a short time for restart to succeed.
  772. exit(ListenerSupPid1, kill),
  773. timer:sleep(1000),
  774. %% Obtain pid of restarted listener_sup process.
  775. [ListenerSupPid2] = [Pid || {{ranch_listener_sup, Ref}, Pid, supervisor, _}
  776. <- supervisor:which_children(ranch_sup), Ref =:= Name],
  777. %% Ensure send_timeout is still set to the changed value.
  778. {ok, [{send_timeout, 300001}]}
  779. = inet:getopts(do_get_listener_socket(ListenerSupPid2), [send_timeout]),
  780. ok = ranch:stop_listener(Name),
  781. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  782. ok.
  783. supervisor_clean_child_restart(Config) ->
  784. case code:is_module_native(?MODULE) of
  785. true -> doc("This test uses tracing and is not compatible with native code.");
  786. false -> do_supervisor_clean_child_restart(Config)
  787. end.
  788. do_supervisor_clean_child_restart(_) ->
  789. doc("Verify that only the relevant parts of the supervision tree restarted "
  790. "when the listening socket is closed."),
  791. Name = name(),
  792. %% Trace socket allocations.
  793. _ = erlang:trace(new, true, [call]),
  794. 1 = erlang:trace_pattern({ranch_tcp, listen, 1},
  795. [{'_', [], [{return_trace}]}], [global]),
  796. {ok, Pid} = ranch:start_listener(Name,
  797. ranch_tcp, [{num_acceptors, 1}], echo_protocol, []),
  798. %% Trace supervisor spawns.
  799. 1 = erlang:trace(Pid, true, [procs, set_on_spawn]),
  800. ConnsSup = ranch_server:get_connections_sup(Name),
  801. %% Manually shut the listening socket down.
  802. LSocket = receive
  803. {trace, _, return_from, {ranch_tcp, listen, 1}, {ok, Socket}} ->
  804. Socket
  805. after 0 ->
  806. error(lsocket_unknown)
  807. end,
  808. ok = gen_tcp:close(LSocket),
  809. receive after 1000 -> ok end,
  810. %% Verify that supervisor and its first two children are alive.
  811. true = is_process_alive(Pid),
  812. true = is_process_alive(ConnsSup),
  813. %% Check that acceptors_sup is restarted properly.
  814. AccSupPid = receive {trace, Pid, spawn, Pid1, _} -> Pid1 end,
  815. receive {trace, AccSupPid, spawn, _, _} -> ok end,
  816. %% No more traces then.
  817. receive
  818. {trace, _, spawn, _, _} -> error(invalid_restart)
  819. after 1000 -> ok end,
  820. %% Verify that children still registered right.
  821. ConnsSup = ranch_server:get_connections_sup(Name),
  822. _ = erlang:trace_pattern({ranch_tcp, listen, 1}, false, []),
  823. _ = erlang:trace(all, false, [all]),
  824. ok = clean_traces(),
  825. ok = ranch:stop_listener(Name).
  826. supervisor_clean_conns_sup_restart(_) ->
  827. doc("Verify that a conns_sup can not register with the same name as an already "
  828. "registered ranch_conns_sup that is still alive. Make sure this does not crash "
  829. "the ranch_server process."),
  830. Name = name(),
  831. {ok, _} = ranch:start_listener(Name,
  832. ranch_tcp, [], echo_protocol, []),
  833. Server = erlang:whereis(ranch_server),
  834. ServerMonRef = erlang:monitor(process, Server),
  835. %% Exit because Name already registered and is alive.
  836. {'EXIT', _} = (catch ranch_server:set_connections_sup(Name, self())),
  837. receive
  838. {'DOWN', ServerMonRef, process, Server, _} ->
  839. error(ranch_server_down)
  840. after
  841. 1000 ->
  842. ok
  843. end,
  844. ok = ranch:stop_listener(Name).
  845. supervisor_clean_restart(Config) ->
  846. case code:is_module_native(?MODULE) of
  847. true -> doc("This test uses tracing and is not compatible with native code.");
  848. false -> do_supervisor_clean_restart(Config)
  849. end.
  850. do_supervisor_clean_restart(_) ->
  851. doc("Verify that killing ranch_conns_sup does not crash everything "
  852. "and that it restarts properly."),
  853. Name = name(),
  854. NumAcc = 4,
  855. {ok, Pid} = ranch:start_listener(Name,
  856. ranch_tcp, [{num_acceptors, NumAcc}], echo_protocol, []),
  857. %% Trace supervisor spawns.
  858. 1 = erlang:trace(Pid, true, [procs, set_on_spawn]),
  859. ConnsSup0 = ranch_server:get_connections_sup(Name),
  860. erlang:exit(ConnsSup0, kill),
  861. receive after 1000 -> ok end,
  862. %% Verify that supervisor is alive
  863. true = is_process_alive(Pid),
  864. %% ...but children are dead.
  865. false = is_process_alive(ConnsSup0),
  866. %% Receive traces from newly started children
  867. ConnsSup = receive {trace, Pid, spawn, Pid2, _} -> Pid2 end,
  868. AccSupPid = receive {trace, Pid, spawn, Pid3, _} -> Pid3 end,
  869. %% ...and its acceptors.
  870. [receive {trace, AccSupPid, spawn, _Pid, _} -> ok end ||
  871. _ <- lists:seq(1, NumAcc)],
  872. %% No more traces then.
  873. receive
  874. {trace, EPid, spawn, _, _} when EPid == Pid; EPid == AccSupPid ->
  875. error(invalid_restart)
  876. after 1000 -> ok end,
  877. %% Verify that new children registered themselves properly.
  878. ConnsSup = ranch_server:get_connections_sup(Name),
  879. _ = erlang:trace(all, false, [all]),
  880. ok = clean_traces(),
  881. ok = ranch:stop_listener(Name).
  882. supervisor_conns_alive(Config) ->
  883. case code:is_module_native(?MODULE) of
  884. true -> doc("This test uses tracing and is not compatible with native code.");
  885. false -> do_supervisor_conns_alive(Config)
  886. end.
  887. do_supervisor_conns_alive(_) ->
  888. doc("Ensure that active connections stay open when the listening socket gets closed."),
  889. Name = name(),
  890. _ = erlang:trace(new, true, [call]),
  891. 1 = erlang:trace_pattern({ranch_tcp, listen, 1},
  892. [{'_', [], [{return_trace}]}], [global]),
  893. {ok, _} = ranch:start_listener(Name,
  894. ranch_tcp, [],
  895. remove_conn_and_wait_protocol, [{remove, false, 2500}]),
  896. %% Get the listener socket
  897. LSocket = receive
  898. {trace, _, return_from, {ranch_tcp, listen, 1}, {ok, S}} ->
  899. S
  900. after 500 ->
  901. error(lsocket_unknown)
  902. end,
  903. TcpPort = ranch:get_port(Name),
  904. {ok, Socket} = gen_tcp:connect("localhost", TcpPort,
  905. [binary, {active, true}, {packet, raw}]),
  906. receive after 500 -> ok end,
  907. %% Shut the socket down
  908. ok = gen_tcp:close(LSocket),
  909. %% Assert that client is still viable.
  910. receive {tcp_closed, _} -> error(closed) after 1500 -> ok end,
  911. ok = gen_tcp:send(Socket, <<"poke">>),
  912. receive {tcp_closed, _} -> ok end,
  913. _ = erlang:trace(all, false, [all]),
  914. ok = clean_traces(),
  915. ok = ranch:stop_listener(Name).
  916. supervisor_protocol_start_link_crash(_) ->
  917. doc("Ensure a protocol start crash does not kill all connections."),
  918. Name = name(),
  919. {ok, _} = ranch:start_listener(Name, ranch_tcp, [], crash_protocol, []),
  920. ConnsSup = ranch_server:get_connections_sup(Name),
  921. Port = ranch:get_port(Name),
  922. {ok, _} = gen_tcp:connect("localhost", Port, [binary, {active, true}, {packet, raw}]),
  923. receive after 500 -> ok end,
  924. ConnsSup = ranch_server:get_connections_sup(Name),
  925. ok = ranch:stop_listener(Name).
  926. supervisor_server_recover_state(Config) ->
  927. case code:is_module_native(?MODULE) of
  928. true -> doc("This test uses tracing and is not compatible with native code.");
  929. false -> do_supervisor_server_recover_state(Config)
  930. end.
  931. do_supervisor_server_recover_state(_) ->
  932. doc("Ensure that when ranch_server crashes and restarts, it recovers "
  933. "its state and continues monitoring the same processes."),
  934. Name = name(),
  935. _ = erlang:trace(new, true, [call]),
  936. 1 = erlang:trace_pattern({ranch_server, init, 1},
  937. [{'_', [], [{return_trace}]}], [global]),
  938. {ok, _} = ranch:start_listener(Name, ranch_tcp, [], echo_protocol, []),
  939. ConnsSup = ranch_server:get_connections_sup(Name),
  940. ServerPid = erlang:whereis(ranch_server),
  941. {monitors, Monitors} = erlang:process_info(ServerPid, monitors),
  942. erlang:exit(ServerPid, kill),
  943. receive
  944. {trace, ServerPid2, return_from, {ranch_server, init, 1}, _Result} ->
  945. {monitors, Monitors2} = erlang:process_info(ServerPid2, monitors),
  946. %% Check that ranch_server is monitoring the same processes.
  947. true = (lists:usort(Monitors) == lists:usort(Monitors2))
  948. after
  949. 1000 ->
  950. error(timeout)
  951. end,
  952. ConnsSup = ranch_server:get_connections_sup(Name),
  953. ok = ranch:stop_listener(Name),
  954. %% Check ranch_server has removed the ranch_conns_sup.
  955. {'EXIT', {badarg, _}} = (catch ranch_server:get_connections_sup(Name)),
  956. _ = erlang:trace(all, false, [all]),
  957. ok = clean_traces().
  958. supervisor_unexpected_message(_) ->
  959. doc("Ensure the connections supervisor stays alive when it receives "
  960. "an unexpected message."),
  961. Name = name(),
  962. {ok, ListenerPid} = ranch:start_listener(Name, ranch_tcp, [], echo_protocol, []),
  963. Port = ranch:get_port(Name),
  964. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  965. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  966. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  967. %% Send the unexpected message to ranch_conns_sup.
  968. Procs = supervisor:which_children(ListenerPid),
  969. {_, ConnsSup, _, _} = lists:keyfind(ranch_conns_sup, 1, Procs),
  970. ConnsSup ! hello,
  971. %% Connection is still up.
  972. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  973. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  974. ok = ranch:stop_listener(Name),
  975. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  976. %% Make sure the listener stopped.
  977. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  978. ok.
  979. %% Utility functions.
  980. connect_loop(_, 0, _) ->
  981. ok;
  982. connect_loop(Port, N, Sleep) ->
  983. {ok, _} = gen_tcp:connect("localhost", Port,
  984. [binary, {active, false}, {packet, raw}]),
  985. receive after Sleep -> ok end,
  986. connect_loop(Port, N - 1, Sleep).
  987. receive_loop(Message, Timeout) ->
  988. receive_loop(Message, Timeout, 0).
  989. receive_loop(Message, Timeout, N) ->
  990. receive Message ->
  991. receive_loop(Message, Timeout, N + 1)
  992. after Timeout ->
  993. N
  994. end.
  995. clean_traces() ->
  996. receive
  997. {trace, _, _, _} ->
  998. clean_traces();
  999. {trace, _, _, _, _} ->
  1000. clean_traces()
  1001. after 0 ->
  1002. ok
  1003. end.
  1004. do_get_listener_socket(ListenerSupPid) ->
  1005. [AcceptorsSupPid] = [Pid || {ranch_acceptors_sup, Pid, supervisor, _}
  1006. <- supervisor:which_children(ListenerSupPid)],
  1007. {links, Links} = erlang:process_info(AcceptorsSupPid, links),
  1008. [LSocket] = [P || P <- Links, is_port(P)],
  1009. LSocket.