acceptor_SUITE.erl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. %% Copyright (c) 2011-2012, 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. -include_lib("common_test/include/ct.hrl").
  16. %% ct.
  17. -export([all/0]).
  18. -export([groups/0]).
  19. -export([init_per_suite/1]).
  20. -export([end_per_suite/1]).
  21. -export([init_per_group/2]).
  22. -export([end_per_group/2]).
  23. %% misc.
  24. -export([misc_bad_transport/1]).
  25. %% ssl.
  26. -export([ssl_accept_error/1]).
  27. -export([ssl_accept_socket/1]).
  28. -export([ssl_active_echo/1]).
  29. -export([ssl_echo/1]).
  30. %% tcp.
  31. -export([tcp_accept_socket/1]).
  32. -export([tcp_active_echo/1]).
  33. -export([tcp_echo/1]).
  34. -export([tcp_max_connections/1]).
  35. -export([tcp_max_connections_and_beyond/1]).
  36. -export([tcp_set_max_connections/1]).
  37. -export([tcp_infinity_max_connections/1]).
  38. -export([tcp_upgrade/1]).
  39. %% supervisor.
  40. -export([supervisor_clean_restart/1]).
  41. -export([supervisor_clean_child_restart/1]).
  42. -export([supervisor_conns_alive/1]).
  43. %% ct.
  44. all() ->
  45. [{group, tcp}, {group, ssl}, {group, misc}, {group, supervisor}].
  46. groups() ->
  47. [{tcp, [
  48. tcp_accept_socket,
  49. tcp_active_echo,
  50. tcp_echo,
  51. tcp_max_connections,
  52. tcp_infinity_max_connections,
  53. tcp_max_connections_and_beyond,
  54. tcp_set_max_connections,
  55. tcp_upgrade
  56. ]}, {ssl, [
  57. ssl_accept_error,
  58. ssl_accept_socket,
  59. ssl_active_echo,
  60. ssl_echo
  61. ]}, {misc, [
  62. misc_bad_transport
  63. ]}, {supervisor, [
  64. supervisor_clean_restart,
  65. supervisor_clean_child_restart,
  66. supervisor_conns_alive
  67. ]}].
  68. init_per_suite(Config) ->
  69. ok = application:start(ranch),
  70. Config.
  71. end_per_suite(_) ->
  72. application:stop(ranch),
  73. ok.
  74. init_per_group(ssl, Config) ->
  75. application:start(crypto),
  76. application:start(public_key),
  77. application:start(ssl),
  78. Config;
  79. init_per_group(_, Config) ->
  80. Config.
  81. end_per_group(ssl, _) ->
  82. application:stop(ssl),
  83. application:stop(public_key),
  84. application:stop(crypto),
  85. ok;
  86. end_per_group(_, _) ->
  87. ok.
  88. %% misc.
  89. misc_bad_transport(_) ->
  90. {error, badarg} = ranch:start_listener(misc_bad_transport, 1,
  91. bad_transport, [{port, 0}],
  92. echo_protocol, []),
  93. ok.
  94. %% ssl.
  95. ssl_accept_error(Config) ->
  96. Name = ssl_accept_error,
  97. {ok, ListenerSup} = ranch:start_listener(Name, 1,
  98. ranch_ssl, [{port, 0},
  99. {certfile, ?config(data_dir, Config) ++ "cert.pem"}],
  100. echo_protocol, []),
  101. Port = ranch:get_port(Name),
  102. ListenerSupChildren = supervisor:which_children(ListenerSup),
  103. {_, AcceptorsSup, _, _}
  104. = lists:keyfind(ranch_acceptors_sup, 1, ListenerSupChildren),
  105. [{{acceptor, _, _}, AcceptorPid, _, _}]
  106. = supervisor:which_children(AcceptorsSup),
  107. true = is_process_alive(AcceptorPid),
  108. {ok, Socket} = gen_tcp:connect("localhost", Port,
  109. [binary, {active, false}, {packet, raw}]),
  110. ok = gen_tcp:close(Socket),
  111. receive after 500 -> ok end,
  112. true = is_process_alive(AcceptorPid),
  113. ranch:stop_listener(Name).
  114. ssl_accept_socket(Config) ->
  115. %%% XXX we can't do the spawn to test the controlling process change
  116. %%% because of the bug in ssl
  117. Name = ssl_accept_socket,
  118. {ok, S} = ssl:listen(0,
  119. [{certfile, ?config(data_dir, Config) ++ "cert.pem"}, binary,
  120. {active, false}, {packet, raw}, {reuseaddr, true}]),
  121. {ok, _} = ranch:start_listener(Name, 1,
  122. ranch_ssl, [{socket, S}], echo_protocol, []),
  123. Port = ranch:get_port(Name),
  124. {ok, Socket} = ssl:connect("localhost", Port,
  125. [binary, {active, false}, {packet, raw},
  126. {certfile, ?config(data_dir, Config) ++ "cert.pem"}]),
  127. ok = ssl:send(Socket, <<"TCP Ranch is working!">>),
  128. {ok, <<"TCP Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  129. ok = ranch:stop_listener(Name),
  130. {error, closed} = ssl:recv(Socket, 0, 1000),
  131. %% Make sure the listener stopped.
  132. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  133. ok.
  134. ssl_active_echo(Config) ->
  135. Name = ssl_active_echo,
  136. {ok, _} = ranch:start_listener(Name, 1,
  137. ranch_ssl, [{port, 0},
  138. {certfile, ?config(data_dir, Config) ++ "cert.pem"}],
  139. active_echo_protocol, []),
  140. Port = ranch:get_port(Name),
  141. {ok, Socket} = ssl:connect("localhost", Port,
  142. [binary, {active, false}, {packet, raw},
  143. {certfile, ?config(data_dir, Config) ++ "cert.pem"}]),
  144. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  145. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  146. ok = ranch:stop_listener(Name),
  147. {error, closed} = ssl:recv(Socket, 0, 1000),
  148. %% Make sure the listener stopped.
  149. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  150. ok.
  151. ssl_echo(Config) ->
  152. Name = ssl_echo,
  153. {ok, _} = ranch:start_listener(Name, 1,
  154. ranch_ssl, [{port, 0},
  155. {certfile, ?config(data_dir, Config) ++ "cert.pem"}],
  156. echo_protocol, []),
  157. Port = ranch:get_port(Name),
  158. {ok, Socket} = ssl:connect("localhost", Port,
  159. [binary, {active, false}, {packet, raw},
  160. {certfile, ?config(data_dir, Config) ++ "cert.pem"}]),
  161. ok = ssl:send(Socket, <<"SSL Ranch is working!">>),
  162. {ok, <<"SSL Ranch is working!">>} = ssl:recv(Socket, 21, 1000),
  163. ok = ranch:stop_listener(Name),
  164. {error, closed} = ssl:recv(Socket, 0, 1000),
  165. %% Make sure the listener stopped.
  166. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  167. ok.
  168. %% tcp.
  169. tcp_accept_socket(_) ->
  170. Name = tcp_accept_socket,
  171. Ref = make_ref(),
  172. Parent = self(),
  173. spawn(fun() ->
  174. {ok, S} = gen_tcp:listen(0, [binary, {active, false}, {packet, raw},
  175. {reuseaddr, true}]),
  176. {ok, _} = ranch:start_listener(Name, 1,
  177. ranch_tcp, [{socket, S}], echo_protocol, []),
  178. Parent ! Ref
  179. end),
  180. receive
  181. Ref -> ok
  182. end,
  183. Port = ranch:get_port(Name),
  184. {ok, Socket} = gen_tcp:connect("localhost", Port,
  185. [binary, {active, false}, {packet, raw}]),
  186. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  187. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  188. ok = ranch:stop_listener(Name),
  189. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  190. %% Make sure the listener stopped.
  191. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  192. ok.
  193. tcp_active_echo(_) ->
  194. Name = tcp_active_echo,
  195. {ok, _} = ranch:start_listener(Name, 1,
  196. ranch_tcp, [{port, 0}], active_echo_protocol, []),
  197. Port = ranch:get_port(Name),
  198. {ok, Socket} = gen_tcp:connect("localhost", Port,
  199. [binary, {active, false}, {packet, raw}]),
  200. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  201. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  202. ok = ranch:stop_listener(Name),
  203. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  204. %% Make sure the listener stopped.
  205. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  206. ok.
  207. tcp_echo(_) ->
  208. Name = tcp_echo,
  209. {ok, _} = ranch:start_listener(Name, 1,
  210. ranch_tcp, [{port, 0}], echo_protocol, []),
  211. Port = ranch:get_port(Name),
  212. {ok, Socket} = gen_tcp:connect("localhost", Port,
  213. [binary, {active, false}, {packet, raw}]),
  214. ok = gen_tcp:send(Socket, <<"TCP Ranch is working!">>),
  215. {ok, <<"TCP Ranch is working!">>} = gen_tcp:recv(Socket, 21, 1000),
  216. ok = ranch:stop_listener(Name),
  217. {error, closed} = gen_tcp:recv(Socket, 0, 1000),
  218. %% Make sure the listener stopped.
  219. {'EXIT', _} = begin catch ranch:get_port(Name) end,
  220. ok.
  221. tcp_max_connections(_) ->
  222. Name = tcp_max_connections,
  223. {ok, _} = ranch:start_listener(Name, 1,
  224. ranch_tcp, [{port, 0}, {max_connections, 10}],
  225. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  226. Port = ranch:get_port(Name),
  227. ok = connect_loop(Port, 11, 150),
  228. 10 = ranch_server:count_connections(Name),
  229. 10 = receive_loop(connected, 400),
  230. 1 = receive_loop(connected, 1000),
  231. ranch:stop_listener(Name).
  232. tcp_max_connections_and_beyond(_) ->
  233. Name = tcp_max_connections_and_beyond,
  234. {ok, _} = ranch:start_listener(Name, 1,
  235. ranch_tcp, [{port, 0}, {max_connections, 10}],
  236. remove_conn_and_wait_protocol, [{remove, true}]),
  237. Port = ranch:get_port(Name),
  238. ok = connect_loop(Port, 10, 0),
  239. receive after 250 -> ok end,
  240. 0 = ranch_server:count_connections(Name),
  241. 10 = length(supervisor:which_children(
  242. ranch_server:lookup_connections_sup(Name))),
  243. Counts = supervisor:count_children(
  244. ranch_server:lookup_connections_sup(Name)),
  245. {_, 1} = lists:keyfind(specs, 1, Counts),
  246. {_, 0} = lists:keyfind(supervisors, 1, Counts),
  247. {_, 10} = lists:keyfind(active, 1, Counts),
  248. {_, 10} = lists:keyfind(workers, 1, Counts),
  249. ranch:set_protocol_options(Name, [{remove, false}]),
  250. receive after 250 -> ok end,
  251. ok = connect_loop(Port, 10, 0),
  252. receive after 250 -> ok end,
  253. 10 = ranch_server:count_connections(Name),
  254. 20 = length(supervisor:which_children(
  255. ranch_server:lookup_connections_sup(Name))),
  256. Counts2 = supervisor:count_children(
  257. ranch_server:lookup_connections_sup(Name)),
  258. {_, 20} = lists:keyfind(active, 1, Counts2),
  259. {_, 20} = lists:keyfind(workers, 1, Counts2),
  260. ranch:stop_listener(Name).
  261. tcp_set_max_connections(_) ->
  262. Name = tcp_set_max_connections,
  263. {ok, _} = ranch:start_listener(Name, 1,
  264. ranch_tcp, [{port, 0}, {max_connections, 10}],
  265. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  266. Port = ranch:get_port(Name),
  267. ok = connect_loop(Port, 20, 0),
  268. 10 = ranch_server:count_connections(Name),
  269. 10 = receive_loop(connected, 1000),
  270. 10 = ranch:get_max_connections(Name),
  271. ranch:set_max_connections(Name, 20),
  272. 10 = receive_loop(connected, 1000),
  273. 20 = ranch:get_max_connections(Name),
  274. ranch:stop_listener(Name).
  275. tcp_infinity_max_connections(_) ->
  276. Name = tcp_infinity_max_connections,
  277. {ok, _} = ranch:start_listener(Name, 1,
  278. ranch_tcp, [{port, 0}, {max_connections, 10}],
  279. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  280. Port = ranch:get_port(Name),
  281. ok = connect_loop(Port, 20, 0),
  282. 10 = ranch_server:count_connections(Name),
  283. 10 = receive_loop(connected, 1000),
  284. 10 = ranch_server:count_connections(Name),
  285. 10 = ranch:get_max_connections(Name),
  286. ranch:set_max_connections(Name, infinity),
  287. receive after 250 -> ok end,
  288. 20 = ranch_server:count_connections(Name),
  289. infinity = ranch:get_max_connections(Name),
  290. ranch:set_max_connections(Name, 10),
  291. 20 = ranch_server:count_connections(Name),
  292. 10 = receive_loop(connected, 1000),
  293. ranch:stop_listener(Name).
  294. tcp_upgrade(_) ->
  295. Name = tcp_upgrade,
  296. {ok, _} = ranch:start_listener(Name, 1,
  297. ranch_tcp, [{port, 0}],
  298. notify_and_wait_protocol, [{msg, connected}, {pid, self()}]),
  299. Port = ranch:get_port(Name),
  300. ok = connect_loop(Port, 1, 0),
  301. receive connected -> ok after 1000 -> error(timeout) end,
  302. ranch:set_protocol_options(Name, [{msg, upgraded}, {pid, self()}]),
  303. ok = connect_loop(Port, 1, 0),
  304. receive upgraded -> ok after 1000 -> error(timeout) end,
  305. ranch:stop_listener(Name).
  306. %% Supervisor tests
  307. supervisor_clean_restart(_) ->
  308. %% There we verify that mature listener death will not let
  309. %% whole supervisor down and also the supervisor itself will
  310. %% restart everything properly.
  311. Name = supervisor_clean_restart,
  312. NbAcc = 4,
  313. {ok, Pid} = ranch:start_listener(Name,
  314. NbAcc, ranch_tcp, [{port, 0}], echo_protocol, []),
  315. %% Trace supervisor spawns.
  316. 1 = erlang:trace(Pid, true, [procs, set_on_spawn]),
  317. ListenerPid0 = ranch_server:lookup_listener(Name),
  318. erlang:exit(ListenerPid0, kill),
  319. receive after 1000 -> ok end,
  320. %% Verify that supervisor is alive
  321. true = is_process_alive(Pid),
  322. %% ...but children are dead.
  323. false = is_process_alive(ListenerPid0),
  324. %% Receive traces from newly started children
  325. ListenerPid = receive {trace, Pid, spawn, Pid1, _} -> Pid1 end,
  326. _ConnSupPid = receive {trace, Pid, spawn, Pid2, _} -> Pid2 end,
  327. AccSupPid = receive {trace, Pid, spawn, Pid3, _} -> Pid3 end,
  328. %% ...and its acceptors.
  329. [receive {trace, AccSupPid, spawn, _Pid, _} -> ok end ||
  330. _ <- lists:seq(1, NbAcc)],
  331. %% No more traces then.
  332. receive
  333. {trace, EPid, spawn, _, _} when EPid == Pid; EPid == AccSupPid ->
  334. error(invalid_restart)
  335. after 1000 -> ok end,
  336. %% Verify that new children registered themselves properly.
  337. ListenerPid = ranch_server:lookup_listener(Name),
  338. _ = erlang:trace(all, false, [all]),
  339. ok = clean_traces(),
  340. ranch:stop_listener(Name).
  341. supervisor_clean_child_restart(_) ->
  342. %% Then we verify that only parts of the supervision tree
  343. %% restarted in the case of failure.
  344. Name = supervisor_clean_child_restart,
  345. %% Trace socket allocations.
  346. _ = erlang:trace(new, true, [call]),
  347. 1 = erlang:trace_pattern({ranch_tcp, listen, 1},
  348. [{'_', [], [{return_trace}]}], [global]),
  349. {ok, Pid} = ranch:start_listener(Name,
  350. 1, ranch_tcp, [{port, 0}], echo_protocol, []),
  351. %% Trace supervisor spawns.
  352. 1 = erlang:trace(Pid, true, [procs, set_on_spawn]),
  353. ListenerPid = ranch_server:lookup_listener(Name),
  354. %% Manually shut the listening socket down.
  355. LSocket = receive
  356. {trace, _, return_from, {ranch_tcp, listen, 1}, {ok, Socket}} ->
  357. Socket
  358. after 0 ->
  359. error(lsocket_unknown)
  360. end,
  361. ok = gen_tcp:close(LSocket),
  362. receive after 1000 -> ok end,
  363. %% Verify that supervisor and its first two children are alive.
  364. true = is_process_alive(Pid),
  365. true = is_process_alive(ListenerPid),
  366. %% Check that acceptors_sup is restarted properly.
  367. AccSupPid = receive {trace, Pid, spawn, Pid1, _} -> Pid1 end,
  368. receive {trace, AccSupPid, spawn, _, _} -> ok end,
  369. %% No more traces then.
  370. receive
  371. {trace, _, spawn, _, _} -> error(invalid_restart)
  372. after 1000 -> ok end,
  373. %% Verify that children still registered right.
  374. ListenerPid = ranch_server:lookup_listener(Name),
  375. _ = erlang:trace_pattern({ranch_tcp, listen, 1}, false, []),
  376. _ = erlang:trace(all, false, [all]),
  377. ok = clean_traces(),
  378. ranch:stop_listener(Name).
  379. supervisor_conns_alive(_) ->
  380. %% And finally we make sure that in the case of partial failure
  381. %% live connections are not being killed.
  382. Name = supervisor_conns_alive,
  383. _ = erlang:trace(new, true, [call]),
  384. 1 = erlang:trace_pattern({ranch_tcp, listen, 1},
  385. [{'_', [], [{return_trace}]}], [global]),
  386. {ok, _} = ranch:start_listener(Name, 1,
  387. ranch_tcp, [{port, 0}],
  388. remove_conn_and_wait_protocol, [{remove, false}]),
  389. %% Get the listener socket
  390. LSocket = receive
  391. {trace, _, return_from, {ranch_tcp, listen, 1}, {ok, S}} ->
  392. S
  393. after 0 ->
  394. error(lsocket_unknown)
  395. end,
  396. TcpPort = ranch:get_port(Name),
  397. {ok, Socket} = gen_tcp:connect("localhost", TcpPort,
  398. [binary, {active, true}, {packet, raw}]),
  399. %% Shut the socket down
  400. ok = gen_tcp:close(LSocket),
  401. %% Assert that client is still viable.
  402. receive {tcp_closed, _} -> error(closed) after 1500 -> ok end,
  403. ok = gen_tcp:send(Socket, <<"poke">>),
  404. receive {tcp_closed, _} -> ok end,
  405. _ = erlang:trace(all, false, [all]),
  406. ok = clean_traces(),
  407. ranch:stop_listener(Name).
  408. %% Utility functions.
  409. connect_loop(_, 0, _) ->
  410. ok;
  411. connect_loop(Port, N, Sleep) ->
  412. {ok, _} = gen_tcp:connect("localhost", Port,
  413. [binary, {active, false}, {packet, raw}]),
  414. receive after Sleep -> ok end,
  415. connect_loop(Port, N - 1, Sleep).
  416. receive_loop(Message, Timeout) ->
  417. receive_loop(Message, Timeout, 0).
  418. receive_loop(Message, Timeout, N) ->
  419. receive Message ->
  420. receive_loop(Message, Timeout, N + 1)
  421. after Timeout ->
  422. N
  423. end.
  424. clean_traces() ->
  425. receive
  426. {trace, _, _, _} ->
  427. clean_traces();
  428. {trace, _, _, _, _} ->
  429. clean_traces()
  430. after 0 ->
  431. ok
  432. end.