acceptor_SUITE.erl 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676
  1. %% Copyright (c) 2011-2020, Loïc Hoguin <essen@ninenines.eu>
  2. %% Copyright (c) 2020, Jan Uhlig <j.uhlig@mailingwork.de>
  3. %%
  4. %% Permission to use, copy, modify, and/or distribute this software for any
  5. %% purpose with or without fee is hereby granted, provided that the above
  6. %% copyright notice and this permission notice appear in all copies.
  7. %%
  8. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. -module(acceptor_SUITE).
  16. -compile(export_all).
  17. -compile(nowarn_export_all).
  18. -dialyzer({nowarn_function, misc_wait_for_connections/1}).
  19. %% @todo Remove when specs in ssl are updated to accept local addresses.
  20. -dialyzer({nowarn_function, do_ssl_local_echo/0}).
  21. -import(ct_helper, [doc/1]).
  22. -import(ct_helper, [name/0]).
  23. %% ct.
  24. all() ->
  25. [{group, tcp}, {group, ssl}, {group, misc}, {group, supervisor}].
  26. groups() ->
  27. [{tcp, [
  28. tcp_active_echo,
  29. tcp_active_n_echo,
  30. tcp_echo,
  31. tcp_local_echo,
  32. tcp_graceful,
  33. tcp_inherit_options,
  34. tcp_max_connections,
  35. tcp_max_connections_and_beyond,
  36. tcp_max_connections_infinity,
  37. tcp_remove_connections,
  38. tcp_remove_connections_acceptor_wakeup,
  39. tcp_set_max_connections,
  40. tcp_set_max_connections_clean,
  41. tcp_getopts_capability,
  42. tcp_getstat_capability,
  43. tcp_upgrade,
  44. tcp_10_acceptors_10_listen_sockets,
  45. tcp_many_listen_sockets_no_reuseport,
  46. tcp_error_eaddrinuse,
  47. tcp_error_eacces
  48. ]}, {ssl, [
  49. ssl_accept_error,
  50. ssl_active_echo,
  51. ssl_active_n_echo,
  52. ssl_echo,
  53. ssl_local_echo,
  54. ssl_graceful,
  55. ssl_handshake,
  56. ssl_sni_echo,
  57. ssl_sni_fail,
  58. ssl_upgrade_from_tcp,
  59. ssl_getopts_capability,
  60. ssl_getstat_capability,
  61. ssl_10_acceptors_10_listen_sockets,
  62. ssl_many_listen_sockets_no_reuseport,
  63. ssl_error_eaddrinuse,
  64. ssl_error_no_cert,
  65. ssl_error_eacces
  66. ]}, {misc, [
  67. misc_bad_transport,
  68. misc_bad_transport_options,
  69. misc_repeated_remove,
  70. misc_info,
  71. misc_info_embedded,
  72. misc_metrics,
  73. misc_opts_logger,
  74. misc_post_listen_callback,
  75. misc_post_listen_callback_error,
  76. misc_set_transport_options,
  77. misc_wait_for_connections,
  78. misc_multiple_ip_local_socket_opts
  79. ]}, {supervisor, [
  80. connection_type_supervisor,
  81. connection_type_supervisor_separate_from_connection,
  82. supervisor_10_acceptors_1_conns_sup,
  83. supervisor_9_acceptors_4_conns_sups,
  84. supervisor_10_acceptors_10_conns_sups,
  85. supervisor_1_acceptor_10_conns_sups,
  86. supervisor_changed_options_restart,
  87. supervisor_clean_child_restart,
  88. supervisor_clean_restart,
  89. supervisor_conns_alive,
  90. supervisor_embedded_ranch_server_crash,
  91. supervisor_protocol_start_link_crash,
  92. supervisor_server_recover_state,
  93. supervisor_unexpected_message
  94. ]}].
  95. %% misc.
  96. misc_bad_transport(_) ->
  97. doc("Reject invalid transport modules."),
  98. {error, {bad_transport, invalid_transport}} = ranch:start_listener(misc_bad_transport,
  99. invalid_transport, #{},
  100. echo_protocol, []),
  101. ok.
  102. misc_bad_transport_options(_) ->
  103. doc("Ignore invalid transport options."),
  104. {ok, _} = ranch:start_listener(misc_bad_transport_options,
  105. ranch_tcp, [binary, {packet, 4}, <<"garbage">>, raw, backlog],
  106. echo_protocol, []),
  107. ok.
  108. misc_info(_) ->
  109. doc("Information about listeners."),
  110. %% Open a listener with a few connections.
  111. {ok, Pid1} = ranch:start_listener({misc_info, tcp},
  112. ranch_tcp, #{num_acceptors => 1},
  113. remove_conn_and_wait_protocol, [{remove, true, 2500}]),
  114. Port1 = ranch:get_port({misc_info, tcp}),
  115. %% Open a few more listeners with different arguments.
  116. {ok, Pid2} = ranch:start_listener({misc_info, act},
  117. ranch_tcp, #{num_acceptors => 2},
  118. active_echo_protocol, {}),
  119. Port2 = ranch:get_port({misc_info, act}),
  120. ranch:set_max_connections({misc_info, act}, infinity),
  121. Opts = ct_helper:get_certs_from_ets(),
  122. {ok, Pid3} = ranch:start_listener({misc_info, ssl},
  123. ranch_ssl, #{num_acceptors => 3, socket_opts => Opts},
  124. echo_protocol, [{}]),
  125. Port3 = ranch:get_port({misc_info, ssl}),
  126. %% Open 5 connections, 3 removed from the count.
  127. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  128. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  129. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  130. receive after 250 -> ok end,
  131. ranch:set_protocol_options({misc_info, tcp}, [{remove, false, 2500}]),
  132. receive after 250 -> ok end,
  133. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  134. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  135. receive after 250 -> ok end,
  136. %% Confirm the info returned by Ranch is correct.
  137. #{
  138. {misc_info, act} := #{
  139. pid := Pid2,
  140. port := Port2,
  141. max_connections := infinity, %% Option was modified.
  142. active_connections := 0,
  143. all_connections := 0,
  144. transport := ranch_tcp,
  145. transport_options := #{num_acceptors := 2},
  146. protocol := active_echo_protocol,
  147. protocol_options := {}
  148. },
  149. {misc_info, ssl} := #{
  150. pid := Pid3,
  151. port := Port3,
  152. max_connections := 1024,
  153. active_connections := 0,
  154. all_connections := 0,
  155. transport := ranch_ssl,
  156. transport_options := #{num_acceptors := 3, socket_opts := Opts},
  157. protocol := echo_protocol,
  158. protocol_options := [{}]
  159. },
  160. {misc_info, tcp} := #{
  161. pid := Pid1,
  162. port := Port1,
  163. max_connections := 1024,
  164. active_connections := 2,
  165. all_connections := 5,
  166. transport := ranch_tcp,
  167. transport_options := #{num_acceptors := 1},
  168. protocol := remove_conn_and_wait_protocol,
  169. protocol_options := [{remove, false, 2500}] %% Option was modified.
  170. }
  171. } = ranch:info(),
  172. %% Get acceptors.
  173. [_] = ranch:procs({misc_info, tcp}, acceptors),
  174. [_, _] = ranch:procs({misc_info, act}, acceptors),
  175. [_, _, _] = ranch:procs({misc_info, ssl}, acceptors),
  176. %% Get connections.
  177. [_, _, _, _, _] = ranch:procs({misc_info, tcp}, connections),
  178. [] = ranch:procs({misc_info, act}, connections),
  179. [] = ranch:procs({misc_info, ssl}, connections),
  180. ok.
  181. misc_info_embedded(_) ->
  182. doc("Information about listeners in embedded mode."),
  183. {ok, SupPid} = embedded_sup:start_link(),
  184. %% Open a listener with a few connections.
  185. {ok, EmbeddedSupPid1} = embedded_sup:start_listener(SupPid, {misc_info_embedded, tcp},
  186. ranch_tcp, #{num_acceptors => 1},
  187. remove_conn_and_wait_protocol, [{remove, true, 2500}]),
  188. {_, Pid1, _, _} = lists:keyfind({ranch_listener_sup, {misc_info_embedded, tcp}}, 1,
  189. supervisor:which_children(EmbeddedSupPid1)),
  190. Port1 = ranch:get_port({misc_info_embedded, tcp}),
  191. %% Open a few more listeners with different arguments.
  192. {ok, EmbeddedSupPid2} = embedded_sup:start_listener(SupPid, {misc_info_embedded, act},
  193. ranch_tcp, #{num_acceptors => 2},
  194. active_echo_protocol, {}),
  195. {_, Pid2, _, _} = lists:keyfind({ranch_listener_sup, {misc_info_embedded, act}}, 1,
  196. supervisor:which_children(EmbeddedSupPid2)),
  197. Port2 = ranch:get_port({misc_info_embedded, act}),
  198. ranch:set_max_connections({misc_info_embedded, act}, infinity),
  199. Opts = ct_helper:get_certs_from_ets(),
  200. {ok, EmbeddedSupPid3} = embedded_sup:start_listener(SupPid, {misc_info_embedded, ssl},
  201. ranch_ssl, #{num_acceptors => 3, socket_opts => Opts},
  202. echo_protocol, [{}]),
  203. {_, Pid3, _, _} = lists:keyfind({ranch_listener_sup, {misc_info_embedded, ssl}}, 1,
  204. supervisor:which_children(EmbeddedSupPid3)),
  205. Port3 = ranch:get_port({misc_info_embedded, ssl}),
  206. %% Open 5 connections, 3 removed from the count.
  207. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  208. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  209. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  210. receive after 250 -> ok end,
  211. ranch:set_protocol_options({misc_info_embedded, tcp}, [{remove, false, 2500}]),
  212. receive after 250 -> ok end,
  213. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  214. {ok, _} = gen_tcp:connect("localhost", Port1, [binary, {active, false}, {packet, raw}]),
  215. receive after 250 -> ok end,
  216. %% Confirm the info returned by Ranch is correct.
  217. #{
  218. {misc_info_embedded, act} := #{
  219. pid := Pid2,
  220. port := Port2,
  221. max_connections := infinity, %% Option was modified.
  222. active_connections := 0,
  223. all_connections := 0,
  224. transport := ranch_tcp,
  225. transport_options := #{num_acceptors := 2},
  226. protocol := active_echo_protocol,
  227. protocol_options := {}
  228. },
  229. {misc_info_embedded, ssl} := #{
  230. pid := Pid3,
  231. port := Port3,
  232. max_connections := 1024,
  233. active_connections := 0,
  234. all_connections := 0,
  235. transport := ranch_ssl,
  236. transport_options := #{num_acceptors := 3, socket_opts := Opts},
  237. protocol := echo_protocol,
  238. protocol_options := [{}]
  239. },
  240. {misc_info_embedded, tcp} := #{
  241. pid := Pid1,
  242. port := Port1,
  243. max_connections := 1024,
  244. active_connections := 2,
  245. all_connections := 5,
  246. transport := ranch_tcp,
  247. transport_options := #{num_acceptors := 1},
  248. protocol := remove_conn_and_wait_protocol,
  249. protocol_options := [{remove, false, 2500}] %% Option was modified.
  250. }
  251. } = ranch:info(),
  252. %% Get acceptors.
  253. [_] = ranch:procs({misc_info_embedded, tcp}, acceptors),
  254. [_, _] = ranch:procs({misc_info_embedded, act}, acceptors),
  255. [_, _, _] = ranch:procs({misc_info_embedded, ssl}, acceptors),
  256. %% Get connections.
  257. [_, _, _, _, _] = ranch:procs({misc_info_embedded, tcp}, connections),
  258. [] = ranch:procs({misc_info_embedded, act}, connections),
  259. [] = ranch:procs({misc_info_embedded, ssl}, connections),
  260. %% Stop embedded tcp listener and ensure it is gone.
  261. ok = embedded_sup:stop_listener(SupPid, {misc_info_embedded, tcp}),
  262. timer:sleep(500),
  263. false = maps:is_key({misc_info_embedded, tcp}, ranch:info()),
  264. %% Stop embedded act listener and ensure it is gone.
  265. ok = embedded_sup:stop_listener(SupPid, {misc_info_embedded, act}),
  266. timer:sleep(500),
  267. false = maps:is_key({misc_info_embedded, act}, ranch:info()),
  268. %% Stop embedded ssl listener and ensure it is gone.
  269. ok = embedded_sup:stop_listener(SupPid, {misc_info_embedded, ssl}),
  270. timer:sleep(500),
  271. false = maps:is_key({misc_info_embedded, ssl}, ranch:info()),
  272. %% Stop embedded supervisor.
  273. embedded_sup:stop(SupPid),
  274. ok.
  275. misc_metrics(_) ->
  276. doc("Confirm accept/terminate metrics are correct."),
  277. Name = name(),
  278. {ok, _} = ranch:start_listener(Name, ranch_tcp, #{},
  279. notify_and_wait_protocol, #{pid => self()}),
  280. Port = ranch:get_port(Name),
  281. %% Start 10 connections.
  282. ok = connect_loop(Port, 10, 0),
  283. {10, ConnPids1} = receive_loop(connected, 400),
  284. #{metrics := Metrics1} = ranch:info(Name),
  285. {10, 0} = do_accumulate_metrics(Metrics1),
  286. %% Start 10 more connections.
  287. ok = connect_loop(Port, 10, 0),
  288. {10, ConnPids2} = receive_loop(connected, 400),
  289. #{metrics := Metrics2} = ranch:info(Name),
  290. {20, 0} = do_accumulate_metrics(Metrics2),
  291. %% Terminate 10 connections.
  292. ok = terminate_loop(stop, ConnPids2),
  293. timer:sleep(100),
  294. #{metrics := Metrics3} = ranch:info(Name),
  295. {20, 10} = do_accumulate_metrics(Metrics3),
  296. %% Terminate 10 more connections.
  297. ok = terminate_loop(stop, ConnPids1),
  298. timer:sleep(100),
  299. #{metrics := Metrics4} = ranch:info(Name),
  300. {20, 20} = do_accumulate_metrics(Metrics4),
  301. ok = ranch:stop_listener(Name),
  302. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  303. ok.
  304. do_accumulate_metrics(Metrics) ->
  305. maps:fold(
  306. fun
  307. ({conns_sup, _, accept}, N, {Accepts, Terminates}) ->
  308. {Accepts+N, Terminates};
  309. ({conns_sup, _, terminate}, N, {Accepts, Terminates}) ->
  310. {Accepts, Terminates+N}
  311. end,
  312. {0, 0},
  313. Metrics
  314. ).
  315. misc_opts_logger(_) ->
  316. doc("Confirm that messages are sent via the configured logger module."),
  317. register(misc_opts_logger, self()),
  318. {ok, _} = ranch:start_listener(name(),
  319. ranch_tcp, #{logger => ?MODULE, socket_opts => [<<"garbage">>]},
  320. echo_protocol, []),
  321. receive
  322. {warning, "Transport option " ++ _, [<<"garbage">>]} ->
  323. ok
  324. after 1000 ->
  325. error(timeout)
  326. end.
  327. warning(Format, Args) ->
  328. misc_opts_logger ! {warning, Format, Args}.
  329. misc_post_listen_callback(_) ->
  330. doc("Ensure that the post-listen callback works."),
  331. Name = name(),
  332. Self = self(),
  333. Ref = make_ref(),
  334. PostListenCb = fun (LSock) ->
  335. ok = ranch_tcp:setopts(LSock, [{send_timeout, 1000}]),
  336. Self ! {post_listen, Ref, LSock},
  337. ok
  338. end,
  339. {ok, _} = ranch:start_listener(Name,
  340. ranch_tcp, #{post_listen_callback => PostListenCb,
  341. socket_opts => [{send_timeout, infinity}]},
  342. echo_protocol, []),
  343. receive
  344. {post_listen, Ref, LSock} ->
  345. {ok, [{send_timeout, 1000}]} = ranch_tcp:getopts(LSock, [send_timeout]),
  346. ok
  347. after 1000 ->
  348. error(timeout)
  349. end,
  350. Port = ranch:get_port(Name),
  351. {ok, S} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  352. ok = gen_tcp:send(S, <<"Test">>),
  353. {ok, <<"Test">>} = gen_tcp:recv(S, 4, 1000),
  354. ok = ranch:stop_listener(Name),
  355. {error, closed} = gen_tcp:recv(S, 0, 1000),
  356. %% Make sure the listener stopped.
  357. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  358. ok.
  359. misc_post_listen_callback_error(_) ->
  360. doc("Ensure that starting a listener fails when the post-listen callback returns an error."),
  361. Name = name(),
  362. PostListenCb = fun (_) -> {error, test} end,
  363. {error, _} = ranch:start_listener(Name,
  364. ranch_tcp, #{post_listen_callback => PostListenCb},
  365. echo_protocol, []),
  366. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  367. ok.
  368. misc_repeated_remove(_) ->
  369. doc("Ensure repeated removal of connection does not crash the connection supervisor."),
  370. Name = name(),
  371. {ok, _} = ranch:start_listener(Name,
  372. ranch_tcp, #{},
  373. remove_conn_and_wait_protocol, [{remove, 5, 0}]),
  374. Port = ranch:get_port(Name),
  375. ConnsSups = lists:sort(ranch_server:get_connections_sups(Name)),
  376. {ok, _} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  377. timer:sleep(1000),
  378. ConnsSups = lists:sort(ranch_server:get_connections_sups(Name)),
  379. true = lists:all(fun ({_, ConnsSup}) -> erlang:is_process_alive(ConnsSup) end, ConnsSups),
  380. ok = ranch:stop_listener(Name).
  381. misc_set_transport_options(_) ->
  382. doc(""),
  383. Name = name(),
  384. {ok, ListenerSupPid} = ranch:start_listener(Name, ranch_tcp, #{max_connections => 10,
  385. handshake_timeout => 5000, shutdown => 1000, num_acceptors => 1,
  386. socket_opts => [{send_timeout, 5000}]}, echo_protocol, []),
  387. ok = ranch:set_transport_options(Name, #{max_connections => 20, handshake_timeout => 5001,
  388. num_acceptors => 2, shutdown => 1001, socket_opts => [{send_timeout, 5002}]}),
  389. ConnsSups = [ConnsSup || {_, ConnsSup} <- ranch_server:get_connections_sups(Name)],
  390. _ = [begin
  391. {State, _, _, _} = sys:get_state(ConnsSup),
  392. 20 = element(11, State),
  393. 5001 = element(10, State),
  394. 1001 = element(6, State)
  395. end || ConnsSup <- ConnsSups],
  396. ok = ranch:suspend_listener(Name),
  397. ok = ranch:resume_listener(Name),
  398. 2 = length(ranch:procs(Name, acceptors)),
  399. LSocket = do_get_listener_socket(ListenerSupPid),
  400. {ok, [{send_timeout, 5002}]} = ranch_tcp:getopts(LSocket, [send_timeout]),
  401. ok = ranch:stop_listener(Name).
  402. misc_wait_for_connections(_) ->
  403. doc("Ensure wait for connections works."),
  404. Name = name(),
  405. Self = self(),
  406. %% Ensure invalid arguments are rejected.
  407. {'EXIT', {badarg, _}} = begin catch ranch:wait_for_connections(Name, 'foo', 0) end,
  408. {'EXIT', {badarg, _}} = begin catch ranch:wait_for_connections(Name, '==', -1) end,
  409. {'EXIT', {badarg, _}} = begin catch ranch:wait_for_connections(Name, '==', 0, -1) end,
  410. {'EXIT', {badarg, _}} = begin catch ranch:wait_for_connections(Name, '<', 0) end,
  411. %% Create waiters for increasing number of connections.
  412. Pid1GT = do_create_waiter(Self, Name, '>', 0),
  413. Pid1GE = do_create_waiter(Self, Name, '>=', 1),
  414. Pid1EQ = do_create_waiter(Self, Name, '==', 1),
  415. Pid2GT = do_create_waiter(Self, Name, '>', 1),
  416. Pid2GE = do_create_waiter(Self, Name, '>=', 2),
  417. Pid2EQ = do_create_waiter(Self, Name, '==', 2),
  418. {ok, _} = ranch:start_listener(Name,
  419. ranch_tcp, #{num_acceptors => 1},
  420. echo_protocol, []),
  421. Port = ranch:get_port(Name),
  422. %% Create some connections, ensure that waiters respond.
  423. {ok, Sock1} = gen_tcp:connect("localhost", Port, []),
  424. ok = do_expect_waiter(Pid1GT),
  425. ok = do_expect_waiter(Pid1GE),
  426. ok = do_expect_waiter(Pid1EQ),
  427. ok = do_expect_waiter(undefined),
  428. {ok, Sock2} = gen_tcp:connect("localhost", Port, []),
  429. ok = do_expect_waiter(Pid2GT),
  430. ok = do_expect_waiter(Pid2GE),
  431. ok = do_expect_waiter(Pid2EQ),
  432. ok = do_expect_waiter(undefined),
  433. %% Create waiters for decreasing number of connections.
  434. Pid3LT = do_create_waiter(Self, Name, '<', 2),
  435. Pid3LE = do_create_waiter(Self, Name, '=<', 1),
  436. Pid3EQ = do_create_waiter(Self, Name, '==', 1),
  437. Pid4LT = do_create_waiter(Self, Name, '<', 1),
  438. Pid4LE = do_create_waiter(Self, Name, '=<', 0),
  439. Pid4EQ = do_create_waiter(Self, Name, '==', 0),
  440. %% Close connections, ensure that waiters respond.
  441. ok = gen_tcp:close(Sock1),
  442. ok = do_expect_waiter(Pid3LT),
  443. ok = do_expect_waiter(Pid3LE),
  444. ok = do_expect_waiter(Pid3EQ),
  445. ok = do_expect_waiter(undefined),
  446. ok = gen_tcp:close(Sock2),
  447. ok = do_expect_waiter(Pid4LT),
  448. ok = do_expect_waiter(Pid4LE),
  449. ok = do_expect_waiter(Pid4EQ),
  450. ok = do_expect_waiter(undefined),
  451. ok = ranch:stop_listener(Name),
  452. %% Make sure the listener stopped.
  453. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  454. ok.
  455. do_create_waiter(ReplyTo, Ref, Op, NumConns) ->
  456. spawn(fun () -> ok = ranch:wait_for_connections(Ref, Op, NumConns, 100),
  457. ReplyTo ! {wait_connections, self()} end).
  458. do_expect_waiter(WaiterPid) ->
  459. receive
  460. {wait_connections, _} when WaiterPid=:=undefined ->
  461. error;
  462. {wait_connections, Pid} when Pid=:=WaiterPid ->
  463. ok
  464. after 1000 ->
  465. case WaiterPid of
  466. undefined ->
  467. ok;
  468. _ ->
  469. timeout
  470. end
  471. end.
  472. misc_multiple_ip_local_socket_opts(_) ->
  473. case do_os_supports_local_sockets() of
  474. true ->
  475. do_misc_multiple_ip_local_socket_opts();
  476. false ->
  477. {skip, "No local socket support."}
  478. end.
  479. do_misc_multiple_ip_local_socket_opts() ->
  480. doc("Ensure that a listener uses the expected ip option if multiple are given."),
  481. Name = name(),
  482. SockFile1 = do_tempname(),
  483. SockFile2 = do_tempname(),
  484. Opts = [{ip, {local, SockFile1}}, {ip, {local, SockFile2}}],
  485. {ok, _} = ranch:start_listener(Name, ranch_tcp, #{socket_opts => Opts}, echo_protocol, []),
  486. {local, SockFile2} = ranch:get_addr(Name),
  487. %% Make sure the socket file from the ignored ip option
  488. %% has not been created.
  489. {error, enoent} = file:read_file_info(SockFile1),
  490. ok = ranch:stop_listener(Name),
  491. %% Make sure the socket file from the accepted ip option
  492. %% is removed.
  493. {error, enoent} = file:read_file_info(SockFile2),
  494. ok.
  495. %% ssl.
  496. ssl_accept_error(_) ->
  497. doc("Acceptor must not crash if client disconnects in the middle of SSL handshake."),
  498. Name = name(),
  499. Opts = ct_helper:get_certs_from_ets(),
  500. {ok, ListenerSup} = ranch:start_listener(Name,
  501. ranch_ssl, #{num_acceptors => 1, socket_opts => Opts},
  502. echo_protocol, []),
  503. Port = ranch:get_port(Name),
  504. ListenerSupChildren = supervisor:which_children(ListenerSup),
  505. {_, AcceptorsSup, _, _} = lists:keyfind(ranch_acceptors_sup, 1, ListenerSupChildren),
  506. [{{acceptor, _, _}, AcceptorPid, _, _}] = supervisor:which_children(AcceptorsSup),
  507. true = is_process_alive(AcceptorPid),
  508. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  509. ok = gen_tcp:close(Socket),
  510. receive after 500 -> ok end,
  511. true = is_process_alive(AcceptorPid),
  512. ok = ranch:stop_listener(Name).
  513. ssl_10_acceptors_10_listen_sockets(_) ->
  514. case do_os_supports_reuseport() of
  515. true ->
  516. ok = do_ssl_10_acceptors_10_listen_sockets();
  517. false ->
  518. {skip, "No SO_REUSEPORT support."}
  519. end.
  520. do_ssl_10_acceptors_10_listen_sockets() ->
  521. doc("Ensure that we can use 10 listen sockets across 10 acceptors with SSL."),
  522. Name = name(),
  523. Opts = ct_helper:get_certs_from_ets(),
  524. {ok, ListenerSupPid} = ranch:start_listener(Name,
  525. ranch_ssl, #{
  526. num_acceptors => 10,
  527. num_listen_sockets => 10,
  528. socket_opts => [{raw, 1, 15, <<1:32/native>>}|Opts]},
  529. echo_protocol, []),
  530. 10 = length(do_get_listener_sockets(ListenerSupPid)),
  531. ok = ranch:stop_listener(Name),
  532. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  533. ok.
  534. ssl_many_listen_sockets_no_reuseport(_) ->
  535. case do_os_supports_reuseport() of
  536. true ->
  537. ok = do_ssl_many_listen_sockets_no_reuseport();
  538. false ->
  539. {skip, "No SO_REUSEPORT support."}
  540. end.
  541. do_ssl_many_listen_sockets_no_reuseport() ->
  542. doc("Confirm that ranch:start_listener/5 fails when SO_REUSEPORT is not available with SSL."),
  543. Name = name(),
  544. Opts = ct_helper:get_certs_from_ets(),
  545. {error, eaddrinuse} = ranch:start_listener(Name,
  546. ranch_ssl, #{
  547. num_acceptors => 10,
  548. num_listen_sockets => 10,
  549. socket_opts => [{raw, 1, 15, <<0:32/native>>}|Opts]},
  550. echo_protocol, []),
  551. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  552. ok.
  553. ssl_active_echo(_) ->
  554. doc("Ensure that active mode works with SSL transport."),
  555. Name = name(),
  556. Opts = ct_helper:get_certs_from_ets(),
  557. {ok, _} = ranch:start_listener(Name,
  558. ranch_ssl, Opts,
  559. active_echo_protocol, []),
  560. Port = ranch:get_port(Name),
  561. {ok, Socket} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  562. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  563. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  564. ok = ranch:stop_listener(Name),
  565. {error, closed} = ssl:recv(Socket, 0, 1000),
  566. %% Make sure the listener stopped.
  567. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  568. ok.
  569. ssl_active_n_echo(_) ->
  570. case application:get_key(ssl, vsn) of
  571. {ok, "9.0"++_} ->
  572. {skip, "No Active N support."};
  573. {ok, "9.1"++_} ->
  574. {skip, "No Active N support."};
  575. {ok, _} ->
  576. do_ssl_active_n_echo()
  577. end.
  578. do_ssl_active_n_echo() ->
  579. doc("Ensure that active N mode works with SSL transport."),
  580. Name = name(),
  581. Opts = ct_helper:get_certs_from_ets(),
  582. {ok, _} = ranch:start_listener(Name,
  583. ranch_ssl, Opts,
  584. batch_echo_protocol, [{batch_size, 3}]),
  585. Port = ranch:get_port(Name),
  586. {ok, Socket} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  587. ok = ssl:send(Socket, <<"One">>),
  588. {ok, <<"OK">>} = ssl:recv(Socket, 2, 1000),
  589. ok = ssl:send(Socket, <<"Two">>),
  590. {ok, <<"OK">>} = ssl:recv(Socket, 2, 1000),
  591. ok = ssl:send(Socket, <<"Three">>),
  592. {ok, <<"OK">>} = ssl:recv(Socket, 2, 1000),
  593. {ok, <<"OneTwoThree">>} = ssl:recv(Socket, 11, 1000),
  594. ok = ranch:stop_listener(Name),
  595. {error, closed} = ssl:recv(Socket, 0, 1000),
  596. %% Make sure the listener stopped.
  597. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  598. ok.
  599. ssl_echo(_) ->
  600. doc("Ensure that passive mode works with SSL transport."),
  601. Name = name(),
  602. Opts = ct_helper:get_certs_from_ets(),
  603. {ok, _} = ranch:start_listener(Name,
  604. ranch_ssl, Opts,
  605. echo_protocol, []),
  606. Port = ranch:get_port(Name),
  607. {ok, Socket} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  608. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  609. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  610. ok = ranch:stop_listener(Name),
  611. {error, closed} = ssl:recv(Socket, 0, 1000),
  612. %% Make sure the listener stopped.
  613. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  614. ok.
  615. ssl_handshake(_) ->
  616. doc("Ensure that multiple steps handshake works with SSL transport."),
  617. Name = name(),
  618. {CaCert1, Cert1, Key1} = ct_helper:make_certs(),
  619. {CaCert2, Cert2, Key2} = ct_helper:make_certs(),
  620. Opts1 = [{cert, Cert1}, {key, Key1}, {cacerts, [CaCert1]}, {verify, verify_peer}],
  621. Opts2 = [{cert, Cert2}, {key, Key2}, {cacerts, [CaCert2]}, {verify, verify_peer}],
  622. DefaultOpts = ct_helper:get_certs_from_ets(),
  623. {ok, _} = ranch:start_listener(Name,
  624. ranch_ssl, [{handshake, hello}|DefaultOpts],
  625. handshake_protocol, #{"ranch1" => Opts1, "ranch2" => Opts2}),
  626. Port = ranch:get_port(Name),
  627. {ok, Socket1} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw},
  628. {server_name_indication, "ranch1"}], 5000),
  629. {ok, Cert1} = ssl:peercert(Socket1),
  630. ok = ssl:send(Socket1, <<"SSL Ranch is working!">>),
  631. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket1, 21, 1000),
  632. {ok, Socket2} = ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw},
  633. {server_name_indication, "ranch2"}], 5000),
  634. {ok, Cert2} = ssl:peercert(Socket2),
  635. ok = ssl:send(Socket2, <<"SSL Ranch is working!">>),
  636. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket2, 21, 1000),
  637. ok = ranch:stop_listener(Name),
  638. {error, closed} = ssl:recv(Socket1, 0, 1000),
  639. {error, closed} = ssl:recv(Socket2, 0, 1000),
  640. %% Make sure the listener stopped.
  641. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  642. ok.
  643. ssl_local_echo(_) ->
  644. case do_os_supports_local_sockets() of
  645. true ->
  646. do_ssl_local_echo();
  647. false ->
  648. {skip, "No local socket support."}
  649. end.
  650. do_ssl_local_echo() ->
  651. doc("Ensure that listening on a local socket works with SSL transport."),
  652. SockFile = do_tempname(),
  653. try
  654. Name = name(),
  655. Opts = ct_helper:get_certs_from_ets(),
  656. {ok, _} = ranch:start_listener(Name,
  657. ranch_ssl, #{socket_opts => [{ip, {local, SockFile}}|Opts]},
  658. echo_protocol, []),
  659. undefined = ranch:get_port(Name),
  660. {ok, Socket} = ssl:connect({local, SockFile}, 0, [binary, {active, false}, {packet, raw}]),
  661. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  662. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  663. ok = ranch:stop_listener(Name),
  664. {error, closed} = ssl:recv(Socket, 0, 1000),
  665. %% Make sure the listener stopped.
  666. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  667. %% Make sure the socket file is removed.
  668. {error, enoent} = file:read_file_info(SockFile),
  669. ok
  670. after
  671. file:delete(SockFile)
  672. end.
  673. ssl_sni_echo(_) ->
  674. doc("Ensure that SNI works with SSL transport."),
  675. Name = name(),
  676. Opts = ct_helper:get_certs_from_ets(),
  677. {ok, _} = ranch:start_listener(Name,
  678. ranch_ssl, [{sni_hosts, [{"localhost", Opts}]}],
  679. echo_protocol, []),
  680. Port = ranch:get_port(Name),
  681. %% We stick to TLS 1.2 because there seems to be a bug in OTP-23.0rc2
  682. %% that leads to a malformed_handshake_data error.
  683. {ok, Socket} = ssl:connect("localhost", Port,
  684. [binary, {active, false}, {packet, raw}, {versions, ['tlsv1.2']}]),
  685. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  686. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  687. ok = ranch:stop_listener(Name),
  688. {error, closed} = ssl:recv(Socket, 0, 1000),
  689. %% Make sure the listener stopped.
  690. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  691. ok.
  692. ssl_sni_fail(_) ->
  693. doc("Ensure that connection fails when host is not in SNI list."),
  694. Name = name(),
  695. Opts = ct_helper:get_certs_from_ets(),
  696. {ok, _} = ranch:start_listener(Name,
  697. ranch_ssl, [{sni_hosts, [{"pouet", Opts}]}],
  698. echo_protocol, []),
  699. Port = ranch:get_port(Name),
  700. %% We stick to TLS 1.2 because there seems to be a bug in OTP-23.0rc2
  701. %% that leads to a malformed_handshake_data error.
  702. {error, _} = ssl:connect("localhost", Port,
  703. [binary, {active, false}, {packet, raw}, {versions, ['tlsv1.2']}]),
  704. ok = ranch:stop_listener(Name),
  705. %% Make sure the listener stopped.
  706. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  707. ok.
  708. ssl_upgrade_from_tcp(_) ->
  709. doc("Ensure a TCP socket can be upgraded to SSL"),
  710. Name = name(),
  711. {ok, _} = ranch:start_listener(Name,
  712. ranch_tcp, #{},
  713. ssl_upgrade_protocol, []),
  714. Port = ranch:get_port(Name),
  715. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  716. ok = gen_tcp:send(Socket, <<"ECHO Before upgrading to SSL">>),
  717. {ok, <<"Before upgrading to SSL">>} = gen_tcp:recv(Socket, 23, 1000),
  718. ok = gen_tcp:send(Socket, <<"UPGRADE">>),
  719. {ok, <<"READY">>} = gen_tcp:recv(Socket, 5, 1000),
  720. {ok, SslSocket} = ssl:connect(Socket, [{verify, verify_none}], 5000),
  721. ok = ssl:send(SslSocket, <<"ECHO After upgrading to SSL">>),
  722. {ok, <<"After upgrading to SSL">>} = ssl:recv(SslSocket, 22, 1000),
  723. ok = ranch:stop_listener(Name),
  724. {error, closed} = ssl:recv(SslSocket, 0, 1000),
  725. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  726. ok.
  727. ssl_graceful(_) ->
  728. doc("Ensure suspending and resuming of listeners does not kill active connections."),
  729. Name = name(),
  730. Opts = ct_helper:get_certs_from_ets(),
  731. {ok, _} = ranch:start_listener(Name,
  732. ranch_ssl, Opts,
  733. echo_protocol, []),
  734. Port = ranch:get_port(Name),
  735. %% Make sure connections with a fresh listener work.
  736. running = ranch:get_status(Name),
  737. {ok, Socket1} = ssl:connect("localhost", Port,
  738. [binary, {active, false}, {packet, raw}]),
  739. ok = ssl:send(Socket1, <<"SSL with fresh listener">>),
  740. {ok, <<"SSL with fresh listener">>} = ssl:recv(Socket1, 23, 1000),
  741. %% Suspend listener, make sure established connections keep running.
  742. ok = ranch:suspend_listener(Name),
  743. suspended = ranch:get_status(Name),
  744. ok = ssl:send(Socket1, <<"SSL with suspended listener">>),
  745. {ok, <<"SSL with suspended listener">>} = ssl:recv(Socket1, 27, 1000),
  746. %% Make sure new connections are refused on the suspended listener.
  747. {error, econnrefused} = ssl:connect("localhost", Port,
  748. [binary, {active, false}, {packet, raw}]),
  749. %% Make sure transport options can be changed when listener is suspended.
  750. ok = ranch:set_transport_options(Name, #{socket_opts => [{port, Port}|Opts]}),
  751. %% Resume listener, make sure connections can be established again.
  752. ok = ranch:resume_listener(Name),
  753. running = ranch:get_status(Name),
  754. {ok, Socket2} = ssl:connect("localhost", Port,
  755. [binary, {active, false}, {packet, raw}]),
  756. ok = ssl:send(Socket2, <<"SSL with resumed listener">>),
  757. {ok, <<"SSL with resumed listener">>} = ssl:recv(Socket2, 25, 1000),
  758. ok = ranch:stop_listener(Name),
  759. {error, closed} = ssl:recv(Socket1, 0, 1000),
  760. {error, closed} = ssl:recv(Socket2, 0, 1000),
  761. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  762. ok.
  763. ssl_getopts_capability(_) ->
  764. doc("Ensure getopts/2 capability."),
  765. Name=name(),
  766. Opts=ct_helper:get_certs_from_ets(),
  767. {ok, _} = ranch:start_listener(Name,
  768. ranch_ssl, Opts,
  769. transport_capabilities_protocol, []),
  770. Port=ranch:get_port(Name),
  771. {ok, Socket}=ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  772. ok=ssl:send(Socket, <<"getopts/2">>),
  773. {ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
  774. ok=ranch:stop_listener(Name),
  775. {error, closed}=ssl:recv(Socket, 0, 1000),
  776. {'EXIT', _}=begin catch ranch:get_port(Name) end,
  777. ok.
  778. ssl_getstat_capability(_) ->
  779. doc("Ensure getstat/1,2 capability."),
  780. Name=name(),
  781. Opts=ct_helper:get_certs_from_ets(),
  782. {ok, _} = ranch:start_listener(Name,
  783. ranch_ssl, Opts,
  784. transport_capabilities_protocol, []),
  785. Port=ranch:get_port(Name),
  786. {ok, Socket}=ssl:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  787. ok=ssl:send(Socket, <<"getstat/1">>),
  788. {ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
  789. ok=ssl:send(Socket, <<"getstat/2">>),
  790. {ok, <<"OK">>}=ssl:recv(Socket, 0, 1000),
  791. ok=ranch:stop_listener(Name),
  792. {error, closed}=ssl:recv(Socket, 0, 1000),
  793. {'EXIT', _}=begin catch ranch:get_port(Name) end,
  794. ok.
  795. ssl_error_eaddrinuse(_) ->
  796. doc("Ensure that failure due to an eaddrinuse returns a compact readable error."),
  797. Name = name(),
  798. Opts = ct_helper:get_certs_from_ets(),
  799. {ok, _} = ranch:start_listener(Name,
  800. ranch_ssl, Opts,
  801. active_echo_protocol, []),
  802. Port = ranch:get_port(Name),
  803. {error, eaddrinuse} = ranch:start_listener({Name, fails},
  804. ranch_ssl, [{port, Port}|Opts],
  805. active_echo_protocol, []),
  806. ok = ranch:stop_listener(Name),
  807. %% Make sure the listener stopped.
  808. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  809. ok.
  810. ssl_error_no_cert(_) ->
  811. doc("Ensure that failure due to missing certificate returns a compact readable error."),
  812. {error, no_cert} = ranch:start_listener(name(),
  813. ranch_ssl, #{},
  814. active_echo_protocol, []),
  815. ok.
  816. ssl_error_eacces(_) ->
  817. case os:type() of
  818. {win32, nt} ->
  819. {skip, "No privileged ports."};
  820. {unix, darwin} ->
  821. {skip, "No privileged ports."};
  822. _ ->
  823. doc("Ensure that failure due to an eacces returns a compact readable error."),
  824. Name = name(),
  825. Opts = ct_helper:get_certs_from_ets(),
  826. {error, eacces} = ranch:start_listener(Name,
  827. ranch_ssl, [{port, 283}|Opts],
  828. active_echo_protocol, []),
  829. ok
  830. end.
  831. %% tcp.
  832. tcp_10_acceptors_10_listen_sockets(_) ->
  833. case do_os_supports_reuseport() of
  834. true ->
  835. ok = do_tcp_10_acceptors_10_listen_sockets();
  836. false ->
  837. {skip, "No SO_REUSEPORT support."}
  838. end.
  839. do_tcp_10_acceptors_10_listen_sockets() ->
  840. doc("Ensure that we can use 10 listen sockets across 10 acceptors with TCP."),
  841. Name = name(),
  842. {ok, ListenerSupPid} = ranch:start_listener(Name,
  843. ranch_tcp, #{
  844. num_acceptors => 10,
  845. num_listen_sockets => 10,
  846. socket_opts => [{raw, 1, 15, <<1:32/native>>}]},
  847. echo_protocol, []),
  848. 10 = length(do_get_listener_sockets(ListenerSupPid)),
  849. ok = ranch:stop_listener(Name),
  850. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  851. ok.
  852. tcp_many_listen_sockets_no_reuseport(_) ->
  853. case do_os_supports_reuseport() of
  854. true ->
  855. ok = do_tcp_many_listen_sockets_no_reuseport();
  856. false ->
  857. {skip, "No SO_REUSEPORT support."}
  858. end.
  859. do_tcp_many_listen_sockets_no_reuseport() ->
  860. doc("Confirm that ranch:start_listener/5 fails when SO_REUSEPORT is not available with TCP."),
  861. Name = name(),
  862. {error, eaddrinuse} = ranch:start_listener(Name,
  863. ranch_tcp, #{
  864. num_acceptors => 10,
  865. num_listen_sockets => 10,
  866. socket_opts => [{raw, 1, 15, <<0:32/native>>}]},
  867. echo_protocol, []),
  868. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  869. ok.
  870. tcp_active_echo(_) ->
  871. doc("Ensure that active mode works with TCP transport."),
  872. Name = name(),
  873. {ok, _} = ranch:start_listener(Name,
  874. ranch_tcp, #{},
  875. active_echo_protocol, []),
  876. Port = ranch:get_port(Name),
  877. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  878. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  879. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  880. ok = ranch:stop_listener(Name),
  881. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  882. %% Make sure the listener stopped.
  883. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  884. ok.
  885. tcp_active_n_echo(_) ->
  886. doc("Ensure that active N mode works with TCP transport."),
  887. Name = name(),
  888. {ok, _} = ranch:start_listener(Name,
  889. ranch_tcp, #{},
  890. batch_echo_protocol, [{batch_size, 3}]),
  891. Port = ranch:get_port(Name),
  892. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  893. ok = gen_tcp:send(Socket, <<"One">>),
  894. {ok, <<"OK">>} = gen_tcp:recv(Socket, 2, 1000),
  895. ok = gen_tcp:send(Socket, <<"Two">>),
  896. {ok, <<"OK">>} = gen_tcp:recv(Socket, 2, 1000),
  897. ok = gen_tcp:send(Socket, <<"Three">>),
  898. {ok, <<"OK">>} = gen_tcp:recv(Socket, 2, 1000),
  899. {ok, <<"OneTwoThree">>} = gen_tcp:recv(Socket, 11, 1000),
  900. ok = ranch:stop_listener(Name),
  901. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  902. %% Make sure the listener stopped.
  903. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  904. ok.
  905. tcp_echo(_) ->
  906. doc("Ensure that passive mode works with TCP transport."),
  907. Name = name(),
  908. {ok, _} = ranch:start_listener(Name,
  909. ranch_tcp, #{},
  910. echo_protocol, []),
  911. Port = ranch:get_port(Name),
  912. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  913. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  914. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  915. ok = ranch:stop_listener(Name),
  916. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  917. %% Make sure the listener stopped.
  918. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  919. ok.
  920. tcp_local_echo(_) ->
  921. case do_os_supports_local_sockets() of
  922. true ->
  923. do_tcp_local_echo();
  924. false ->
  925. {skip, "No local socket support."}
  926. end.
  927. do_tcp_local_echo() ->
  928. doc("Ensure that listening on a local socket works with TCP transport."),
  929. SockFile = do_tempname(),
  930. try
  931. Name = name(),
  932. {ok, _} = ranch:start_listener(Name,
  933. ranch_tcp, #{socket_opts => [{ip, {local, SockFile}}]},
  934. echo_protocol, []),
  935. undefined = ranch:get_port(Name),
  936. {ok, Socket} = gen_tcp:connect({local, SockFile}, 0, [binary, {active, false}, {packet, raw}]),
  937. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  938. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  939. ok = ranch:stop_listener(Name),
  940. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  941. %% Make sure the listener stopped.
  942. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  943. %% Make sure the socket file is removed.
  944. {error, enoent} = file:read_file_info(SockFile),
  945. ok
  946. after
  947. file:delete(SockFile)
  948. end.
  949. tcp_graceful(_) ->
  950. doc("Ensure suspending and resuming of listeners does not kill active connections."),
  951. Name = name(),
  952. {ok, _} = ranch:start_listener(Name,
  953. ranch_tcp, #{},
  954. echo_protocol, []),
  955. Port = ranch:get_port(Name),
  956. %% Make sure connections with a fresh listener work.
  957. running = ranch:get_status(Name),
  958. {ok, Socket1} = gen_tcp:connect("localhost", Port,
  959. [binary, {active, false}, {packet, raw}]),
  960. ok = gen_tcp:send(Socket1, <<"TCP with fresh listener">>),
  961. {ok, <<"TCP with fresh listener">>} = gen_tcp:recv(Socket1, 23, 1000),
  962. %% Suspend listener, make sure established connections keep running.
  963. ok = ranch:suspend_listener(Name),
  964. suspended = ranch:get_status(Name),
  965. ok = gen_tcp:send(Socket1, <<"TCP with suspended listener">>),
  966. {ok, <<"TCP with suspended listener">>} = gen_tcp:recv(Socket1, 27, 1000),
  967. %% Make sure new connections are refused on the suspended listener.
  968. {error, econnrefused} = gen_tcp:connect("localhost", Port,
  969. [binary, {active, false}, {packet, raw}]),
  970. %% Make sure transport options can be changed when listener is suspended.
  971. ok = ranch:set_transport_options(Name, [{port, Port}]),
  972. %% Resume listener, make sure connections can be established again.
  973. ok = ranch:resume_listener(Name),
  974. running = ranch:get_status(Name),
  975. {ok, Socket2} = gen_tcp:connect("localhost", Port,
  976. [binary, {active, false}, {packet, raw}]),
  977. ok = gen_tcp:send(Socket2, <<"TCP with resumed listener">>),
  978. {ok, <<"TCP with resumed listener">>} = gen_tcp:recv(Socket2, 25, 1000),
  979. ok = ranch:stop_listener(Name),
  980. {error, closed} = gen_tcp:recv(Socket1, 0, 1000),
  981. {error, closed} = gen_tcp:recv(Socket2, 0, 1000),
  982. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  983. ok.
  984. tcp_inherit_options(_) ->
  985. doc("Ensure TCP options are inherited in the protocol."),
  986. Name = name(),
  987. Opts = [{nodelay, false}, {send_timeout_close, false}],
  988. {ok, _} = ranch:start_listener(Name,
  989. ranch_tcp, Opts,
  990. check_tcp_options, [{pid, self()} | Opts]),
  991. Port = ranch:get_port(Name),
  992. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, true}, {packet, raw}]),
  993. receive checked -> ok after 1000 -> error(timeout) end,
  994. ok = gen_tcp:close(Socket),
  995. ok = ranch:stop_listener(Name).
  996. tcp_max_connections(_) ->
  997. doc("Ensure the max_connections option actually limits connections."),
  998. Name = name(),
  999. {ok, _} = ranch:start_listener(Name,
  1000. ranch_tcp, #{max_connections => 10, num_acceptors => 1},
  1001. notify_and_wait_protocol, #{pid => self()}),
  1002. Port = ranch:get_port(Name),
  1003. ok = connect_loop(Port, 11, 150),
  1004. 10 = ranch_server:count_connections(Name),
  1005. {10, Pids1} = receive_loop(connected, 400),
  1006. ok = terminate_loop(stop, Pids1),
  1007. {1, Pids2} = receive_loop(connected, 1000),
  1008. ok = terminate_loop(stop, Pids2),
  1009. ok = ranch:stop_listener(Name).
  1010. tcp_max_connections_and_beyond(_) ->
  1011. doc("Ensure the max_connections option works when connections are removed from the count."),
  1012. Name = name(),
  1013. {ok, _} = ranch:start_listener(Name,
  1014. ranch_tcp, #{max_connections => 10, num_acceptors => 1},
  1015. remove_conn_and_wait_protocol, [{remove, true, 2500}]),
  1016. Port = ranch:get_port(Name),
  1017. ok = connect_loop(Port, 10, 0),
  1018. receive after 250 -> ok end,
  1019. 0 = ranch_server:count_connections(Name),
  1020. 10 = length(do_conns_which_children(Name)),
  1021. Counts = do_conns_count_children(Name),
  1022. {_, 1} = lists:keyfind(specs, 1, Counts),
  1023. {_, 0} = lists:keyfind(supervisors, 1, Counts),
  1024. {_, 10} = lists:keyfind(active, 1, Counts),
  1025. {_, 10} = lists:keyfind(workers, 1, Counts),
  1026. ranch:set_protocol_options(Name, [{remove, false, 2500}]),
  1027. receive after 250 -> ok end,
  1028. ok = connect_loop(Port, 10, 0),
  1029. receive after 250 -> ok end,
  1030. 10 = ranch_server:count_connections(Name),
  1031. 20 = length(do_conns_which_children(Name)),
  1032. Counts2 = do_conns_count_children(Name),
  1033. {_, 20} = lists:keyfind(active, 1, Counts2),
  1034. {_, 20} = lists:keyfind(workers, 1, Counts2),
  1035. ok = ranch:stop_listener(Name).
  1036. tcp_max_connections_infinity(_) ->
  1037. doc("Set the max_connections option from 10 to infinity and back to 10."),
  1038. Name = name(),
  1039. {ok, _} = ranch:start_listener(Name,
  1040. ranch_tcp, #{max_connections => 10, num_acceptors => 1},
  1041. notify_and_wait_protocol, #{pid => self()}),
  1042. Port = ranch:get_port(Name),
  1043. ok = connect_loop(Port, 20, 0),
  1044. 10 = ranch_server:count_connections(Name),
  1045. {10, Pids1} = receive_loop(connected, 1000),
  1046. 10 = ranch_server:count_connections(Name),
  1047. 10 = ranch:get_max_connections(Name),
  1048. ranch:set_max_connections(Name, infinity),
  1049. receive after 250 -> ok end,
  1050. 20 = ranch_server:count_connections(Name),
  1051. infinity = ranch:get_max_connections(Name),
  1052. ranch:set_max_connections(Name, 10),
  1053. 20 = ranch_server:count_connections(Name),
  1054. {10, Pids2} = receive_loop(connected, 1000),
  1055. ok = terminate_loop(stop, Pids1 ++ Pids2),
  1056. ok = ranch:stop_listener(Name).
  1057. tcp_remove_connections(_) ->
  1058. doc("Ensure that removed connections are only removed once."),
  1059. Name = name(),
  1060. {ok, _} = ranch:start_listener(Name,
  1061. ranch_tcp, #{},
  1062. remove_conn_and_wait_protocol, [{remove, true, 0}]),
  1063. Port = ranch:get_port(Name),
  1064. ok = connect_loop(Port, 10, 0),
  1065. receive after 250 -> ok end,
  1066. 0 = ranch_server:count_connections(Name),
  1067. ok = ranch:stop_listener(Name).
  1068. tcp_remove_connections_acceptor_wakeup(_) ->
  1069. doc("Ensure that removed connections wake up acceptors."),
  1070. Name = name(),
  1071. {ok, _} = ranch:start_listener(Name,
  1072. ranch_tcp, #{max_connections => 1, num_acceptors => 1},
  1073. remove_conn_and_wait_protocol, [{remove, true, infinity}]),
  1074. Port = ranch:get_port(Name),
  1075. ConnectOptions = [binary, {active, false}],
  1076. Localhost = "localhost",
  1077. {ok, Socket1} = gen_tcp:connect(Localhost, Port, ConnectOptions),
  1078. {ok, Socket2} = gen_tcp:connect(Localhost, Port, ConnectOptions),
  1079. {ok, Socket3} = gen_tcp:connect(Localhost, Port, ConnectOptions),
  1080. ok = gen_tcp:send(Socket3, <<"bye">>),
  1081. true = maps:get(all_connections, ranch:info(Name)) >= 2,
  1082. ok = gen_tcp:send(Socket1, <<"bye">>),
  1083. ok = gen_tcp:send(Socket2, <<"bye">>),
  1084. ok = ranch:stop_listener(Name).
  1085. tcp_set_max_connections(_) ->
  1086. doc("Ensure that changing the max_connections option to a larger value allows for more connections."),
  1087. Name = name(),
  1088. {ok, _} = ranch:start_listener(Name,
  1089. ranch_tcp, #{max_connections => 10, num_acceptors => 1},
  1090. notify_and_wait_protocol, #{pid => self()}),
  1091. Port = ranch:get_port(Name),
  1092. ok = connect_loop(Port, 20, 0),
  1093. 10 = ranch_server:count_connections(Name),
  1094. {10, Pids1} = receive_loop(connected, 1000),
  1095. 10 = ranch:get_max_connections(Name),
  1096. ranch:set_max_connections(Name, 20),
  1097. {10, Pids2} = receive_loop(connected, 1000),
  1098. 20 = ranch:get_max_connections(Name),
  1099. ok = terminate_loop(stop, Pids1 ++ Pids2),
  1100. ok = ranch:stop_listener(Name).
  1101. tcp_set_max_connections_clean(_) ->
  1102. doc("Ensure that setting max_connections does not crash any process."),
  1103. Name = name(),
  1104. {ok, ListSupPid} = ranch:start_listener(Name,
  1105. ranch_tcp, #{max_connections => 4},
  1106. notify_and_wait_protocol, #{pid => self()}),
  1107. Children = supervisor:which_children(ListSupPid),
  1108. {_, AccSupPid, _, _} = lists:keyfind(ranch_acceptors_sup, 1, Children),
  1109. 1 = erlang:trace(ListSupPid, true, [procs]),
  1110. 1 = erlang:trace(AccSupPid, true, [procs]),
  1111. Port = ranch:get_port(Name),
  1112. N = 20,
  1113. ok = connect_loop(Port, N*5, 0),
  1114. %% Randomly set max_connections.
  1115. [spawn(ranch, set_max_connections, [Name, Max]) ||
  1116. Max <- lists:flatten(lists:duplicate(N, [6, 4, 8, infinity]))],
  1117. receive
  1118. {trace, _, spawn, _, _} ->
  1119. error(dirty_set_max_connections)
  1120. after
  1121. 2000 -> ok
  1122. end,
  1123. _ = erlang:trace(all, false, [all]),
  1124. ok = clean_traces(),
  1125. ok = ranch:stop_listener(Name).
  1126. tcp_getopts_capability(_) ->
  1127. doc("Ensure getopts/2 capability."),
  1128. Name=name(),
  1129. {ok, _}=ranch:start_listener(Name,
  1130. ranch_tcp, #{},
  1131. transport_capabilities_protocol, []),
  1132. Port=ranch:get_port(Name),
  1133. {ok, Socket}=gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  1134. ok=gen_tcp:send(Socket, <<"getopts/2">>),
  1135. {ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
  1136. ok=ranch:stop_listener(Name),
  1137. {error, closed}=gen_tcp:recv(Socket, 0, 1000),
  1138. {'EXIT', _}=begin catch ranch:get_port(Name) end,
  1139. ok.
  1140. tcp_getstat_capability(_) ->
  1141. doc("Ensure getstat/1,2 capability."),
  1142. Name=name(),
  1143. {ok, _}=ranch:start_listener(Name,
  1144. ranch_tcp, #{},
  1145. transport_capabilities_protocol, []),
  1146. Port=ranch:get_port(Name),
  1147. {ok, Socket}=gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  1148. ok=gen_tcp:send(Socket, <<"getstat/1">>),
  1149. {ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
  1150. ok=gen_tcp:send(Socket, <<"getstat/2">>),
  1151. {ok, <<"OK">>}=gen_tcp:recv(Socket, 0, 1000),
  1152. ok=ranch:stop_listener(Name),
  1153. {error, closed}=gen_tcp:recv(Socket, 0, 1000),
  1154. {'EXIT', _}=begin catch ranch:get_port(Name) end,
  1155. ok.
  1156. tcp_upgrade(_) ->
  1157. doc("Ensure that protocol options can be updated."),
  1158. Name = name(),
  1159. {ok, _} = ranch:start_listener(Name,
  1160. ranch_tcp, #{},
  1161. notify_and_wait_protocol, #{pid => self()}),
  1162. Port = ranch:get_port(Name),
  1163. ok = connect_loop(Port, 1, 0),
  1164. {1, Pids1} = receive_loop(connected, 1000),
  1165. ranch:set_protocol_options(Name, #{msg => upgraded, pid => self()}),
  1166. ok = connect_loop(Port, 1, 0),
  1167. {1, Pids2} = receive_loop(upgraded, 1000),
  1168. ok = terminate_loop(stop, Pids1 ++ Pids2),
  1169. ok = ranch:stop_listener(Name).
  1170. tcp_error_eaddrinuse(_) ->
  1171. doc("Ensure that failure due to an eaddrinuse returns a compact readable error."),
  1172. Name = name(),
  1173. {ok, _} = ranch:start_listener(Name,
  1174. ranch_tcp, #{},
  1175. active_echo_protocol, []),
  1176. Port = ranch:get_port(Name),
  1177. {error, eaddrinuse} = ranch:start_listener({Name, fails},
  1178. ranch_tcp, [{port, Port}],
  1179. active_echo_protocol, []),
  1180. ok = ranch:stop_listener(Name),
  1181. %% Make sure the listener stopped.
  1182. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  1183. ok.
  1184. tcp_error_eacces(_) ->
  1185. case os:type() of
  1186. {win32, nt} ->
  1187. {skip, "No privileged ports."};
  1188. {unix, darwin} ->
  1189. {skip, "No privileged ports."};
  1190. _ ->
  1191. doc("Ensure that failure due to an eacces returns a compact readable error."),
  1192. Name = name(),
  1193. {error, eacces} = ranch:start_listener(Name,
  1194. ranch_tcp, [{port, 283}],
  1195. active_echo_protocol, []),
  1196. ok
  1197. end.
  1198. %% Supervisor tests
  1199. connection_type_supervisor(_) ->
  1200. doc("The supervisor connection type must be reflected in the specifications."),
  1201. Name = name(),
  1202. {ok, _} = ranch:start_listener(Name,
  1203. ranch_tcp, #{connection_type => supervisor},
  1204. echo_protocol, []),
  1205. Port = ranch:get_port(Name),
  1206. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  1207. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  1208. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  1209. [{echo_protocol, _, supervisor, [echo_protocol]}] = do_conns_which_children(Name),
  1210. ok = ranch:stop_listener(Name),
  1211. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  1212. %% Make sure the listener stopped.
  1213. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  1214. ok.
  1215. connection_type_supervisor_separate_from_connection(_) ->
  1216. doc("The supervisor connection type allows separate supervised and connection processes."),
  1217. Name = name(),
  1218. {ok, _} = ranch:start_listener(Name,
  1219. ranch_tcp, #{connection_type => supervisor},
  1220. supervisor_separate, []),
  1221. Port = ranch:get_port(Name),
  1222. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  1223. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  1224. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  1225. [{supervisor_separate, _, supervisor, [supervisor_separate]}] = do_conns_which_children(Name),
  1226. ok = ranch:stop_listener(Name),
  1227. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  1228. %% Make sure the listener stopped.
  1229. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  1230. ok.
  1231. supervisor_10_acceptors_1_conns_sup(_) ->
  1232. doc("Ensure that using 10 acceptors and 1 connection supervisor works."),
  1233. ok = do_supervisor_n_acceptors_m_conns_sups(10, 1).
  1234. supervisor_9_acceptors_4_conns_sups(_) ->
  1235. doc("Ensure that using 9 acceptors and 4 connection supervisors works."),
  1236. ok = do_supervisor_n_acceptors_m_conns_sups(9, 4).
  1237. supervisor_10_acceptors_10_conns_sups(_) ->
  1238. doc("Ensure that using 10 acceptors and 10 connection supervisors works."),
  1239. ok = do_supervisor_n_acceptors_m_conns_sups(10, 10).
  1240. supervisor_1_acceptor_10_conns_sups(_) ->
  1241. doc("Ensure that using 1 acceptor and 10 connection supervisors works."),
  1242. ok = do_supervisor_n_acceptors_m_conns_sups(1, 10).
  1243. do_supervisor_n_acceptors_m_conns_sups(NumAcceptors, NumConnsSups) ->
  1244. Name = name(),
  1245. {ok, Pid} = ranch:start_listener(Name,
  1246. ranch_tcp, #{num_conns_sups => NumConnsSups, num_acceptors => NumAcceptors},
  1247. notify_and_wait_protocol, #{pid => self()}),
  1248. Port = ranch:get_port(Name),
  1249. ConnsSups = [ConnsSup || {_, ConnsSup} <- ranch_server:get_connections_sups(Name)],
  1250. NumConnsSups = length(ConnsSups),
  1251. {ranch_acceptors_sup, AcceptorsSup, supervisor, _} =
  1252. lists:keyfind(ranch_acceptors_sup, 1, supervisor:which_children(Pid)),
  1253. AcceptorIds = [AcceptorId ||
  1254. {{acceptor, _, AcceptorId}, _, worker, _} <- supervisor:which_children(AcceptorsSup)],
  1255. NumAcceptors = length(AcceptorIds),
  1256. AcceptorConnsSups0 = [ranch_server:get_connections_sup(Name, AcceptorId) ||
  1257. AcceptorId <- AcceptorIds],
  1258. AcceptorConnsSups1 = lists:usort(AcceptorConnsSups0),
  1259. if
  1260. NumAcceptors > NumConnsSups ->
  1261. NumConnsSups = length(AcceptorConnsSups1),
  1262. [] = ConnsSups -- AcceptorConnsSups1;
  1263. NumAcceptors < NumConnsSups ->
  1264. NumAcceptors = length(AcceptorConnsSups1),
  1265. [] = AcceptorConnsSups1 -- ConnsSups;
  1266. NumAcceptors =:= NumConnsSups ->
  1267. NumConnsSups = length(AcceptorConnsSups1),
  1268. NumAcceptors = length(AcceptorConnsSups1),
  1269. [] = ConnsSups -- AcceptorConnsSups1,
  1270. [] = AcceptorConnsSups1 -- ConnsSups
  1271. end,
  1272. ok = connect_loop(Port, 100, 0),
  1273. {100, Pids} = receive_loop(connected, 1000),
  1274. 100 = ranch_server:count_connections(Name),
  1275. ok = terminate_loop(stop, Pids),
  1276. ok = ranch:stop_listener(Name),
  1277. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  1278. ok.
  1279. supervisor_changed_options_restart(_) ->
  1280. doc("Ensure that a listener is restarted with changed transport options."),
  1281. Name = name(),
  1282. %% Start a listener using send_timeout as option change marker.
  1283. {ok, ListenerSupPid1} = ranch:start_listener(Name,
  1284. ranch_tcp, [{send_timeout, 300000}],
  1285. echo_protocol, []),
  1286. %% Ensure send_timeout is really set to initial value.
  1287. {ok, [{send_timeout, 300000}]}
  1288. = inet:getopts(do_get_listener_socket(ListenerSupPid1), [send_timeout]),
  1289. %% Change send_timeout option.
  1290. ok = ranch:suspend_listener(Name),
  1291. ok = ranch:set_transport_options(Name, [{send_timeout, 300001}]),
  1292. ok = ranch:resume_listener(Name),
  1293. %% Ensure send_timeout is really set to the changed value.
  1294. {ok, [{send_timeout, 300001}]}
  1295. = inet:getopts(do_get_listener_socket(ListenerSupPid1), [send_timeout]),
  1296. %% Crash the listener_sup process, allow a short time for restart to succeed.
  1297. %% We silence the expected log events coming from the relevant supervisors.
  1298. ListenerChilds = [ChildPid || {_, ChildPid, _, _} <- supervisor:which_children(ListenerSupPid1)],
  1299. FilterFun = fun (#{meta := #{pid := EventPid}}, _) ->
  1300. case lists:member(EventPid, ListenerChilds) of
  1301. true -> stop;
  1302. false -> ignore
  1303. end
  1304. end,
  1305. ok = logger:add_primary_filter(?MODULE, {FilterFun, undefined}),
  1306. try
  1307. exit(ListenerSupPid1, kill),
  1308. timer:sleep(1000)
  1309. after
  1310. ok = logger:remove_primary_filter(?MODULE)
  1311. end,
  1312. %% Obtain pid of restarted listener_sup process.
  1313. [ListenerSupPid2] = [Pid || {{ranch_listener_sup, Ref}, Pid, supervisor, _}
  1314. <- supervisor:which_children(ranch_sup), Ref =:= Name],
  1315. %% Ensure send_timeout is still set to the changed value.
  1316. {ok, [{send_timeout, 300001}]}
  1317. = inet:getopts(do_get_listener_socket(ListenerSupPid2), [send_timeout]),
  1318. ok = ranch:stop_listener(Name),
  1319. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  1320. ok.
  1321. supervisor_clean_child_restart(_) ->
  1322. doc("Verify that only the relevant parts of the supervision tree restarted "
  1323. "when the listening socket is closed."),
  1324. Name = name(),
  1325. %% Trace socket allocations.
  1326. {module, ranch_tcp} = code:ensure_loaded(ranch_tcp),
  1327. _ = erlang:trace(new, true, [call]),
  1328. 1 = erlang:trace_pattern({ranch_tcp, listen, 1},
  1329. [{'_', [], [{return_trace}]}], [global]),
  1330. {ok, Pid} = ranch:start_listener(Name,
  1331. ranch_tcp, #{num_acceptors => 1},
  1332. echo_protocol, []),
  1333. %% Trace supervisor spawns.
  1334. 1 = erlang:trace(Pid, true, [procs, set_on_spawn]),
  1335. ConnsSups = ranch_server:get_connections_sups(Name),
  1336. %% Manually shut the listening socket down.
  1337. LSocket = receive
  1338. {trace, _, return_from, {ranch_tcp, listen, 1}, {ok, Socket}} ->
  1339. Socket
  1340. after 0 ->
  1341. error(lsocket_unknown)
  1342. end,
  1343. ok = gen_tcp:close(LSocket),
  1344. receive after 1000 -> ok end,
  1345. %% Verify that supervisor and its first two children are alive.
  1346. true = is_process_alive(Pid),
  1347. true = lists:all(fun erlang:is_process_alive/1, [ConnsSup || {_, ConnsSup} <- ConnsSups]),
  1348. %% Check that acceptors_sup is restarted properly.
  1349. AccSupPid = receive {trace, Pid, spawn, Pid1, _} -> Pid1 end,
  1350. receive {trace, AccSupPid, spawn, _, _} -> ok end,
  1351. %% No more traces then.
  1352. receive
  1353. {trace, _, spawn, _, _} -> error(invalid_restart)
  1354. after 1000 -> ok end,
  1355. %% Verify that children still registered right.
  1356. ConnsSups = ranch_server:get_connections_sups(Name),
  1357. _ = erlang:trace_pattern({ranch_tcp, listen, 1}, false, []),
  1358. _ = erlang:trace(all, false, [all]),
  1359. ok = clean_traces(),
  1360. ok = ranch:stop_listener(Name).
  1361. supervisor_clean_restart(_) ->
  1362. doc("Verify that killing ranch_conns_sup does not crash everything "
  1363. "and that it restarts properly."),
  1364. Name = name(),
  1365. NumAcc = 4,
  1366. {ok, Pid} = ranch:start_listener(Name,
  1367. ranch_tcp, #{num_acceptors => NumAcc},
  1368. echo_protocol, []),
  1369. %% Trace supervisor spawns.
  1370. 1 = erlang:trace(Pid, true, [procs, set_on_spawn]),
  1371. {_, ConnsSupSup0, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, supervisor:which_children(Pid)),
  1372. exit(ConnsSupSup0, kill),
  1373. receive after 1000 -> ok end,
  1374. %% Verify that supervisor is alive
  1375. true = is_process_alive(Pid),
  1376. %% ...but children are dead.
  1377. false = is_process_alive(ConnsSupSup0),
  1378. %% Receive traces from newly started children
  1379. ConnsSupSup = receive {trace, Pid, spawn, Pid2, _} -> Pid2 end,
  1380. [receive {trace, ConnsSupSup, spawn, _Pid, _} -> ok end ||
  1381. _ <- lists:seq(1, NumAcc)],
  1382. AccSupPid = receive {trace, Pid, spawn, Pid3, _} -> Pid3 end,
  1383. %% ...and its acceptors.
  1384. [receive {trace, AccSupPid, spawn, _Pid, _} -> ok end ||
  1385. _ <- lists:seq(1, NumAcc)],
  1386. %% No more traces then.
  1387. receive
  1388. {trace, EPid, spawn, _, _} when EPid == Pid; EPid == AccSupPid ->
  1389. error(invalid_restart)
  1390. after 1000 -> ok end,
  1391. %% Verify that new children registered themselves properly.
  1392. _ = erlang:trace(all, false, [all]),
  1393. ok = clean_traces(),
  1394. ok = ranch:stop_listener(Name).
  1395. supervisor_conns_alive(_) ->
  1396. doc("Ensure that active connections stay open when the listening socket gets closed."),
  1397. Name = name(),
  1398. {module, ranch_tcp} = code:ensure_loaded(ranch_tcp),
  1399. _ = erlang:trace(new, true, [call]),
  1400. 1 = erlang:trace_pattern({ranch_tcp, listen, 1},
  1401. [{'_', [], [{return_trace}]}], [global]),
  1402. {ok, _} = ranch:start_listener(Name,
  1403. ranch_tcp, #{},
  1404. remove_conn_and_wait_protocol, [{remove, false, 2500}]),
  1405. %% Get the listener socket
  1406. LSocket = receive
  1407. {trace, _, return_from, {ranch_tcp, listen, 1}, {ok, S}} ->
  1408. S
  1409. after 500 ->
  1410. error(lsocket_unknown)
  1411. end,
  1412. TcpPort = ranch:get_port(Name),
  1413. {ok, Socket} = gen_tcp:connect("localhost", TcpPort,
  1414. [binary, {active, true}, {packet, raw}]),
  1415. receive after 500 -> ok end,
  1416. %% Shut the socket down
  1417. ok = gen_tcp:close(LSocket),
  1418. %% Assert that client is still viable.
  1419. receive {tcp_closed, _} -> error(closed) after 1500 -> ok end,
  1420. ok = gen_tcp:send(Socket, <<"poke">>),
  1421. receive {tcp_closed, _} -> ok end,
  1422. _ = erlang:trace(all, false, [all]),
  1423. ok = clean_traces(),
  1424. ok = ranch:stop_listener(Name).
  1425. supervisor_embedded_ranch_server_crash(_) ->
  1426. doc("Ensure that restarting ranch_server also restarts embedded listeners."),
  1427. Name = name(),
  1428. {ok, SupPid} = embedded_sup:start_link(),
  1429. {ok, EmbeddedSupPid} = embedded_sup:start_listener(SupPid, Name,
  1430. ranch_tcp, #{},
  1431. echo_protocol, []),
  1432. [{{ranch_listener_sup, Name}, ListenerPid, supervisor, _},
  1433. {ranch_server_proxy, ProxyPid, worker, _}] = supervisor:which_children(EmbeddedSupPid),
  1434. ProxyMonitor = monitor(process, ProxyPid),
  1435. ListenerMonitor = monitor(process, ListenerPid),
  1436. ok = supervisor:terminate_child(ranch_sup, ranch_server),
  1437. receive {'DOWN', ProxyMonitor, process, ProxyPid, shutdown} -> ok after 1000 -> exit(timeout) end,
  1438. receive {'DOWN', ListenerMonitor, process, ListenerPid, shutdown} -> ok after 1000 -> exit(timeout) end,
  1439. {ok, _} = supervisor:restart_child(ranch_sup, ranch_server),
  1440. receive after 1000 -> ok end,
  1441. [{{ranch_listener_sup, Name}, _, supervisor, _},
  1442. {ranch_server_proxy, _, worker, _}] = supervisor:which_children(EmbeddedSupPid),
  1443. embedded_sup:stop_listener(SupPid, Name),
  1444. embedded_sup:stop(SupPid),
  1445. ok.
  1446. supervisor_protocol_start_link_crash(_) ->
  1447. doc("Ensure a protocol start crash does not kill all connections."),
  1448. Name = name(),
  1449. {ok, _} = ranch:start_listener(Name,
  1450. ranch_tcp, #{},
  1451. crash_protocol, []),
  1452. ConnsSups = ranch_server:get_connections_sups(Name),
  1453. Port = ranch:get_port(Name),
  1454. {ok, _} = gen_tcp:connect("localhost", Port, [binary, {active, true}, {packet, raw}]),
  1455. receive after 500 -> ok end,
  1456. ConnsSups = ranch_server:get_connections_sups(Name),
  1457. ok = ranch:stop_listener(Name).
  1458. supervisor_server_recover_state(_) ->
  1459. doc("Ensure that when ranch_server crashes and restarts, it recovers "
  1460. "its state and continues monitoring the same processes."),
  1461. Name = name(),
  1462. _ = erlang:trace(new, true, [call]),
  1463. 1 = erlang:trace_pattern({ranch_server, init, 1},
  1464. [{'_', [], [{return_trace}]}], [global]),
  1465. {ok, _} = ranch:start_listener(Name,
  1466. ranch_tcp, #{},
  1467. echo_protocol, []),
  1468. ConnsSups = ranch_server:get_connections_sups(Name),
  1469. ServerPid = erlang:whereis(ranch_server),
  1470. {monitors, Monitors} = erlang:process_info(ServerPid, monitors),
  1471. erlang:exit(ServerPid, kill),
  1472. receive
  1473. {trace, ServerPid2, return_from, {ranch_server, init, 1}, _Result} ->
  1474. {monitors, Monitors2} = erlang:process_info(ServerPid2, monitors),
  1475. %% Check that ranch_server is monitoring the same processes.
  1476. true = (lists:usort(Monitors) == lists:usort(Monitors2))
  1477. after
  1478. 1000 ->
  1479. error(timeout)
  1480. end,
  1481. ConnsSups = ranch_server:get_connections_sups(Name),
  1482. ok = ranch:stop_listener(Name),
  1483. %% Check ranch_server has removed the ranch_conns_sup.
  1484. [] = (catch ranch_server:get_connections_sups(Name)),
  1485. _ = erlang:trace(all, false, [all]),
  1486. ok = clean_traces().
  1487. supervisor_unexpected_message(_) ->
  1488. doc("Ensure the connections supervisor stays alive when it receives "
  1489. "an unexpected message."),
  1490. Name = name(),
  1491. {ok, _} = ranch:start_listener(Name,
  1492. ranch_tcp, #{},
  1493. echo_protocol, []),
  1494. Port = ranch:get_port(Name),
  1495. {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  1496. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  1497. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  1498. %% Send the unexpected message to all ranch_conns_sups.
  1499. _ = [ConnSup ! hello || {_, ConnSup} <- ranch_server:get_connections_sups(Name)],
  1500. %% Connection is still up.
  1501. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  1502. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  1503. ok = ranch:stop_listener(Name),
  1504. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  1505. %% Make sure the listener stopped.
  1506. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  1507. ok.
  1508. %% Utility functions.
  1509. connect_loop(_, 0, _) ->
  1510. ok;
  1511. connect_loop(Port, N, Sleep) ->
  1512. {ok, _} = gen_tcp:connect("localhost", Port,
  1513. [binary, {active, false}, {packet, raw}]),
  1514. receive after Sleep -> ok end,
  1515. connect_loop(Port, N - 1, Sleep).
  1516. receive_loop(Message, Timeout) ->
  1517. receive_loop(Message, Timeout, 0, []).
  1518. receive_loop(Message, Timeout, N, Acc) ->
  1519. receive {Pid, Message} ->
  1520. receive_loop(Message, Timeout, N + 1, [Pid|Acc])
  1521. after Timeout ->
  1522. {N, Acc}
  1523. end.
  1524. terminate_loop(_, []) ->
  1525. ok;
  1526. terminate_loop(Message, [Pid|Pids]) ->
  1527. Pid ! Message,
  1528. terminate_loop(Message, Pids).
  1529. clean_traces() ->
  1530. receive
  1531. {trace, _, _, _} ->
  1532. clean_traces();
  1533. {trace, _, _, _, _} ->
  1534. clean_traces()
  1535. after 0 ->
  1536. ok
  1537. end.
  1538. do_get_listener_socket(ListenerSupPid) ->
  1539. [LSocket] = do_get_listener_sockets(ListenerSupPid),
  1540. LSocket.
  1541. do_get_listener_sockets(ListenerSupPid) ->
  1542. [AcceptorsSupPid] = [Pid || {ranch_acceptors_sup, Pid, supervisor, _}
  1543. <- supervisor:which_children(ListenerSupPid)],
  1544. {links, Links} = erlang:process_info(AcceptorsSupPid, links),
  1545. [P || P <- Links, is_port(P)].
  1546. do_conns_which_children(Name) ->
  1547. Conns = [supervisor:which_children(ConnsSup) ||
  1548. {_, ConnsSup} <- ranch_server:get_connections_sups(Name)],
  1549. lists:flatten(Conns).
  1550. do_conns_count_children(Name) ->
  1551. lists:foldl(
  1552. fun
  1553. (Stats, undefined) ->
  1554. Stats;
  1555. (Stats, Acc) ->
  1556. lists:zipwith(
  1557. fun ({K, V1}, {K, V2}) -> {K, V1+V2} end,
  1558. Acc,
  1559. Stats
  1560. )
  1561. end,
  1562. undefined,
  1563. [supervisor:count_children(ConnsSup) ||
  1564. {_, ConnsSup} <- ranch_server:get_connections_sups(Name)]
  1565. ).
  1566. do_os_supports_reuseport() ->
  1567. case {os:type(), os:version()} of
  1568. {{unix, linux}, {Major, _, _}} when Major > 3 -> true;
  1569. {{unix, linux}, {3, Minor, _}} when Minor >= 9 -> true;
  1570. _ -> false
  1571. end.
  1572. do_os_supports_local_sockets() ->
  1573. case os:type() of
  1574. {unix, _} -> true;
  1575. _ -> false
  1576. end.
  1577. do_tempname() ->
  1578. list_to_binary(lists:droplast(os:cmd("mktemp -u"))).