acceptor_SUITE.erl 45 KB

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