acceptor_SUITE.erl 13 KB

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