1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1998-2021. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(gen_tcp_misc_SUITE). 21 22-include_lib("common_test/include/ct.hrl"). 23-include("kernel_test_lib.hrl"). 24 25-export([ 26 all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 27 init_per_group/2,end_per_group/2, 28 controlling_process/1, controlling_process_self/1, 29 no_accept/1, close_with_pending_output/1, active_n/1, 30 active_n_closed/1, 31 data_before_close/1, 32 iter_max_socks/0, iter_max_socks/1, 33 get_status/1, 34 passive_sockets/1, accept_closed_by_other_process/1, 35 init_per_testcase/2, end_per_testcase/2, 36 otp_3924/1, closed_socket/1, 37 shutdown_active/1, shutdown_passive/1, shutdown_pending/1, 38 show_econnreset_active/1, show_econnreset_active_once/1, 39 show_econnreset_passive/1, econnreset_after_sync_send/1, 40 econnreset_after_async_send_active/1, 41 econnreset_after_async_send_active_once/1, 42 econnreset_after_async_send_passive/1, 43 linger_zero/1, linger_zero_sndbuf/1, 44 default_options/1, http_bad_packet/1, 45 busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1, 46 fill_sendq/1, partial_recv_and_close/1, 47 partial_recv_and_close_2/1,partial_recv_and_close_3/1,so_priority/1, 48 recvtos/1, recvttl/1, recvtosttl/1, recvtclass/1, 49 %% Accept tests 50 primitive_accept/1,multi_accept_close_listen/1,accept_timeout/1, 51 accept_timeouts_in_order/1,accept_timeouts_in_order2/1, 52 accept_timeouts_in_order3/1,accept_timeouts_in_order4/1, 53 accept_timeouts_in_order5/1,accept_timeouts_in_order6/1, 54 accept_timeouts_in_order7/1,accept_timeouts_mixed/1, 55 killing_acceptor/1, 56 killing_multi_acceptors/1, 57 killing_multi_acceptors2/1, 58 several_accepts_in_one_go/1, accept_system_limit/1, 59 active_once_closed/1, send_timeout/1, send_timeout_active/1, 60 otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1, 61 wrapping_oct/0, wrapping_oct/1, otp_9389/1, otp_13939/1, 62 otp_12242/1, delay_send_error/1, bidirectional_traffic/1, 63 socket_monitor1/1, 64 socket_monitor1_manys/1, 65 socket_monitor1_manyc/1, 66 socket_monitor1_demon_after/1, 67 socket_monitor2/1, 68 socket_monitor2_manys/1, 69 socket_monitor2_manyc/1, 70 otp_17492/1 71 ]). 72 73%% Internal exports. 74-export([sender/4, 75 not_owner/1, 76 passive_sockets_server/3, 77 priority_server/2, 78 %% oct_acceptor/1, 79 otp_3924_sender/5, 80 otp_7731_server/2, 81 zombie_server/3, 82 do_iter_max_socks/3]). 83 84init_per_testcase(_Func, Config) -> 85 ?P("init_per_testcase -> entry with" 86 "~n Config: ~p" 87 "~n Nodes: ~p" 88 "~n Links: ~p" 89 "~n Monitors: ~p", 90 [Config, erlang:nodes(), pi(links), pi(monitors)]), 91 92 kernel_test_global_sys_monitor:reset_events(), 93 94 ?P("init_per_testcase -> done when" 95 "~n Nodes: ~p" 96 "~n Links: ~p" 97 "~n Monitors: ~p", [erlang:nodes(), pi(links), pi(monitors)]), 98 Config. 99 100end_per_testcase(_Func, Config) -> 101 ?P("end_per_testcase -> entry with" 102 "~n Config: ~p" 103 "~n Nodes: ~p" 104 "~n Links: ~p" 105 "~n Monitors: ~p", 106 [Config, erlang:nodes(), pi(links), pi(monitors)]), 107 108 SysEvs = kernel_test_global_sys_monitor:events(), 109 110 ?P("system events during test: " 111 "~n ~p", [SysEvs]), 112 113 ?P("end_per_testcase -> done with" 114 "~n Nodes: ~p" 115 "~n Links: ~p" 116 "~n Monitors: ~p", [erlang:nodes(), pi(links), pi(monitors)]), 117 ok. 118 119suite() -> 120 [{ct_hooks,[ts_install_cth]}, 121 {timetrap,{minutes,4}}]. 122 123all() -> 124 %% This is a temporary messure to ensure that we can 125 %% test the socket backend without effecting *all* 126 %% applications on *all* machines. 127 %% This flag is set only for *one* host. 128 case ?TEST_INET_BACKENDS() of 129 true -> 130 [ 131 {group, inet_backend_default}, 132 {group, inet_backend_inet}, 133 {group, inet_backend_socket} 134 ]; 135 _ -> 136 [ 137 {group, inet_backend_default} 138 ] 139 end. 140 141groups() -> 142 [ 143 {inet_backend_default, [], inet_backend_default_cases()}, 144 {inet_backend_inet, [], inet_backend_inet_cases()}, 145 {inet_backend_socket, [], inet_backend_socket_cases()}, 146 147 {ctrl_proc, [], ctrl_proc_cases()}, 148 {close, [], close_cases()}, 149 {active, [], active_cases()}, 150 {shutdown, [], shutdown_cases()}, 151 {econnreset, [], econnreset_cases()}, 152 {linger_zero, [], linger_zero_cases()}, 153 {busy_disconnect, [], busy_disconnect_cases()}, 154 {partial_recv_and_close, [], partial_recv_and_close_cases()}, 155 {pktoptions, [], pktoptions_cases()}, 156 {accept, [], accept_cases()}, 157 {send_timeout, [], send_timeout_cases()}, 158 {socket_monitor, [], socket_monitor_cases()} 159 ]. 160 161inet_backend_default_cases() -> 162 all_cases(). 163 164inet_backend_inet_cases() -> 165 all_cases(). 166 167inet_backend_socket_cases() -> 168 all_cases(). 169 170all_cases() -> 171 [ 172 {group, ctrl_proc}, 173 iter_max_socks, 174 {group, close}, 175 {group, active}, 176 {group, shutdown}, 177 {group, econnreset}, 178 {group, linger_zero}, 179 default_options, http_bad_packet, busy_send, 180 {group, busy_disconnect}, 181 fill_sendq, 182 {group, partial_recv_and_close}, 183 so_priority, 184 {group, pktoptions}, 185 {group, accept}, 186 {group, send_timeout}, 187 otp_7731, 188 wrapping_oct, 189 zombie_sockets, 190 otp_7816, 191 otp_8102, otp_9389, 192 otp_12242, delay_send_error, 193 bidirectional_traffic, 194 {group, socket_monitor}, 195 otp_17492 196 ]. 197 198close_cases() -> 199 [ 200 no_accept, 201 close_with_pending_output, 202 data_before_close, 203 accept_closed_by_other_process, 204 otp_3924, 205 closed_socket 206 ]. 207 208ctrl_proc_cases() -> 209 [ 210 controlling_process, 211 controlling_process_self 212 ]. 213 214active_cases() -> 215 [ 216 passive_sockets, 217 active_n, 218 active_n_closed, 219 active_once_closed 220 ]. 221 222shutdown_cases() -> 223 [ 224 shutdown_active, 225 shutdown_passive, 226 shutdown_pending 227 ]. 228 229econnreset_cases() -> 230 [ 231 show_econnreset_active, 232 show_econnreset_active_once, 233 show_econnreset_passive, 234 econnreset_after_sync_send, 235 econnreset_after_async_send_active, 236 econnreset_after_async_send_active_once, 237 econnreset_after_async_send_passive 238 ]. 239 240linger_zero_cases() -> 241 [ 242 linger_zero, 243 linger_zero_sndbuf 244 ]. 245 246busy_disconnect_cases() -> 247 [ 248 busy_disconnect_passive, 249 busy_disconnect_active 250 ]. 251 252partial_recv_and_close_cases() -> 253 [ 254 partial_recv_and_close, 255 partial_recv_and_close_2, 256 partial_recv_and_close_3 257 ]. 258 259pktoptions_cases() -> 260 [ 261 recvtos, 262 recvttl, 263 recvtosttl, 264 recvtclass 265 ]. 266 267accept_cases() -> 268 [ 269 primitive_accept, 270 multi_accept_close_listen, 271 accept_timeout, 272 accept_timeouts_in_order, 273 accept_timeouts_in_order2, 274 accept_timeouts_in_order3, 275 accept_timeouts_in_order4, 276 accept_timeouts_in_order5, 277 accept_timeouts_in_order6, 278 accept_timeouts_in_order7, 279 accept_timeouts_mixed, 280 killing_acceptor, 281 killing_multi_acceptors, 282 killing_multi_acceptors2, 283 several_accepts_in_one_go, 284 accept_system_limit 285 ]. 286 287send_timeout_cases() -> 288 [ 289 send_timeout, 290 send_timeout_active 291 ]. 292 293socket_monitor_cases() -> 294 [ 295 socket_monitor1, 296 socket_monitor1_manys, 297 socket_monitor1_manyc, 298 socket_monitor1_demon_after, 299 socket_monitor2, 300 socket_monitor2_manys, 301 socket_monitor2_manyc 302 ]. 303 304init_per_suite(Config0) -> 305 306 ?P("init_per_suite -> entry with" 307 "~n Config: ~p" 308 "~n Nodes: ~p", [Config0, erlang:nodes()]), 309 310 case ?LIB:init_per_suite(Config0) of 311 {skip, _} = SKIP -> 312 SKIP; 313 314 Config1 when is_list(Config1) -> 315 316 ?P("init_per_suite -> end when " 317 "~n Config: ~p", [Config1]), 318 319 %% We need a monitor on this node also 320 kernel_test_sys_monitor:start(), 321 322 Config1 323 end. 324 325end_per_suite(Config0) -> 326 327 ?P("end_per_suite -> entry with" 328 "~n Config: ~p" 329 "~n Nodes: ~p", [Config0, erlang:nodes()]), 330 331 %% Stop the local monitor 332 kernel_test_sys_monitor:stop(), 333 334 Config1 = ?LIB:end_per_suite(Config0), 335 336 ?P("end_per_suite -> " 337 "~n Nodes: ~p", [erlang:nodes()]), 338 339 Config1. 340 341init_per_group(inet_backend_default = _GroupName, Config) -> 342 [{socket_create_opts, []} | Config]; 343init_per_group(inet_backend_inet = _GroupName, Config) -> 344 case ?EXPLICIT_INET_BACKEND() of 345 true -> 346 %% The environment trumps us, 347 %% so only the default group should be run! 348 {skip, "explicit inet backend"}; 349 false -> 350 [{socket_create_opts, [{inet_backend, inet}]} | Config] 351 end; 352init_per_group(inet_backend_socket = _GroupName, Config) -> 353 case ?EXPLICIT_INET_BACKEND() of 354 true -> 355 %% The environment trumps us, 356 %% so only the default group should be run! 357 {skip, "explicit inet backend"}; 358 false -> 359 [{socket_create_opts, [{inet_backend, socket}]} | Config] 360 end; 361init_per_group(_GroupName, Config) -> 362 Config. 363 364end_per_group(_GroupName, Config) -> 365 Config. 366 367-define(UNIQ_NODE_NAME, 368 list_to_atom(?MODULE_STRING ++ "__" ++ 369 atom_to_list(?FUNCTION_NAME) ++ "_" ++ 370 integer_to_list(erlang:unique_integer([positive])))). 371 372%% Tests kernel application variables inet_default_listen_options and 373%% inet_default_connect_options. 374default_options(Config) when is_list(Config) -> 375 ?TC_TRY(default_options, fun() -> do_default_options(Config) end). 376 377do_default_options(Config) -> 378 %% First check the delay_send option 379 {true,true,true}=do_delay_send_1(Config), 380 {false,false,false}=do_delay_send_2(Config), 381 {true,false,false}=do_delay_send_3(Config), 382 {false,false,false}=do_delay_send_4(Config), 383 {false,false,false}=do_delay_send_5(Config), 384 {false,true,true}=do_delay_send_6(Config), 385 %% Now lets start some nodes with different combinations of options: 386 {true,true,true} = 387 do_delay_on_other_node("", fun() -> do_delay_send_1(Config) end), 388 {true,false,false} = 389 do_delay_on_other_node("-kernel inet_default_connect_options " 390 "\"[{delay_send,true}]\"", 391 fun() -> do_delay_send_2(Config) end), 392 393 {false,true,true} = 394 do_delay_on_other_node("-kernel inet_default_listen_options " 395 "\"[{delay_send,true}]\"", 396 fun() -> do_delay_send_2(Config) end), 397 398 {true,true,true} = 399 do_delay_on_other_node("-kernel inet_default_listen_options " 400 "\"[{delay_send,true}]\"", 401 fun() -> do_delay_send_3(Config) end), 402 {true,true,true} = 403 do_delay_on_other_node("-kernel inet_default_connect_options " 404 "\"[{delay_send,true}]\"", 405 fun() -> do_delay_send_6(Config) end), 406 {false,false,false} = 407 do_delay_on_other_node("-kernel inet_default_connect_options " 408 "\"[{delay_send,true}]\"", 409 fun() -> do_delay_send_5(Config) end), 410 {false,true,true} = 411 do_delay_on_other_node("-kernel inet_default_connect_options " 412 "\"[{delay_send,true}]\" " 413 "-kernel inet_default_listen_options " 414 "\"[{delay_send,true}]\"", 415 fun() -> do_delay_send_5(Config) end), 416 {true,false,false} = 417 do_delay_on_other_node("-kernel inet_default_connect_options " 418 "\"[{delay_send,true}]\" " 419 "-kernel inet_default_listen_options " 420 "\"[{delay_send,true}]\"", 421 fun() -> do_delay_send_4(Config) end), 422 {true,true,true} = 423 do_delay_on_other_node("-kernel inet_default_connect_options " 424 "\"{delay_send,true}\" " 425 "-kernel inet_default_listen_options " 426 "\"{delay_send,true}\"", 427 fun() -> do_delay_send_2(Config) end), 428 %% Active is to dangerous and is supressed 429 {true,true,true} = 430 do_delay_on_other_node("-kernel inet_default_connect_options " 431 "\"{active,false}\" " 432 "-kernel inet_default_listen_options " 433 "\"{active,false}\"", 434 fun() -> do_delay_send_7(Config) end), 435 {true,true,true} = 436 do_delay_on_other_node("-kernel inet_default_connect_options " 437 "\"[{active,false},{delay_send,true}]\" " 438 "-kernel inet_default_listen_options " 439 "\"[{active,false},{delay_send,true}]\"", 440 fun() -> do_delay_send_7(Config) end), 441 {true,true,true} = 442 do_delay_on_other_node("-kernel inet_default_connect_options " 443 "\"[{active,false},{delay_send,true}]\" " 444 "-kernel inet_default_listen_options " 445 "\"[{active,false},{delay_send,true}]\"", 446 fun() -> do_delay_send_2(Config) end), 447 ok. 448 449 450do_delay_on_other_node(XArgs, Function) -> 451 Dir = filename:dirname(code:which(?MODULE)), 452 {ok, Node} = ?START_SLAVE_NODE(?UNIQ_NODE_NAME, 453 "-pa " ++ Dir ++ " " ++ XArgs), 454 Res = rpc:call(Node,erlang,apply,[Function,[]]), 455 ?STOP_NODE(Node), 456 Res. 457 458do_delay_send_1(Config) -> 459 {ok,LS} = ?LISTEN(Config, 0, [{delay_send,true}]), 460 {ok,{{0,0,0,0},PortNum}}=inet:sockname(LS), 461 S = case ?CONNECT(Config, "localhost", PortNum, [{delay_send,true}]) of 462 {ok, Sock} -> 463 Sock; 464 {error, eaddrnotavail = Reason} -> 465 ?SKIPT(connect_failed_str(Reason)) 466 end, 467 {ok,S2}= gen_tcp:accept(LS), 468 {ok,[{delay_send,B1}]}=inet:getopts(S,[delay_send]), 469 {ok,[{delay_send,B2}]}=inet:getopts(LS,[delay_send]), 470 {ok,[{delay_send,B3}]}=inet:getopts(S2,[delay_send]), 471 gen_tcp:close(S2), 472 gen_tcp:close(S), 473 gen_tcp:close(LS), 474 {B1,B2,B3}. 475 476do_delay_send_2(Config) -> 477 {ok, LS} = ?LISTEN(Config), 478 {ok, {{0,0,0,0},PortNum}} = inet:sockname(LS), 479 {ok, S} = ?CONNECT(Config, "localhost",PortNum,[]), 480 {ok, S2} = gen_tcp:accept(LS), 481 {ok, [{delay_send,B1}]} = inet:getopts(S,[delay_send]), 482 {ok, [{delay_send,B2}]} = inet:getopts(LS,[delay_send]), 483 {ok, [{delay_send,B3}]} = inet:getopts(S2,[delay_send]), 484 gen_tcp:close(S2), 485 gen_tcp:close(S), 486 gen_tcp:close(LS), 487 {B1,B2,B3}. 488 489do_delay_send_3(Config) -> 490 {ok, LS} = ?LISTEN(Config, 0, []), 491 {ok,{{0,0,0,0},PortNum}}=inet:sockname(LS), 492 {ok,S} = ?CONNECT(Config, "localhost", PortNum, [{delay_send,true}]), 493 {ok,S2}= gen_tcp:accept(LS), 494 {ok,[{delay_send,B1}]}=inet:getopts(S,[delay_send]), 495 {ok,[{delay_send,B2}]}=inet:getopts(LS,[delay_send]), 496 {ok,[{delay_send,B3}]}=inet:getopts(S2,[delay_send]), 497 gen_tcp:close(S2), 498 gen_tcp:close(S), 499 gen_tcp:close(LS), 500 {B1,B2,B3}. 501 502do_delay_send_4(Config) -> 503 {ok,LS} = ?LISTEN(Config, 0, [{delay_send,false}]), 504 {ok,{{0,0,0,0},PortNum}}=inet:sockname(LS), 505 {ok,S} = ?CONNECT(Config, "localhost", PortNum, []), 506 {ok,S2}= gen_tcp:accept(LS), 507 {ok,[{delay_send,B1}]}=inet:getopts(S,[delay_send]), 508 {ok,[{delay_send,B2}]}=inet:getopts(LS,[delay_send]), 509 {ok,[{delay_send,B3}]}=inet:getopts(S2,[delay_send]), 510 gen_tcp:close(S2), 511 gen_tcp:close(S), 512 gen_tcp:close(LS), 513 {B1,B2,B3}. 514 515do_delay_send_5(Config) -> 516 {ok,LS} = ?LISTEN(Config, 0, []), 517 {ok,{{0,0,0,0},PortNum}}=inet:sockname(LS), 518 {ok,S} = ?CONNECT(Config, "localhost",PortNum,[{delay_send,false}]), 519 {ok,S2}= gen_tcp:accept(LS), 520 {ok,[{delay_send,B1}]}=inet:getopts(S,[delay_send]), 521 {ok,[{delay_send,B2}]}=inet:getopts(LS,[delay_send]), 522 {ok,[{delay_send,B3}]}=inet:getopts(S2,[delay_send]), 523 gen_tcp:close(S2), 524 gen_tcp:close(S), 525 gen_tcp:close(LS), 526 {B1,B2,B3}. 527 528do_delay_send_6(Config) -> 529 {ok,LS} = ?LISTEN(Config, 0, [{delay_send,true}]), 530 {ok,{{0,0,0,0},PortNum}}=inet:sockname(LS), 531 {ok,S} = ?CONNECT(Config, "localhost", PortNum, []), 532 {ok,S2}= gen_tcp:accept(LS), 533 {ok,[{delay_send,B1}]}=inet:getopts(S,[delay_send]), 534 {ok,[{delay_send,B2}]}=inet:getopts(LS,[delay_send]), 535 {ok,[{delay_send,B3}]}=inet:getopts(S2,[delay_send]), 536 gen_tcp:close(S2), 537 gen_tcp:close(S), 538 gen_tcp:close(LS), 539 {B1,B2,B3}. 540 541do_delay_send_7(Config) -> 542 {ok,LS} = ?LISTEN(Config, 0, []), 543 {ok,{{0,0,0,0},PortNum}}=inet:sockname(LS), 544 {ok,S} = ?CONNECT(Config, "localhost", PortNum, []), 545 {ok,S2} = gen_tcp:accept(LS), 546 {ok,[{active,B1}]}=inet:getopts(S,[active]), 547 {ok,[{active,B2}]}=inet:getopts(LS,[active]), 548 {ok,[{active,B3}]}=inet:getopts(S2,[active]), 549 gen_tcp:close(S2), 550 gen_tcp:close(S), 551 gen_tcp:close(LS), 552 {B1,B2,B3}. 553 554%% Open a listen port and change controlling_process for it 555%% The result should be ok of done by the owner process, 556%% Otherwise is should return {error,not_owner} or similar. 557controlling_process(Config) when is_list(Config) -> 558 {ok, S} = ?LISTEN(Config, 0,[]), 559 Pid2 = spawn(?MODULE, not_owner, [S]), 560 Pid2 ! {self(),2,control}, 561 {error, E} = receive {2,_E} -> 562 _E 563 after 10000 -> timeout 564 end, 565 io:format("received ~p~n",[E]), 566 Pid = spawn(?MODULE,not_owner,[S]), 567 ok = gen_tcp:controlling_process(S,Pid), 568 Pid ! {self(),1,control}, 569 ok = receive {1,ok} -> 570 ok 571 after 1000 -> timeout 572 end, 573 Pid ! close. 574 575not_owner(S) -> 576 receive 577 {From,Tag,control} -> 578 From ! {Tag,gen_tcp:controlling_process(S,self())}; 579 close -> 580 gen_tcp:close(S) 581 after 1000 -> 582 ok 583 end. 584 585%% Open a listen port and assign the controlling process to 586%% it self, then exit and make sure the port is closed properly. 587controlling_process_self(Config) when is_list(Config) -> 588 S = self(), 589 process_flag(trap_exit,true), 590 spawn_link(fun() -> 591 {ok,Sock} = ?LISTEN(Config, 0, []), 592 S ! {socket, Sock}, 593 ok = gen_tcp:controlling_process(Sock,self()), 594 S ! done 595 end), 596 receive 597 done -> 598 receive 599 {socket,Sock} -> 600 process_flag(trap_exit,false), 601 %% Make sure the port is invalid after process crash 602 receive after 500 -> ok end, 603 case inet:port(Sock) of 604 {error,einval} -> ok; 605 {error,closed} -> ok % XXX gen_tcp_socket 606 end 607 608 end; 609 Msg when element(1,Msg) /= socket -> 610 process_flag(trap_exit,false), 611 exit({unknown_msg,Msg}) 612 end. 613 614 615%% Open a listen port and connect to it, then close the listen port 616%% without doing any accept. The connected socket should receive 617%% a tcp_closed message. 618no_accept(Config) when is_list(Config) -> 619 {ok, L} = ?LISTEN(Config, 0, []), 620 {ok, {_, Port}} = inet:sockname(L), 621 {ok, Client} = ?CONNECT(Config, localhost, Port, []), 622 ok = gen_tcp:close(L), 623 receive 624 {tcp_closed, Client} -> 625 ok 626 after 5000 -> 627 ct:fail(never_closed) 628 629 end. 630 631%% Send several packets to a socket and close it. All packets should 632%% arrive to the other end. 633close_with_pending_output(Config) when is_list(Config) -> 634 {ok, L} = ?LISTEN(Config, 0, [binary, {active, false}]), 635 {ok, {_, Port}} = inet:sockname(L), 636 Packets = 16, 637 Total = 2048*Packets, 638 case start_remote(close_pending) of 639 {ok, Node} -> 640 {ok, Host} = inet:gethostname(), 641 spawn_link(Node, ?MODULE, sender, [Config, Port, Packets, Host]), 642 {ok, A} = gen_tcp:accept(L), 643 case gen_tcp:recv(A, Total) of 644 {ok, Bin} when byte_size(Bin) == Total -> 645 gen_tcp:close(A), 646 gen_tcp:close(L); 647 {ok, Bin} -> 648 ct:fail({small_packet, 649 byte_size(Bin)}); 650 Error -> 651 ct:fail({unexpected, Error}) 652 end, 653 ok; 654 {error, no_remote_hosts} -> 655 {skipped,"No remote hosts"}; 656 {error, Other} -> 657 ct:fail({failed_to_start_slave_node, Other}) 658 end. 659 660sender(Config, Port, Packets, Host) -> 661 X256 = lists:seq(0, 255), 662 X512 = [X256|X256], 663 X1K = [X512|X512], 664 Bin = list_to_binary([X1K|X1K]), 665 {ok, Sock} = ?CONNECT(Config, Host, Port, []), 666 send_loop(Sock, Bin, Packets), 667 ok = gen_tcp:close(Sock). 668 669send_loop(_Sock, _Data, 0) -> ok; 670send_loop(Sock, Data, Left) -> 671 ok = gen_tcp:send(Sock, Data), 672 send_loop(Sock, Data, Left-1). 673 674%% Test {active,N} option 675%% Verify operation of the {active,N} option. 676active_n(Config) when is_list(Config) -> 677 ?TC_TRY(active_n, fun() -> do_active_n(Config) end). 678 679do_active_n(Config) -> 680 N = 3, 681 LS = ok(?LISTEN(Config, 0, [{active,N}])), 682 [{active,N}] = ok(inet:getopts(LS, [active])), 683 ok = inet:setopts(LS, [{active,-N}]), 684 receive 685 {tcp_passive, LS} -> ok 686 after 687 5000 -> 688 exit({error,tcp_passive_failure}) 689 end, 690 [{active,false}] = ok(inet:getopts(LS, [active])), 691 ok = inet:setopts(LS, [{active,0}]), 692 receive 693 {tcp_passive, LS} -> ok 694 after 695 5000 -> 696 exit({error,tcp_passive_failure}) 697 end, 698 ok = inet:setopts(LS, [{active,32767}]), 699 {error,einval} = inet:setopts(LS, [{active,1}]), 700 {error,einval} = inet:setopts(LS, [{active,-32769}]), 701 ok = inet:setopts(LS, [{active,-32768}]), 702 receive 703 {tcp_passive, LS} -> ok 704 after 705 5000 -> 706 exit({error,tcp_passive_failure}) 707 end, 708 [{active,false}] = ok(inet:getopts(LS, [active])), 709 ok = inet:setopts(LS, [{active,N}]), 710 ok = inet:setopts(LS, [{active,true}]), 711 [{active,true}] = ok(inet:getopts(LS, [active])), 712 receive 713 _ -> exit({error,active_n}) 714 after 715 0 -> 716 ok 717 end, 718 ok = inet:setopts(LS, [{active,N}]), 719 ok = inet:setopts(LS, [{active,once}]), 720 [{active,once}] = ok(inet:getopts(LS, [active])), 721 receive 722 _ -> exit({error,active_n}) 723 after 724 0 -> 725 ok 726 end, 727 {error,einval} = inet:setopts(LS, [{active,32768}]), 728 ok = inet:setopts(LS, [{active,false}]), 729 [{active,false}] = ok(inet:getopts(LS, [active])), 730 Port = ok(inet:port(LS)), 731 C = case ?CONNECT(Config, "localhost", Port, [{active,N}]) of 732 {ok, CS} -> 733 CS; 734 {error, eaddrnotavail = Reason} -> 735 ?SKIPT(connect_failed_str(Reason)) 736 end, 737 [{active,N}] = ok(inet:getopts(C, [active])), 738 S = ok(gen_tcp:accept(LS)), 739 ok = inet:setopts(S, [{active,N}]), 740 [{active,N}] = ok(inet:getopts(S, [active])), 741 repeat(3, 742 fun(I) -> 743 Msg = "message "++integer_to_list(I), 744 ok = gen_tcp:send(C, Msg), 745 receive 746 {tcp,S,Msg} -> 747 ok = gen_tcp:send(S, Msg) 748 after 749 5000 -> 750 exit({error,timeout}) 751 end, 752 receive 753 {tcp,C,Msg} -> 754 ok 755 after 756 5000 -> 757 exit({error,timeout}) 758 end 759 end), 760 receive 761 {tcp_passive,S} -> 762 [{active,false}] = ok(inet:getopts(S, [active])) 763 after 764 5000 -> 765 exit({error,tcp_passive}) 766 end, 767 receive 768 {tcp_passive,C} -> 769 [{active,false}] = ok(inet:getopts(C, [active])) 770 after 771 5000 -> 772 exit({error,tcp_passive}) 773 end, 774 LS2 = ok(?LISTEN(Config, 0, [{active,0}])), 775 receive 776 {tcp_passive,LS2} -> 777 [{active,false}] = ok(inet:getopts(LS2, [active])) 778 after 779 5000 -> 780 exit({error,tcp_passive}) 781 end, 782 ok = gen_tcp:close(LS2), 783 ok = gen_tcp:close(C), 784 ok = gen_tcp:close(S), 785 ok = gen_tcp:close(LS), 786 ok. 787 788-define(OTP_3924_MAX_DELAY, 100). 789%% Taken out of the blue, but on intra host connections 790%% I expect propagation of a close to be quite fast 791%% so 100 ms seems reasonable. 792 793%% Tests that a socket can be closed fast enough. 794otp_3924(Config) when is_list(Config) -> 795 MaxDelay = (case has_superfluous_schedulers() of 796 true -> 4; 797 false -> 1 798 end 799 * case {erlang:system_info(debug_compiled), 800 erlang:system_info(lock_checking)} of 801 {true, _} -> 6; 802 {_, true} -> 2; 803 _ -> 1 804 end * ?OTP_3924_MAX_DELAY), 805 otp_3924_1(Config, MaxDelay). 806 807otp_3924_1(Config, MaxDelay) -> 808 {ok, Node} = start_node(otp_3924), 809 DataLen = 100*1024, 810 Data = otp_3924_data(DataLen), 811 %% Repeat the test a couple of times to prevent the test from passing 812 %% by chance. 813 repeat(10, fun(N) -> 814 ok = otp_3924(Config, MaxDelay, Node, Data, DataLen, N) 815 end), 816 ?STOP_NODE(Node), 817 ok. 818 819otp_3924(Config, MaxDelay, Node, Data, DataLen, N) -> 820 {ok, L} = ?LISTEN(Config, 0, [list, {active, false}]), 821 {ok, {_, Port}} = inet:sockname(L), 822 {ok, Host} = inet:gethostname(), 823 Sender = spawn_link(Node, 824 ?MODULE, 825 otp_3924_sender, 826 [Config, self(), Host, Port, Data]), 827 Data = otp_3924_receive_data(L, Sender, MaxDelay, DataLen, N), 828 ok = gen_tcp:close(L). 829 830otp_3924_receive_data(LSock, Sender, MaxDelay, Len, N) -> 831 OP = process_flag(priority, max), 832 OTE = process_flag(trap_exit, true), 833 TimeoutRef = make_ref(), 834 Data = (catch begin 835 Sender ! start, 836 {ok, Sock} = gen_tcp:accept(LSock), 837 D = otp_3924_receive_data(Sock, 838 TimeoutRef, 839 MaxDelay, 840 Len, 841 [], 842 0), 843 ok = gen_tcp:close(Sock), 844 D 845 end), 846 unlink(Sender), 847 process_flag(trap_exit, OTE), 848 process_flag(priority, OP), 849 receive 850 {'EXIT', _, TimeoutRef} -> 851 ct:fail({close_not_fast_enough,MaxDelay,N}); 852 {'EXIT', Sender, Reason} -> 853 ct:fail({sender_exited, Reason}); 854 {'EXIT', _Other, Reason} -> 855 ct:fail({linked_process_exited, Reason}) 856 after 0 -> 857 case Data of 858 {'EXIT', {A,B}} -> 859 ct:fail({A,B,N}); 860 {'EXIT', Failure} -> 861 ct:fail(Failure); 862 _ -> 863 Data 864 end 865 end. 866 867 868otp_3924_receive_data(Sock, TimeoutRef, MaxDelay, Len, Acc, AccLen) -> 869 case gen_tcp:recv(Sock, 0) of 870 {ok, Data} -> 871 NewAccLen = AccLen + length(Data), 872 if 873 NewAccLen == Len -> 874 {ok, TRef} = timer:exit_after(MaxDelay, 875 self(), 876 TimeoutRef), 877 {error, closed} = gen_tcp:recv(Sock, 0), 878 timer:cancel(TRef), 879 lists:flatten([Acc, Data]); 880 NewAccLen > Len -> 881 exit({received_too_much, NewAccLen}); 882 true -> 883 otp_3924_receive_data(Sock, 884 TimeoutRef, 885 MaxDelay, 886 Len, 887 [Acc, Data], 888 NewAccLen) 889 end; 890 {error, closed} -> 891 exit({premature_close, AccLen}); 892 Error -> 893 exit({unexpected_error, Error}) 894 end. 895 896otp_3924_data(Size) -> 897 Block = 898 "This is a sequence of characters that will be repeated " 899 "again and again and again and again and again and ... ", 900 L = length(Block), 901 otp_3924_data(Block, [], Size div L, Size rem L). 902 903otp_3924_data(_, Acc, 0, 0) -> 904 lists:flatten(Acc); 905otp_3924_data(_, Acc, 0, SingleLeft) -> 906 otp_3924_data(false, ["."|Acc], 0, SingleLeft-1); 907otp_3924_data(Block, Acc, BlockLeft, SingleLeft) -> 908 otp_3924_data(Block, [Block|Acc], BlockLeft-1, SingleLeft). 909 910otp_3924_sender(Config, Receiver, Host, Port, Data) -> 911 receive 912 start -> 913 {ok, Sock} = ?CONNECT(Config, Host, Port, [list]), 914 gen_tcp:send(Sock, Data), 915 ok = gen_tcp:close(Sock), 916 unlink(Receiver) 917 end. 918 919 920%% Tests that a huge amount of data can be received before a close. 921data_before_close(Config) when is_list(Config) -> 922 {ok, L} = ?LISTEN(Config, 0, [binary]), 923 {ok, {_, TcpPort}} = inet:sockname(L), 924 Bytes = 256*1024, 925 spawn_link(fun() -> huge_sender(Config, TcpPort, Bytes) end), 926 {ok, A} = gen_tcp:accept(L), 927 case count_bytes_recv(A, 0) of 928 {Bytes, Result} -> 929 io:format("Result: ~p", [Result]); 930 {Wrong, Result} -> 931 io:format("Result: ~p", [Result]), 932 ct:fail({wrong_count, Wrong}) 933 end, 934 ok. 935 936count_bytes_recv(Sock, Total) -> 937 receive 938 {tcp, Sock, Bin} -> 939 count_bytes_recv(Sock, Total+byte_size(Bin)); 940 Other -> 941 {Total, Other} 942 end. 943 944huge_sender(Config, TcpPort, Bytes) -> 945 {ok, Client} = ?CONNECT(Config, localhost, TcpPort, []), 946 receive after 500 -> ok end, 947 gen_tcp:send(Client, make_zero_packet(Bytes)), 948 gen_tcp:close(Client). 949 950make_zero_packet(0) -> []; 951make_zero_packet(N) when N rem 2 == 0 -> 952 P = make_zero_packet(N div 2), 953 [P|P]; 954make_zero_packet(N) -> 955 P = make_zero_packet(N div 2), 956 [0, P|P]. 957 958%% OTP-2924. Test that the socket process does not crash when 959%% sys:get_status(Pid) is called. 960get_status(Config) when is_list(Config) -> 961 {ok,{socket,Pid,_,_}} = ?LISTEN(Config, 5678,[]), 962 {status,Pid,_,_} = sys:get_status(Pid). 963 964-define(RECOVER_SLEEP, 60000). 965-define(RETRY_SLEEP, 15000). 966 967iter_max_socks() -> 968 [{timetrap,{minutes,30}}]. 969 970%% Open as many sockets as possible. Do this several times and check 971%% that we get the same number of sockets every time. 972iter_max_socks(Config) when is_list(Config) -> 973 %% This is not *nearly* enough 974 %% We have some crap machines, which we need to "handle with care"... 975 Tries = 976 case os:type() of 977 {win32, _} -> 978 10; 979 {unix, darwin} -> 980 10; 981 _ -> 982 20 983 end, 984 %% Run on a different node in order to limit the effect if this test fails. 985 Dir = filename:dirname(code:which(?MODULE)), 986 {ok, Node} = ?START_SLAVE_NODE(test_iter_max_socks, "+Q 2048 -pa " ++ Dir), 987 %% L = rpc:call(Node,?MODULE,do_iter_max_socks,[N, initalize]), 988 L = iter_max_socks_run(Node, 989 fun() -> 990 exit(do_iter_max_socks(Config, Tries, initalize)) 991 end), 992 ?STOP_NODE(Node), 993 994 io:format("Result: ~p", [L]), 995 all_equal(L), 996 {comment, "Max sockets: " ++ integer_to_list(hd(L))}. 997 998iter_max_socks_run(Node, F) -> 999 try erlang:spawn_opt(Node, F, [monitor]) of 1000 {Pid, MRef} when is_pid(Pid) andalso is_reference(MRef) -> 1001 receive 1002 {'DOWN', MRef, process, Pid, Res} -> 1003 Res 1004 end; 1005 _Any -> 1006 ?P("Unexpected process start result: " 1007 "~n ~p", [_Any]), 1008 {skip, "Failed starting iterator (slave) process"} 1009 catch 1010 C:E:S -> 1011 ?P("Failed starting iterator (slave) process: " 1012 "~n Class: ~p" 1013 "~n Error: ~p" 1014 "~n Stack: ~p", [C, E, S]), 1015 {skip, "Failed starting iterator (slave) process"} 1016 end. 1017 1018 1019do_iter_max_socks(_Config, 0, _) -> 1020 ?P("do_iter_max_socks(0,-) -> done"), 1021 []; 1022do_iter_max_socks(Config, N, initalize = First) -> 1023 ?P("do_iter_max_socks(~w,~w) -> entry", [N, First]), 1024 MS = max_socks(Config), 1025 [MS|do_iter_max_socks(Config, N-1, MS)]; 1026do_iter_max_socks(Config, N, failed = First) -> 1027 ?P("do_iter_max_socks(~w,~w) -> entry", [N, First]), 1028 MS = max_socks(Config), 1029 [MS|do_iter_max_socks(Config, N-1, failed)]; 1030do_iter_max_socks(Config, N, First) when is_integer(First) -> 1031 ?P("do_iter_max_socks(~w,~w) -> entry", [N, First]), 1032 MS = max_socks(Config), 1033 if 1034 (MS =:= First) -> 1035 [MS|do_iter_max_socks(Config, N-1, First)]; 1036 true -> 1037 ?P("~w =/= ~w => sleeping for ~p seconds...", 1038 [MS, First, ?RETRY_SLEEP/1000]), 1039 ct:sleep(?RETRY_SLEEP), 1040 ?P("Trying again...", []), 1041 RetryMS = max_socks(Config), 1042 if RetryMS == First -> 1043 [RetryMS|do_iter_max_socks(Config, N-1, First)]; 1044 true -> 1045 [RetryMS|do_iter_max_socks(Config, N-1, failed)] 1046 end 1047 end. 1048 1049all_equal([]) -> 1050 ok; 1051all_equal([Rule | T]) -> 1052 all_equal(Rule, T). 1053 1054all_equal(Rule, [Rule | T]) -> 1055 all_equal(Rule, T); 1056all_equal(_, [_ | _]) -> 1057 ct:sleep(?RECOVER_SLEEP), % Wait a while and *hope* that we'll 1058 % recover so other tests won't be 1059 % affected. 1060 ct:fail(max_socket_mismatch); 1061all_equal(_Rule, []) -> 1062 ok. 1063 1064max_socks(Config) -> 1065 Socks = open_socks(Config), 1066 N = length(Socks), 1067 lists:foreach(fun(S) -> ok = gen_tcp:close(S) end, Socks), 1068 ?P("Got ~p sockets", [N]), 1069 N. 1070 1071open_socks(Config) -> 1072 case ?LISTEN(Config, 0, []) of 1073 {ok, L} -> 1074 {ok, {_, Port}} = inet:sockname(L), 1075 [L| connect_accept(Config, L, Port)]; 1076 _ -> 1077 [] 1078 end. 1079 1080connect_accept(Config, L, Port) -> 1081 case ?CONNECT(Config, localhost, Port, []) of 1082 {ok, C} -> 1083 [C| do_accept(Config, L, Port)]; 1084 _ -> 1085 [] 1086 end. 1087 1088do_accept(Config, L, Port) -> 1089 case gen_tcp:accept(L) of 1090 {ok, A} -> [A| connect_accept(Config, L, Port)]; 1091 _ -> [] 1092 end. 1093 1094start_node(Name) -> 1095 Pa = filename:dirname(code:which(?MODULE)), 1096 ?START_SLAVE_NODE(Name, "-pa " ++ Pa). 1097 1098start_remote(Name) -> 1099 Pa = filename:dirname(code:which(?MODULE)), 1100 ?START_SLAVE_NODE(Name, "-pa " ++ Pa, [{remote, true}]). 1101 1102%% Tests that when 'the other side' on a passive socket closes, the 1103%% connecting side can still read until the end of data. 1104passive_sockets(Config) when is_list(Config) -> 1105 spawn_link(?MODULE, passive_sockets_server, 1106 [Config, [{active, false}], self()]), 1107 receive 1108 {socket,Port} -> ok 1109 end, 1110 ct:sleep(500), 1111 case ?CONNECT(Config, "localhost", Port, [{active, false}]) of 1112 {ok, Sock} -> 1113 passive_sockets_read(Sock); 1114 {error, eaddrnotavail = Reason} -> 1115 {skip, connect_failed_str(Reason)}; 1116 Error -> 1117 ct:fail({"Could not connect to server", Error}) 1118 end. 1119 1120%% 1121%% Read until we get an {error, closed}. If we get another error, this test case 1122%% should fail. 1123%% 1124passive_sockets_read(Sock) -> 1125 case gen_tcp:recv(Sock, 0, 2000) of 1126 {ok, Data} -> 1127 io:format("Received ~p bytes~n", [length(Data)]), 1128 passive_sockets_read(Sock); 1129 {error, closed} -> 1130 gen_tcp:close(Sock); 1131 Error -> 1132 gen_tcp:close(Sock), 1133 ct:fail({"Did not get {error, closed} before other error", Error}) 1134 end. 1135 1136passive_sockets_server(Config, Opts, Parent) -> 1137 case ?LISTEN(Config, 0, Opts) of 1138 {ok, LSock} -> 1139 {ok,{_,Port}} = inet:sockname(LSock), 1140 Parent ! {socket,Port}, 1141 passive_sockets_server_accept(LSock); 1142 Error -> 1143 ct:fail({"Could not create listen socket", Error}) 1144 end. 1145 1146passive_sockets_server_accept(Sock) -> 1147 case gen_tcp:accept(Sock) of 1148 {ok, Socket} -> 1149 timer:sleep(500), % Simulate latency 1150 passive_sockets_server_send(Socket, 5), 1151 passive_sockets_server_accept(Sock); 1152 Error -> 1153 ct:fail({"Could not accept connection", Error}) 1154 end. 1155 1156passive_sockets_server_send(Socket, 0) -> 1157 io:format("Closing other end..~n", []), 1158 gen_tcp:close(Socket); 1159passive_sockets_server_send(Socket, X) -> 1160 Data = lists:duplicate(1024*X, $a), 1161 case gen_tcp:send(Socket, Data) of 1162 ok -> 1163 ct:sleep(50), % Simulate some processing. 1164 passive_sockets_server_send(Socket, X-1); 1165 {error, _Reason} -> 1166 ct:fail("Failed to send data") 1167 end. 1168 1169 1170%% Tests the return value from gen_tcp:accept when 1171%% the socket is closed from another process. (OTP-3817) 1172accept_closed_by_other_process(Config) when is_list(Config) -> 1173 Parent = self(), 1174 {ok, ListenSocket} = ?LISTEN(Config, 0, []), 1175 Child = 1176 spawn_link( 1177 fun() -> 1178 Parent ! {self(), gen_tcp:accept(ListenSocket)} 1179 end), 1180 receive after 1000 -> ok end, 1181 ok = gen_tcp:close(ListenSocket), 1182 receive 1183 {Child, {error, closed}} -> 1184 ok; 1185 {Child, Other} -> 1186 ct:fail({"Wrong result of gen_tcp:accept", Other}) 1187 end. 1188 1189repeat(N, Fun) -> 1190 repeat(N, N, Fun). 1191 1192repeat(N, T, Fun) when is_integer(N), N > 0 -> 1193 Fun(T-N), 1194 repeat(N-1, T, Fun); 1195repeat(_, _, _) -> 1196 ok. 1197 1198 1199%% Tests the response when using a closed socket as argument. 1200closed_socket(Config) when is_list(Config) -> 1201 {ok, LS1} = ?LISTEN(Config, 0, []), 1202 erlang:yield(), 1203 ok = gen_tcp:close(LS1), 1204 %% If the following delay is uncommented, the result error values 1205 %% below will change from {error, einval} to {error, closed} since 1206 %% inet_db then will have noticed that the socket is closed. 1207 %% This is a scheduling issue, i.e when the gen_server in 1208 %% in inet_db processes the 'EXIT' message from the port, 1209 %% the socket is unregistered. 1210 %% 1211 %% ct:sleep({seconds,2}) 1212 %% 1213 {error, R_send} = gen_tcp:send(LS1, "data"), 1214 {error, R_recv} = gen_tcp:recv(LS1, 17), 1215 {error, R_accept} = gen_tcp:accept(LS1), 1216 {error, R_controlling_process} = 1217 gen_tcp:controlling_process(LS1, self()), 1218 %% 1219 ok = ?P("R_send = ~p", [R_send]), 1220 ok = ?P("R_recv = ~p", [R_recv]), 1221 ok = ?P("R_accept = ~p", [R_accept]), 1222 ok = ?P("R_controlling_process = ~p", [R_controlling_process]), 1223 ok. 1224 1225%%% 1226%%% Test using the gen_tcp:shutdown/2 function using a sort server. 1227%%% 1228 1229shutdown_active(Config) when is_list(Config) -> 1230 ?TC_TRY(shutdown_active, fun() -> shutdown_common(Config, true) end). 1231 1232shutdown_passive(Config) when is_list(Config) -> 1233 ?TC_TRY(shutdown_passive, fun() -> shutdown_common(Config, false) end). 1234 1235shutdown_common(Config, Active) -> 1236 ?P("start sort server"), 1237 P = sort_server(Config, Active), 1238 ?P("Sort server port: ~p", [P]), 1239 1240 1241 do_sort(Config, P, []), 1242 do_sort(Config, P, ["glurf"]), 1243 do_sort(Config, P, ["abc","nisse","dum"]), 1244 1245 do_sort(Config, P, [lists:reverse(integer_to_list(I)) || I <- lists:seq(25, 255)]), 1246 do_sort(Config, P, [lists:reverse(integer_to_list(I)) || I <- lists:seq(77, 999)]), 1247 do_sort(Config, P, [lists:reverse(integer_to_list(I)) || I <- lists:seq(25, 55)]), 1248 do_sort(Config, P, []), 1249 do_sort(Config, P, ["apa"]), 1250 do_sort(Config, P, ["kluns","gorilla"]), 1251 do_sort(Config, P, [lists:reverse(integer_to_list(I)) || I <- lists:seq(25, 1233)]), 1252 do_sort(Config, P, []), 1253 receive 1254 Any -> 1255 ct:fail({unexpected_message,Any}) 1256 after 0 -> ok 1257 end. 1258 1259do_sort(Config, P, List0) -> 1260 ?P("Sort: " 1261 "~n ~p", [List0]), 1262 List = [El++"\n" || El <- List0], 1263 S = case ?CONNECT(Config, localhost, P, [{packet,line}]) of 1264 {ok, Socket} -> 1265 Socket; 1266 {error, eaddrnotavail = Reason} -> 1267 ?SKIPT(connect_failed_str(Reason)) 1268 end, 1269 send_lines(S, List), 1270 ok = gen_tcp:shutdown(S, write), 1271 Lines = collect_lines(S, true), 1272 ?P("Collected: " 1273 "~n ~p", [Lines]), 1274 SortedLines = lists:sort(List), 1275 ?P("Sorted: " 1276 "~n ~p", [SortedLines]), 1277 Lines = SortedLines, 1278 ok = gen_tcp:close(S). 1279 1280sort_server(Config, Active) -> 1281 Opts = [{exit_on_close,false},{packet,line},{active,Active}], 1282 {ok,L} = ?LISTEN(Config, 0, Opts), 1283 Go = make_ref(), 1284 Pid = spawn_link(fun() -> 1285 receive Go -> sort_server_1(L, Active) end 1286 end), 1287 ok = gen_tcp:controlling_process(L, Pid), 1288 Pid ! Go, 1289 {ok,Port} = inet:port(L), 1290 Port. 1291 1292sort_server_1(L, Active) -> 1293 {ok,S} = gen_tcp:accept(L), 1294 Go = make_ref(), 1295 Sorter = spawn(fun() -> receive Go -> sorter(S, Active) end end), 1296 ok = gen_tcp:controlling_process(S, Sorter), 1297 Sorter ! Go, 1298 sort_server_1(L, Active). 1299 1300sorter(S, Active) -> 1301 Lines = collect_lines(S, Active), 1302 send_lines(S, lists:sort(Lines)), 1303 gen_tcp:shutdown(S, write), 1304 gen_tcp:close(S). 1305 1306collect_lines(S, true) -> 1307 collect_lines_1(S, []); 1308collect_lines(S, false) -> 1309 passive_collect_lines_1(S, []). 1310 1311collect_lines_1(S, Acc) -> 1312 receive 1313 {tcp,S,Line} -> 1314 ?P("collect_lines_1(~w): ~p", [S, Line]), 1315 collect_lines_1(S, [Line|Acc]); 1316 {tcp_closed,S} -> 1317 ?P("collect_lines_1(~w): tcp_closed", [S]), 1318 lists:reverse(Acc) 1319 end. 1320 1321passive_collect_lines_1(S, Acc) -> 1322 case gen_tcp:recv(S, 0) of 1323 {ok,Line} -> passive_collect_lines_1(S, [Line|Acc]); 1324 {error,closed} -> lists:reverse(Acc) 1325 end. 1326 1327 1328send_lines(S, Lines) -> 1329 lists:foreach(fun(Line) -> 1330 ?P("send_line(~w): ~p", [S, Line]), 1331 ok = gen_tcp:send(S, Line) 1332 end, Lines). 1333 1334%%% 1335%%% Shutdown pending. 1336%%% 1337 1338shutdown_pending(Config) when is_list(Config) -> 1339 ?TC_TRY(shutdown_pending, fun() -> do_shutdown_pending(Config) end). 1340 1341do_shutdown_pending(Config) -> 1342 N = 512*1024+17, 1343 ?P("N: ~p", [N]), 1344 Data = [<<N:32>>,ones(N),42], 1345 {Port, Pid} = a_server(Config), 1346 ?P("try connect to server (port: ~p)", [Port]), 1347 S = case ?CONNECT(Config, localhost, Port, []) of 1348 {ok, Socket} -> 1349 ?P("connected"), 1350 Socket; 1351 {error, eaddrnotavail = Reason} -> 1352 ?SKIPT(connect_failed_str(Reason)) 1353 end, 1354 ?P("send"), 1355 gen_tcp:send(S, Data), 1356 ?P("shutdown(write)"), 1357 gen_tcp:shutdown(S, write), 1358 ?P("await data message"), 1359 case sp_await_data(Pid, S) of 1360 N -> 1361 ok; 1362 InvalidN -> 1363 ?P("Invalid message: " 1364 "~n Expected: ~p" 1365 "~n Received: ~p", [N, InvalidN]), 1366 ct:fail({unexpected_msg, N, InvalidN}) 1367 end, 1368 ?P("done"), 1369 ok. 1370 1371sp_await_data(Pid, Sock) -> 1372 receive 1373 {tcp, Sock, Msg} -> 1374 ?P("got tcp (data) message: ~p", [Msg]), 1375 list_to_integer(Msg) - 5; 1376 {'EXIT', Pid, normal} -> 1377 ?P("server exited normal"), 1378 sp_await_data(Pid, Sock); 1379 Other -> 1380 ?P("UNEXPECTED: " 1381 "~n ~p", [Other]), 1382 ct:fail({unexpected, Other}) 1383 end. 1384 1385 ones(0) -> []; 1386 ones(1) -> [1]; 1387 ones(N) -> 1388 Half = N div 2, 1389 Ones = ones(Half), 1390 case 2*Half of 1391 N -> [Ones|Ones]; 1392 _ -> [1,Ones|Ones] 1393 end. 1394 1395 a_server(Config) -> 1396 {ok, L} = ?LISTEN(Config, 0, [{exit_on_close,false},{active,false}]), 1397 Pid = spawn_link(fun() -> a_server2(L) end), 1398 ok = gen_tcp:controlling_process(L, Pid), 1399 {ok, Port} = inet:port(L), 1400 {Port, Pid}. 1401 1402a_server2(L) -> 1403 {ok,S} = gen_tcp:accept(L), 1404 do_recv(S, []). 1405 1406 do_recv(S, Bs0) -> 1407 case gen_tcp:recv(S, 0) of 1408 {ok,B} -> 1409 do_recv(S, [Bs0,B]); 1410 {error,closed} -> 1411 Bs = list_to_binary(Bs0), 1412 gen_tcp:send(S, integer_to_list(byte_size(Bs))), 1413 gen_tcp:close(S) 1414 end. 1415 1416%% 1417%% Test 'show_econnreset' option 1418%% 1419 1420show_econnreset_active(Config) when is_list(Config) -> 1421 ?TC_TRY(show_econnreset_active, 1422 fun() -> do_show_econnreset_active(Config) end). 1423 1424do_show_econnreset_active(Config) -> 1425 %% First confirm everything works with option turned off. 1426 ?P("test with option switched off (default)"), 1427 {ok, L0} = ?LISTEN(Config, 0, []), 1428 {ok, Port0} = inet:port(L0), 1429 Client0 = case ?CONNECT(Config, localhost, Port0, [{active, false}]) of 1430 {ok, CSock0} -> 1431 CSock0; 1432 {error, eaddrnotavail = Reason0} -> 1433 ?SKIPT(connect_failed_str(Reason0)) 1434 end, 1435 {ok, S0} = gen_tcp:accept(L0), 1436 ok = gen_tcp:close(L0), 1437 ok = inet:setopts(Client0, [{linger, {true, 0}}]), 1438 ok = gen_tcp:close(Client0), 1439 receive 1440 {tcp_closed, S0} -> 1441 ok; 1442 Other0 -> 1443 ct:fail({unexpected, off, closed, Other0}) 1444 after 1000 -> 1445 ct:fail({timeout, {server, no_tcp_closed}}) 1446 end, 1447 1448 %% Now test with option switched on. 1449 %% Note: We are also testing that the show_econnreset option is 1450 %% inherited from the listening socket by the accepting socket. 1451 ?P("test with option explicitly switched on"), 1452 {ok, L1} = ?LISTEN(Config, 0, [{show_econnreset, true}]), 1453 {ok, Port1} = inet:port(L1), 1454 Client1 = case ?CONNECT(Config, localhost, Port1, [{active, false}]) of 1455 {ok, CSock1} -> 1456 CSock1; 1457 {error, eaddrnotavail = Reason1} -> 1458 ?SKIPT(connect_failed_str(Reason1)) 1459 end, 1460 {ok, S1} = gen_tcp:accept(L1), 1461 ok = gen_tcp:close(L1), 1462 ok = inet:setopts(Client1, [{linger, {true, 0}}]), 1463 ok = gen_tcp:close(Client1), 1464 receive 1465 {tcp_error, S1, econnreset} -> 1466 receive 1467 {tcp_closed, S1} -> 1468 ?P("done"), 1469 ok; 1470 Other1 -> 1471 ?P("UNEXPECTED (expected closed):" 1472 "~n ~p", [Other1]), 1473 ct:fail({unexpected, on, closed, Other1}) 1474 after 1 -> 1475 ?P("UNEXPECTED timeout (expected closed)"), 1476 ct:fail({timeout, {server, no_tcp_closed}}) 1477 end; 1478 Other2 -> 1479 ?P("UNEXPECTED (expected error:econnreset):" 1480 "~n ~p", [Other2]), 1481 ct:fail({unexpected, on, econnreset, Other2}) 1482 after 1000 -> 1483 ?P("UNEXPECTED timeout (expected error:econnreset)"), 1484 ct:fail({timeout, {server, no_tcp_error}}) 1485 end. 1486 1487show_econnreset_active_once(Config) when is_list(Config) -> 1488 ?TC_TRY(show_econnreset_active_once, 1489 fun() -> do_show_econnreset_active_once(Config) end). 1490 1491do_show_econnreset_active_once(Config) -> 1492 %% Now test using {active, once} 1493 {ok, L} = ?LISTEN(Config, 0, 1494 [{active, false}, 1495 {show_econnreset, true}]), 1496 {ok, Port} = inet:port(L), 1497 Client = case ?CONNECT(Config, localhost, Port, [{active, false}]) of 1498 {ok, CSock} -> 1499 CSock; 1500 {error, eaddrnotavail = Reason} -> 1501 ?SKIPT(connect_failed_str(Reason)) 1502 end, 1503 {ok, S} = gen_tcp:accept(L), 1504 ok = gen_tcp:close(L), 1505 ok = inet:setopts(Client, [{linger, {true, 0}}]), 1506 ok = gen_tcp:close(Client), 1507 ok = ct:sleep(20), 1508 ok = receive Msg -> {unexpected_msg, Msg} after 0 -> ok end, 1509 ok = inet:setopts(S, [{active, once}]), 1510 receive 1511 {tcp_error, S, econnreset} -> 1512 receive 1513 {tcp_closed, S} -> 1514 ok; 1515 Other1 -> 1516 ct:fail({unexpected1, Other1}) 1517 after 1 -> 1518 ct:fail({timeout, {server, no_tcp_closed}}) 1519 end; 1520 Other2 -> 1521 ct:fail({unexpected2, Other2}) 1522 after 1000 -> 1523 ct:fail({timeout, {server, no_tcp_error}}) 1524 end. 1525 1526show_econnreset_passive(Config) when is_list(Config) -> 1527 ?TC_TRY(show_econnreset_passive, 1528 fun() -> do_show_econnreset_passive(Config) end). 1529 1530do_show_econnreset_passive(Config) -> 1531 %% First confirm everything works with option turned off. 1532 {ok, L} = ?LISTEN(Config, 0, [{active, false}]), 1533 {ok, Port} = inet:port(L), 1534 Client = case ?CONNECT(Config, localhost, Port, [{active, false}]) of 1535 {ok, CSock} -> 1536 CSock; 1537 {error, eaddrnotavail = Reason} -> 1538 ?SKIPT(connect_failed_str(Reason)) 1539 end, 1540 {ok, S} = gen_tcp:accept(L), 1541 ok = gen_tcp:close(L), 1542 ok = inet:setopts(S, [{linger, {true, 0}}]), 1543 ok = gen_tcp:close(S), 1544 ok = ct:sleep(1), 1545 {error, closed} = gen_tcp:recv(Client, 0), 1546 1547 %% Now test with option switched on. 1548 {ok, L1} = ?LISTEN(Config, 0, [{active, false}]), 1549 {ok, Port1} = inet:port(L1), 1550 Client1 = 1551 case ?CONNECT(Config, localhost, Port1, 1552 [{active, false}, {show_econnreset, true}]) of 1553 {ok, CSock1} -> 1554 CSock1; 1555 {error, eaddrnotavail = Reason1} -> 1556 ?SKIPT(connect_failed_str(Reason1)) 1557 end, 1558 {ok, S1} = gen_tcp:accept(L1), 1559 ok = gen_tcp:close(L1), 1560 ok = inet:setopts(S1, [{linger, {true, 0}}]), 1561 ok = gen_tcp:close(S1), 1562 ok = ct:sleep(1), 1563 {error, econnreset} = gen_tcp:recv(Client1, 0). 1564 1565econnreset_after_sync_send(Config) when is_list(Config) -> 1566 ?TC_TRY(econnreset_after_sync_send, 1567 fun() -> do_econnreset_after_sync_send(Config) end). 1568 1569do_econnreset_after_sync_send(Config) -> 1570 %% First confirm everything works with option turned off. 1571 ?P("test with option switched off (default)"), 1572 {ok, L} = ?LISTEN(Config, 0, [{active, false}]), 1573 {ok, Port} = inet:port(L), 1574 Client = case ?CONNECT(Config, localhost, Port, [{active, false}]) of 1575 {ok, CSock} -> 1576 CSock; 1577 {error, eaddrnotavail = Reason} -> 1578 ?SKIPT(connect_failed_str(Reason)) 1579 end, 1580 {ok, S} = gen_tcp:accept(L), 1581 ok = gen_tcp:close(L), 1582 ok = inet:setopts(S, [{linger, {true, 0}}]), 1583 ok = gen_tcp:close(S), 1584 ok = ct:sleep(20), 1585 {error, closed} = gen_tcp:send(Client, "Whatever"), 1586 1587 %% Now test with option switched on. 1588 ?P("test with option explicitly switched on"), 1589 {ok, L1} = ?LISTEN(Config, 0, [{active, false}]), 1590 {ok, Port1} = inet:port(L1), 1591 Client1 = 1592 case ?CONNECT(Config, localhost, Port1, 1593 [{active, false}, {show_econnreset, true}]) of 1594 {ok, CSock1} -> 1595 CSock1; 1596 {error, eaddrnotavail = Reason1} -> 1597 ?SKIPT(connect_failed_str(Reason1)) 1598 end, 1599 {ok, S1} = gen_tcp:accept(L1), 1600 ok = gen_tcp:close(L1), 1601 ok = inet:setopts(S1, [{linger, {true, 0}}]), 1602 ok = gen_tcp:close(S1), 1603 ok = ct:sleep(20), 1604 {error, econnreset} = gen_tcp:send(Client1, "Whatever"). 1605 1606econnreset_after_async_send_active(Config) when is_list(Config) -> 1607 ?TC_TRY(econnreset_after_async_send_active, 1608 fun() -> do_econnreset_after_async_send_active(Config) end). 1609 1610do_econnreset_after_async_send_active(Config) -> 1611 {OS, _} = os:type(), 1612 CPayload = craasa_mk_payload(), 1613 SPayload = "Whatever", 1614 1615 %% First confirm everything works with option turned off. 1616 ?P("pre 1 (default)"), 1617 {Client1, Server1} = craasa_pre(Config, default), 1618 1619 ?P("populate 1 (default)"), 1620 {ok, Sender1} = craasa_populate(OS, default, 1621 Client1, Server1, CPayload, SPayload), 1622 ?P("sleep some"), 1623 ok = ct:sleep(20), 1624 1625 ?P("[server] set linger true:0"), 1626 ok = inet:setopts(Server1, [{linger, {true, 0}}]), 1627 ?P("[server] close socket"), 1628 ok = gen_tcp:close(Server1), 1629 ?P("sleep some"), 1630 ok = ct:sleep(20), 1631 1632 ?P("verify 1 (default)"), 1633 craasa_verify(default, Client1, SPayload), 1634 1635 ?P("cleanup 1 (default)"), 1636 craasa_cleanup(Client1, Sender1), 1637 1638 %% Now test with option switched on. 1639 ?P("pre 2 (true)"), 1640 {Client2, Server2} = craasa_pre(Config, true), 1641 1642 ?P("populate 2 (true)"), 1643 {ok, Sender2} = craasa_populate(OS, true, 1644 Client2, Server2, CPayload, SPayload), 1645 ?P("sleep some"), 1646 ok = ct:sleep(20), 1647 1648 ?P("[server] set linger true:0"), 1649 ok = inet:setopts(Server2, [{linger, {true, 0}}]), 1650 ?P("[server] close socket"), 1651 ok = gen_tcp:close(Server2), 1652 ?P("sleep some"), 1653 ok = ct:sleep(20), 1654 1655 ?P("verify 2 (true)"), 1656 craasa_verify(true, Client2, SPayload), 1657 1658 ?P("cleanup 2 (true)"), 1659 craasa_cleanup(Client2, Sender2), 1660 1661 ?P("done"), 1662 ok. 1663 1664craasa_mk_payload() -> 1665 list_to_binary(lists:duplicate(1024 * 1024, $.)). 1666 1667craasa_pre(Config, EConnReset) 1668 when is_boolean(EConnReset) orelse (EConnReset =:= default) -> 1669 ?P("create listen socket (server) with active = false"), 1670 {ok, L} = ?LISTEN(Config, 0, [{active, false}, {recbuf, 4096}]), 1671 {ok, Port} = inet:port(L), 1672 ?P("[client] create connect socket with show_econnreset: ~p", [EConnReset]), 1673 Opts = if (EConnReset =:= default) -> []; 1674 is_boolean(EConnReset) -> [{show_econnreset, EConnReset}] 1675 end, 1676 Client = case ?CONNECT(Config, localhost, Port, [{sndbuf, 4096}] ++ Opts) of 1677 {ok, CSock} -> 1678 CSock; 1679 {error, eaddrnotavail = Reason} -> 1680 ?SKIPT(connect_failed_str(Reason)) 1681 end, 1682 ?P("create accept socket (server)"), 1683 {ok, S} = gen_tcp:accept(L), 1684 ?P("close listen socket"), 1685 ok = gen_tcp:close(L), 1686 {Client, S}. 1687 1688craasa_populate(OS, _EConnReset, Client, Server, CPayload, SPayload) 1689 when is_port(Client) andalso is_port(Server) -> 1690 ?P("send payload (~w bytes) from client to server", [byte_size(CPayload)]), 1691 ok = gen_tcp:send(Client, CPayload), 1692 ?P("verify client socket queue size"), 1693 case erlang:port_info(Client, queue_size) of 1694 {queue_size, N} when N > 0 -> ok; 1695 {queue_size, 0} when OS =:= win32 -> ok; 1696 {queue_size, 0} = T -> ct:fail(T) 1697 end, 1698 ?P("[server] send something"), 1699 ok = gen_tcp:send(Server, SPayload), 1700 {ok, undefined}; 1701craasa_populate(_OS, EConnReset, Client, Server, CPayload, SPayload) -> 1702 ExpectedSendRes = if (EConnReset =:= default) -> closed; 1703 (EConnReset =:= true) -> econnreset 1704 end, 1705 Sender = spawn_link(fun() -> 1706 craasa_populate_sender(Client, 1707 ExpectedSendRes, 1708 CPayload) 1709 end), 1710 receive 1711 {'EXIT', Sender, Reason} -> 1712 {error, {unexpected_exit, Sender, Reason}} 1713 after 2000 -> 1714 ?P("[server] send something"), 1715 ok = gen_tcp:send(Server, SPayload), 1716 {ok, Sender} 1717 end. 1718 1719craasa_populate_sender(Client, ExpectedSendRes, Payload) -> 1720 ?P("[socket] send payload (expect failure)"), 1721 case gen_tcp:send(Client, Payload) of 1722 {error, ExpectedSendRes} -> 1723 ?P("[socket] payload send failure (as expected)"), 1724 exit(normal); 1725 Unexpected -> 1726 exit({unexpected, Unexpected}) 1727 end. 1728 1729craasa_cleanup(Client, Sender) -> 1730 (catch gen_tcp:close(Client)), 1731 craasa_cleanup(Sender). 1732 1733craasa_cleanup(Sender) when is_pid(Sender) -> 1734 exit(Sender, kill), 1735 receive 1736 {'EXIT', Sender, _} -> 1737 ok 1738 after 0 -> 1739 ok 1740 end; 1741craasa_cleanup(_) -> 1742 ok. 1743 1744craasa_verify(default, Client, Payload) -> 1745 ?P("[verify-default] client await server data"), 1746 receive 1747 {tcp, Client, Payload} -> 1748 ?P("[verify-default] " 1749 "client received expected server data - " 1750 "now await socket closed"), 1751 receive 1752 {tcp_closed, Client} -> 1753 ?P("[verify-default] " 1754 "received client socket closed"), 1755 ok; 1756 Other1 -> 1757 ?P("[verify-default] " 1758 "awaiting client socket closed - received upexpected: " 1759 "~n ~p", [Other1]), 1760 ct:fail({unexpected, tcp_closed, Other1}) 1761 end; 1762 Other2 -> 1763 ?P("[verify-default] " 1764 "awaiting client socket data - received upexpected: " 1765 "~n ~p", [Other2]), 1766 ct:fail({unexpected, tcp, Other2}) 1767 end; 1768craasa_verify(true, Client, Payload) -> 1769 ?P("[verify-true] client await server data"), 1770 receive 1771 {tcp, Client, Payload} -> 1772 ?P("[verify-true] " 1773 "client received expected server data - now await socket error"), 1774 receive 1775 {tcp_error, Client, econnreset} -> 1776 ?P("[verify-true] " 1777 "client received expected socket error - " 1778 "now await socket closed"), 1779 receive 1780 {tcp_closed, Client} -> 1781 ?P("[verify-true] " 1782 "client received expected socket closed"), 1783 ok; 1784 Other1 -> 1785 ?P("[verify-true] " 1786 "client awaiting socket closed - " 1787 "received upexpected: " 1788 "~n ~p", [Other1]), 1789 ct:fail({unexpected, tcp_closed, Other1}) 1790 end; 1791 Other2 -> 1792 ?P("[verify-true] " 1793 "client awaiting socket error - received upexpected: " 1794 "~n ~p", [Other2]), 1795 ct:fail({unexpected, tcp_error, Other2}) 1796 end; 1797 Other3 -> 1798 ?P("[verify-true] " 1799 "client awaiting socket data - received upexpected: " 1800 "~n ~p", [Other3]), 1801 ct:fail({unexpected, tcp, Other3}) 1802 end. 1803 1804 1805%% -------------------------------------------------------------------------- 1806 1807econnreset_after_async_send_active_once(Config) when is_list(Config) -> 1808 ?TC_TRY(econnreset_after_async_send_active_once, 1809 fun() -> do_econnreset_after_async_send_active_once(Config) end). 1810 1811do_econnreset_after_async_send_active_once(Config) -> 1812 ?P("pre"), 1813 {Client, Server, CPayload, SPayload} = craasao_pre(Config), 1814 1815 ?P("populate"), 1816 {ok, Sender} = craasao_populate(Client, Server, CPayload, SPayload), 1817 1818 ?P("set server socket option linger: {true, 0}"), 1819 ok = inet:setopts(Server, [{linger, {true, 0}}]), 1820 ?P("close server socket"), 1821 ok = gen_tcp:close(Server), 1822 ?P("sleep some"), 1823 ok = ct:sleep(20), 1824 1825 ?P("verify"), 1826 craasao_verify(Client, Sender, SPayload), 1827 1828 ?P("cleanup"), 1829 craasao_cleanup(Client), 1830 1831 ?P("done"), 1832 ok. 1833 1834craasao_pre(Config) -> 1835 ?P("[pre] create listen socket with active = false"), 1836 {ok, L} = ?LISTEN(Config, 0, [{active, false}, {recbuf, 4096}]), 1837 ?P("[pre] listen socket: " 1838 "~n ~p", [L]), 1839 {ok, Port} = inet:port(L), 1840 ?P("[pre] create connect socket (~w)", [Port]), 1841 Client = case ?CONNECT(Config, localhost, Port, 1842 [{active, false}, 1843 {sndbuf, 4096}, 1844 {show_econnreset, true}]) of 1845 {ok, CSock} -> 1846 ?P("[pre] connect socket created:" 1847 "~n ~p", [CSock]), 1848 CSock; 1849 {error, eaddrnotavail = Reason} -> 1850 ?SKIPT(connect_failed_str(Reason)) 1851 end, 1852 ?P("[pre] create accept socket"), 1853 {ok, Server} = gen_tcp:accept(L), 1854 ?P("[pre] close listen socket"), 1855 ok = gen_tcp:close(L), 1856 {Client, Server, craasao_mk_payload(), "Whatever"}. 1857 1858craasao_populate(Client, Server, CPayload, SPayload) 1859 when is_port(Client) andalso is_port(Server) -> 1860 ?P("[populate,inet] client send data when" 1861 "~n Client: ~p" 1862 "~n Server: ~p", [Client, Server]), 1863 ok = gen_tcp:send(Client, CPayload), 1864 ?P("[populate,inet] verify client socket queue size"), 1865 {OS, _} = os:type(), 1866 case erlang:port_info(Client, queue_size) of 1867 {queue_size, N} when N > 0 -> ok; 1868 {queue_size, 0} when OS =:= win32 -> ok; 1869 {queue_size, 0} = T -> ct:fail(T) 1870 end, 1871 ?P("[populate,inet] server send data"), 1872 ok = gen_tcp:send(Server, SPayload), 1873 ?P("[populate,inet] sleep some"), 1874 ok = ct:sleep(20), 1875 {ok, undefined}; 1876craasao_populate(Client, Server, CPayload, SPayload) -> 1877 ?P("[populate,socket] entry when" 1878 "~n Client: ~p" 1879 "~n Server: ~p", [Client, Server]), 1880 Sender = spawn_link(fun() -> 1881 craasao_populate_sender(Client, CPayload) 1882 end), 1883 receive 1884 {'EXIT', Sender, Reason} -> 1885 {error, {unexpected_exit, Sender, Reason}} 1886 after 2000 -> 1887 ?P("[populate,socket] send something"), 1888 ok = gen_tcp:send(Server, SPayload), 1889 {ok, Sender} 1890 end. 1891 1892craasao_populate_sender(Client, Payload) -> 1893 ?P("[populate,sender] send payload (expect failure)"), 1894 {error, econnreset} = gen_tcp:send(Client, Payload), 1895 ?P("[populate,sender] payload send failure (as expected)"), 1896 exit(normal). 1897 1898craasao_mk_payload() -> 1899 list_to_binary(lists:duplicate(1024 * 1024, $.)). 1900 1901craasao_verify(Client, _Sender, _Payload) when is_port(Client) -> 1902 ?P("[verify] ensure no 'unexpected messages' received"), 1903 ok = receive Msg -> {unexpected_msg, Msg} after 0 -> ok end, 1904 ?P("[verify] set client socket option active: once"), 1905 ok = inet:setopts(Client, [{active, once}]), 1906 ?P("[verify] expect client econnreset"), 1907 receive 1908 {tcp_error, Client, econnreset} -> 1909 ?P("[verify] received client econnreset -> " 1910 "expect client closed message"), 1911 receive 1912 {tcp_closed, Client} -> 1913 ?P("[verify] " 1914 "received expected client closed message - done"), 1915 ok; 1916 Other1 -> 1917 ?P("[verify] client received unexpected message " 1918 "(expected closed): " 1919 "~n ~p", [Other1]), 1920 ct:fail({unexpected, tcp_closed, Other1}) 1921 end; 1922 Other2 -> 1923 ?P("[verify] client received unexpected message (expected error): " 1924 "~n Unexpected: ~p" 1925 "~n Flushed: ~p", [Other2, craasao_flush()]), 1926 ct:fail({unexpected, tcp_error, Other2}) 1927 end; 1928craasao_verify(Client, Sender, Payload) when is_pid(Sender) -> 1929 ?P("[verify] begin with" 1930 "~n Client: ~p" 1931 "~n Sender: ~p", [Client, Sender]), 1932 craasao_verify_sender(Sender), 1933 ?P("[verify] ensure no 'unexpected messages' received"), 1934 ok = receive Msg -> {unexpected_msg, Msg} after 0 -> ok end, 1935 ?P("[verify] set client socket option active once (1)"), 1936 ok = inet:setopts(Client, [{active, once}]), 1937 ?P("[verify] client expect (server) data"), 1938 receive 1939 {tcp, Client, Payload} -> 1940 ?P("[verify] client received expected data"), 1941 ok 1942 end, 1943 ?P("[verify] set client socket option active once (2)"), 1944 ok = inet:setopts(Client, [{active, once}]), 1945 ?P("[verify] await client econnreset"), 1946 receive 1947 {tcp_error, Client, econnreset} -> 1948 ?P("[verify] client received expected econnreset -> " 1949 "expect socket close message"), 1950 receive 1951 {tcp_closed, Client} -> 1952 ?P("[verify] client received expected closed message"), 1953 ok; 1954 Other1 -> 1955 ?P("[verify] client received unexpected message " 1956 "(expected closed): " 1957 "~n Unexpected: ~p" 1958 "~n Flushed: ~p", [Other1, craasao_flush()]), 1959 ct:fail({unexpected, tcp_closed, Other1}) 1960 end; 1961 Other2 -> 1962 ?P("[verify] client received unexpected message (expected error): " 1963 "~n Unexpected: ~p" 1964 "~n Flushed: ~p", [Other2, craasao_flush()]), 1965 ct:fail({unexpected, tcp_error, Other2}) 1966 after 10000 -> 1967 ?P("[verify] client received unexpected timeout (expected error): " 1968 "~n Flushed: ~p", [craasao_flush()]), 1969 ct:fail({unexpected_timeout, tcp_error}) 1970 end. 1971 1972craasao_flush() -> 1973 craasao_flush([]). 1974 1975craasao_flush(Acc) -> 1976 erlang:yield(), 1977 receive Msg -> craasao_flush([Msg|Acc]) 1978 after 1000 -> lists:reverse(Acc) 1979 end. 1980 1981craasao_verify_sender(Sender) when is_pid(Sender) -> 1982 ?P("await sender termination"), 1983 receive 1984 {'EXIT', Sender, normal} -> 1985 ?P("expected normal sender termination received"), 1986 ok; 1987 {'EXIT', Sender, Reason} -> 1988 ?P("unexpected sender termination: " 1989 "~n ~p", [Reason]), 1990 ct:fail({unexpected_sender_termination, Sender, Reason}) 1991 after infinity -> 1992 ok 1993 end; 1994craasao_verify_sender(_) -> 1995 ok. 1996 1997craasao_cleanup(Client) -> 1998 (catch gen_tcp:close(Client)). 1999 2000 2001%% -------------------------------------------------------------------------- 2002 2003econnreset_after_async_send_passive(Config) when is_list(Config) -> 2004 ?TC_TRY(econnreset_after_async_send_passive, 2005 fun() -> do_econnreset_after_async_send_passive(Config) end). 2006 2007do_econnreset_after_async_send_passive(Config) -> 2008 CPayload = craasp_mk_payload(), 2009 SPayload = "Whatever", 2010 2011 %% First confirm everything works with option turned off. 2012 ?P("pre 1 (default)"), 2013 {Client1, Server1} = craasp_pre(Config, default), 2014 2015 ?P("populate 1 (default)"), 2016 {ok, Sender1} = craasp_populate(default, 2017 Client1, Server1, CPayload, SPayload), 2018 2019 ?P("close server socket (1)"), 2020 ok = gen_tcp:close(Server1), 2021 ?P("sleep some"), 2022 ok = ct:sleep(20), 2023 2024 ?P("verify 1 (default)"), 2025 ?line ok = craasp_verify(Client1, default, SPayload), 2026 2027 ?P("cleanup 1 (default)"), 2028 craasp_cleanup(Client1, Sender1), 2029 2030 %% Now test with option switched on. 2031 ?P("pre 2 (true)"), 2032 {Client2, Server2} = craasp_pre(Config, true), 2033 2034 ?P("populate 2 (default)"), 2035 {ok, Sender2} = craasp_populate(true, 2036 Client2, Server2, CPayload, SPayload), 2037 2038 2039 ?P("close server socket 2"), 2040 ok = gen_tcp:close(Server2), 2041 ?P("sleep some"), 2042 ok = ct:sleep(20), 2043 2044 ?P("verify 2 (default)"), 2045 ?line ok = craasp_verify(Client2, true, SPayload), 2046 2047 ?P("cleanup 2 (default)"), 2048 craasp_cleanup(Client2, Sender2), 2049 2050 ?P("done"), 2051 ok. 2052 2053 2054craasp_pre(Config, EConnReset) 2055 when is_boolean(EConnReset) orelse (EConnReset =:= default) -> 2056 ?P("create listen socket *** with option switched off (default)"), 2057 {ok, L} = ?LISTEN(Config, 0, [{active, false}, {recbuf, 4096}]), 2058 {ok, Port} = inet:port(L), 2059 ?P("[client] create connect socket with show_econnreset: ~p", [EConnReset]), 2060 COpts = [{active, false}, {sndbuf, 4096}] ++ 2061 if (EConnReset =:= default) -> []; 2062 is_boolean(EConnReset) -> [{show_econnreset, EConnReset}] 2063 end, 2064 Client = case ?CONNECT(Config, localhost, Port, COpts) of 2065 {ok, CSock} -> 2066 CSock; 2067 {error, eaddrnotavail = Reason} -> 2068 ?SKIPT(connect_failed_str(Reason)) 2069 end, 2070 ?P("accept connection"), 2071 {ok, Server} = gen_tcp:accept(L), 2072 ?P("close listen socket"), 2073 ok = gen_tcp:close(L), 2074 {Client, Server}. 2075 2076craasp_mk_payload() -> 2077 list_to_binary(lists:duplicate(1024 * 1024, $.)). 2078 2079craasp_populate(_EConnReset, Client, Server, CPayload, SPayload) 2080 when is_port(Client) andalso is_port(Server) -> 2081 ?P("[server] set linger: true:0"), 2082 ok = inet:setopts(Server, [{linger, {true, 0}}]), 2083 ?P("[server] send some data to client"), 2084 ok = gen_tcp:send(Server, SPayload), 2085 ?P("[client] send some data to server"), 2086 ok = gen_tcp:send(Client, CPayload), 2087 {OS, _} = os:type(), 2088 ?P("[client] verify (port) queue-size"), 2089 case erlang:port_info(Client, queue_size) of 2090 {queue_size, N} when N > 0 -> ok; 2091 {queue_size, 0} when OS =:= win32 -> ok; 2092 {queue_size, 0} = T -> ct:fail(T) 2093 end, 2094 {ok, undefined}; 2095craasp_populate(EConnReset, Client, Server, CPayload, SPayload) -> 2096 ExpectedSendRes = if (EConnReset =:= default) -> closed; 2097 (EConnReset =:= true) -> econnreset 2098 end, 2099 Sender = spawn_link(fun() -> 2100 craasp_populate_sender(Client, 2101 ExpectedSendRes, 2102 CPayload) 2103 end), 2104 receive 2105 {'EXIT', Sender, Reason} -> 2106 {error, {unexpected_exit, Sender, Reason}} 2107 after 2000 -> 2108 ?P("[server] send something"), 2109 ok = gen_tcp:send(Server, SPayload), 2110 {ok, Sender} 2111 end. 2112 2113craasp_populate_sender(Client, ExpectedSendRes, Payload) -> 2114 ?P("[socket] send payload (expect failure)"), 2115 {error, ExpectedSendRes} = gen_tcp:send(Client, Payload), 2116 ?P("[socket] payload send failure (as expected)"), 2117 exit(normal). 2118 2119craasp_verify(Client, EConnReset, _Payload) 2120 when is_port(Client) andalso 2121 ((EConnReset =:= default) orelse is_boolean(EConnReset)) -> 2122 ?P("[client,~w] attempt receive and expect error (closed): " 2123 "~n Port Info: ~p" 2124 "~n Socket Status: ~s", 2125 [EConnReset, 2126 try erlang:port_info(Client) 2127 catch 2128 _:_:_ -> 2129 "-" 2130 end, 2131 try prim_inet:getstatus(Client) of 2132 {ok, CStatus} -> ?F("~p", [CStatus]); 2133 _ -> "-" 2134 catch 2135 _:_:_ -> 2136 "-" 2137 end]), 2138 case gen_tcp:recv(Client, 0) of 2139 {error, closed} when (EConnReset =:= default) -> 2140 ok; 2141 {error, econnreset} when (EConnReset =:= true) -> 2142 ok; 2143 {error, Reason} -> 2144 {error, {unexpected_error, Reason}}; 2145 ok -> 2146 {error, unexpected_success} 2147 end; 2148craasp_verify(Client, EConnReset, Payload) 2149 when (EConnReset =:= default) orelse is_boolean(EConnReset) -> 2150 ?P("[client] attempt first recv and expect success"), 2151 case gen_tcp:recv(Client, 0) of 2152 {ok, Payload} -> 2153 ?P("[client] attempt second recv and expect failure (~w)", 2154 [EConnReset]), 2155 case gen_tcp:recv(Client, 0) of 2156 {error, closed} when (EConnReset =:= default) -> 2157 ?P("[client] expected failure (closed)"), 2158 ok; 2159 {error, econnreset} when (EConnReset =:= true) -> 2160 ?P("[client] expected failure (econnreset)"), 2161 ok; 2162 {error, Reason2} -> 2163 ?P("[client] unexpected failure:" 2164 "~n EConnReset: ~p" 2165 "~n Reason: ~p", [EConnReset, Reason2]), 2166 {error, {unexpected_error2, EConnReset, Reason2}}; 2167 {ok, _} -> 2168 ?P("[client] unexpected success"), 2169 {error, unexpected_recv2} 2170 end; 2171 {ok, _} -> 2172 ?P("[client] unexpected first recv success (wrong payload)"), 2173 {error, unexpected_recv1}; 2174 {error, Reason1} -> 2175 ?P("[client] unexpected first recv failure: " 2176 "~n Reason: ~p", [Reason1]), 2177 {error, {unexpected_error1, Reason1}} 2178 end. 2179 2180craasp_cleanup(Client, Sender) -> 2181 (catch gen_tcp:close(Client)), 2182 craasp_cleanup(Sender). 2183 2184craasp_cleanup(Sender) when is_pid(Sender) -> 2185 exit(Sender, kill), 2186 receive 2187 {'EXIT', Sender, _} -> 2188 ok 2189 after 0 -> 2190 ok 2191 end; 2192craasp_cleanup(_) -> 2193 ok. 2194 2195 2196 2197%% 2198%% Test {linger {true, 0}} aborts a connection 2199%% 2200 2201linger_zero(Config) when is_list(Config) -> 2202 ?TC_TRY(linger_zero, fun() -> do_linger_zero(Config) end). 2203 2204do_linger_zero(Config) -> 2205 %% All the econnreset tests will prove that {linger, {true, 0}} aborts 2206 %% a connection when the driver queue is empty. We will test here 2207 %% that it also works when the driver queue is not empty. 2208 {OS, Client, Server} = lz_pre(Config), 2209 2210 PayloadSize = 1024 * 1024, 2211 {ok, Sender} = lz_populate(Client, OS, PayloadSize), 2212 2213 ?P("set linger: {true, 0}"), 2214 ok = inet:setopts(Client, [{linger, {true, 0}}]), 2215 ?P("close client socket"), 2216 ok = gen_tcp:close(Client), 2217 ?P("sleep some"), 2218 ok = ct:sleep(1), 2219 2220 lz_verify(Client, Server, PayloadSize), 2221 2222 ?P("cleanup"), % Just in case 2223 (catch gen_tcp:close(Server)), 2224 if is_pid(Sender) -> exit(Sender, kill); 2225 true -> ok 2226 end, 2227 2228 ?P("done"), 2229 ok. 2230 2231lz_pre(Config) -> 2232 {OS, _} = os:type(), 2233 ?P("create listen socket"), 2234 {ok, L} = ?LISTEN(Config, 0, [{active, false}, 2235 {recbuf, 4096}, 2236 {show_econnreset, true}]), 2237 ?P("listen socket created"), 2238 %% inet_backend = inet 2239 {ok, Port} = inet:port(L), 2240 ?P("connect (create client socket)"), 2241 Client = case ?CONNECT(Config, localhost, Port, 2242 [{nodelay, true}, 2243 {active, false}, 2244 {sndbuf, 4096}]) of 2245 {ok, CSock} -> 2246 CSock; 2247 {error, eaddrnotavail = Reason} -> 2248 ?SKIPT(connect_failed_str(Reason)) 2249 end, 2250 ?P("accept"), 2251 {ok, Server} = gen_tcp:accept(L), 2252 ?P("close listen socket"), 2253 ok = gen_tcp:close(L), 2254 {OS, Client, Server}. 2255 2256lz_populate(Client, OS, PayloadSize) when is_port(Client) -> 2257 ?P("[inet] create payload"), 2258 Payload = lz_make_payload(PayloadSize), 2259 ?P("[inet] ensure non-empty queue"), 2260 lz_ensure_non_empty_queue(Client, Payload, OS), 2261 {ok, undefined}; 2262lz_populate(Client, _OS, PayloadSize) -> 2263 ?P("[socket] send payload"), 2264 Sender = spawn_link(fun() -> lz_populate_sender(Client, PayloadSize) end), 2265 receive 2266 {'EXIT', Sender, Reason} -> 2267 {error, {unexpected_exit, Sender, Reason}} 2268 after 2000 -> 2269 {ok, Sender} 2270 end. 2271 2272lz_populate_sender(Client, PayloadSize) -> 2273 ?P("[socket] create payload"), 2274 Payload = lz_make_payload(PayloadSize), 2275 ?P("[socket] send payload (expect failure)"), 2276 {error, closed} = gen_tcp:send(Client, Payload), 2277 ?P("[socket] payload send failed (as expected)"), 2278 exit(normal). 2279 2280lz_verify(Client, Server, PayloadSize) 2281 when is_port(Client) andalso is_port(Server) -> 2282 ?P("[inet] verify client socket (port) not connected"), 2283 undefined = erlang:port_info(Client, connected), 2284 ?P("[inet] try (and fail) recv (on accepted socket)"), 2285 {error, econnreset} = gen_tcp:recv(Server, PayloadSize), 2286 ok; 2287lz_verify(_Client, Server, PayloadSize) -> 2288 ?P("[socket] try (and fail) recv (on accepted socket)"), 2289 {error, econnreset} = gen_tcp:recv(Server, PayloadSize), 2290 ok. 2291 2292lz_make_payload(PayloadSize) -> 2293 list_to_binary(lists:duplicate(PayloadSize, $.)). 2294 2295%% THIS DOES NOT WORK FOR 'SOCKET' 2296lz_ensure_non_empty_queue(Sock, Payload, OS) when is_port(Sock) -> 2297 lz_ensure_non_empty_queue(Sock, Payload, OS, 1). 2298 2299-define(LZ_MAX_SENDS, 3). 2300 2301lz_ensure_non_empty_queue(Sock, _Payload, _OS, N) when (N > ?LZ_MAX_SENDS) -> 2302 ?P("queue size verification failed - port info: " 2303 "~n Socket: ~p" 2304 "~n Socket info: ~p", [Sock, erlang:port_info(Sock)]), 2305 ct:fail("Queue size verification failed"); 2306lz_ensure_non_empty_queue(Sock, Payload, OS, N) -> 2307 ?P("try send payload (~w bytes) ~w (on client socket) when port info:" 2308 "~n ~p", [byte_size(Payload), N, erlang:port_info(Sock)]), 2309 ok = gen_tcp:send(Sock, Payload), 2310 ?P("try verify client socket queue size"), 2311 case erlang:port_info(Sock, queue_size) of 2312 {queue_size, QSz} when QSz > 0 -> 2313 ?P("queue size verification *successfull* (~p) - port info: " 2314 "~n ~p", [QSz, erlang:port_info(Sock)]), 2315 ok; 2316 {queue_size, 0} when OS =:= win32 -> 2317 ?P("queue size verification *successfull* - port info: " 2318 "~n ~p", [erlang:port_info(Sock)]), 2319 ok; 2320 {queue_size, 0} -> 2321 ?P("queue size verification failed - port info: " 2322 "~n ~p", [erlang:port_info(Sock)]), 2323 lz_ensure_non_empty_queue(Sock, Payload, OS, N+1) 2324 end. 2325 2326 2327linger_zero_sndbuf(Config) when is_list(Config) -> 2328 ?TC_TRY(linger_zero_sndbuf, fun() -> do_linger_zero_sndbuf(Config) end). 2329 2330do_linger_zero_sndbuf(Config) -> 2331 %% All the econnreset tests will prove that {linger, {true, 0}} aborts 2332 %% a connection when the driver queue is empty. We will test here 2333 %% that it also works when the driver queue is not empty 2334 %% and the linger zero option is set on the listen socket. 2335 {OS, Client, Server} = lzs_pre(Config), 2336 2337 PayloadSize = 1024 * 1024, 2338 {ok, Sender} = lzs_populate(Client, OS, PayloadSize), 2339 2340 ?P("verify linger: {true, 0}"), 2341 {ok, [{linger, {true, 0}}]} = inet:getopts(Server, [linger]), 2342 ?P("close client socket"), 2343 ok = gen_tcp:close(Server), 2344 ok = ct:sleep(1), 2345 2346 lzs_verify(Client, Server, PayloadSize), 2347 2348 ?P("cleanup"), % Just in case 2349 (catch gen_tcp:close(Server)), 2350 if is_pid(Sender) -> exit(Sender, kill); 2351 true -> ok 2352 end, 2353 2354 ?P("done"), 2355 ok. 2356 2357lzs_pre(Config) -> 2358 {OS, _} = os:type(), 2359 ?P("create listen socket"), 2360 {ok, Listen} = ?LISTEN(Config, 0, [{active, false}, 2361 {recbuf, 4096}, 2362 {show_econnreset, true}, 2363 {linger, {true, 0}}]), 2364 {ok, Port} = inet:port(Listen), 2365 ?P("connect (create client socket)"), 2366 Client = case ?CONNECT(Config, localhost, Port, 2367 [{nodelay, true}, 2368 {active, false}, 2369 {sndbuf, 4096}]) of 2370 {ok, CSock} -> 2371 CSock; 2372 {error, eaddrnotavail = CReason} -> 2373 ?SKIPT(connect_failed_str(CReason)) 2374 end, 2375 ?P("accept"), 2376 {ok, Server} = gen_tcp:accept(Listen), 2377 %% On *some* platforms, the linger is inherited, 2378 %% but not all so do not assume... 2379 ?P("check if linger option was inherited"), 2380 case inet:getopts(Server, [linger]) of 2381 {ok, [{linger, {true, 0}}]} -> 2382 ?P("linger option was inherited"), 2383 ok; 2384 {ok, [{linger, {true, TO}}]} -> 2385 ?P("linger option was *not* inherited: ~p", [TO]), 2386 ok = inet:setopts(Server, [{linger, {true, 0}}]), 2387 ok; 2388 {error, SReason} -> 2389 ?P("FAILED reading linger option: ~p", [SReason]), 2390 ok = inet:setopts(Server, [{linger, {true, 0}}]), 2391 ok 2392 end, 2393 ?P("close listen socket"), 2394 ok = gen_tcp:close(Listen), 2395 {OS, Client, Server}. 2396 2397lzs_populate(Client, OS, PayloadSize) when is_port(Client) -> 2398 ?P("[inet] create payload"), 2399 Payload = lzs_make_payload(PayloadSize), 2400 ?P("[inet] ensure non-empty queue"), 2401 lz_ensure_non_empty_queue(Client, Payload, OS), 2402 {ok, undefined}; 2403lzs_populate(Client, _OS, PayloadSize) -> 2404 ?P("[socket] send payload ( = start payload sender)"), 2405 Sender = spawn(fun() -> lzs_populate_sender(Client, PayloadSize) end), 2406 receive 2407 {'EXIT', Sender, Reason} -> 2408 {error, {unexpected_exit, Sender, Reason}} 2409 after 2000 -> 2410 {ok, Sender} 2411 end. 2412 2413lzs_populate_sender(Client, PayloadSize) -> 2414 ?P("[socket] create payload"), 2415 Payload = lzs_make_payload(PayloadSize), 2416 ?P("[socket] send payload (expect failure)"), 2417 {error, closed} = gen_tcp:send(Client, Payload), 2418 ?P("[socket] payload send failed (as expected)"), 2419 exit(normal). 2420 2421lzs_make_payload(PayloadSize) -> 2422 Payload = binary:copy(<<"0123456789ABCDEF">>, 64 * 1024), % 1 MB 2423 if (PayloadSize =:= byte_size(Payload)) -> 2424 Payload; 2425 true -> 2426 exit({payload_size, PayloadSize, byte_size(Payload)}) 2427 end. 2428 2429lzs_verify(Client, Server, PayloadSize) 2430 when is_port(Client) andalso is_port(Server) -> 2431 ?P("[inet] verify client socket (port) not connected"), 2432 undefined = erlang:port_info(Server, connected), 2433 ?P("[inet] try (and fail) recv (on accepted socket)"), 2434 {error, closed} = gen_tcp:recv(Client, PayloadSize), 2435 ok; 2436lzs_verify(Client, _Server, PayloadSize) -> 2437 ?P("[socket] try (and fail) recv (on accepted socket)"), 2438 {error, closed} = gen_tcp:recv(Client, PayloadSize), 2439 ok. 2440 2441%% Thanks to Luke Gorrie. Tests for a very specific problem with 2442%% corrupt data. The testcase will be killed by the timetrap timeout 2443%% if the bug is present. 2444http_bad_packet(Config) when is_list(Config) -> 2445 {ok,L} = ?LISTEN(Config, 0, [{active, false}, 2446 binary, 2447 {reuseaddr, true}, 2448 {packet, http}]), 2449 {ok,Port} = inet:port(L), 2450 spawn_link(fun() -> erlang:yield(), http_bad_client(Config, Port) end), 2451 case gen_tcp:accept(L) of 2452 {ok,S} -> 2453 http_worker(S); 2454 Err -> 2455 exit({accept,Err}) 2456 end. 2457 2458http_worker(S) -> 2459 case gen_tcp:recv(S, 0, 30000) of 2460 {ok,{http_error,Error}} -> 2461 io:format("Http error: ~s\n", [Error]); 2462 {ok,Data} -> 2463 io:format("Data: ~p\n", [Data]), 2464 http_worker(S) 2465 end. 2466 2467http_bad_client(Config, Port) -> 2468 {ok,S} = ?CONNECT(Config, "localhost", Port, [{active,false}, binary]), 2469 ok = gen_tcp:send(S, "\r\n"), 2470 ok = gen_tcp:close(S). 2471 2472 2473%% Fill send queue and then start receiving. 2474%% 2475busy_send(Config) when is_list(Config) -> 2476 ?TC_TRY(busy_send, fun() -> do_busy_send(Config) end). 2477 2478do_busy_send(Config) -> 2479 OldFlag = process_flag(trap_exit, true), 2480 Master = self(), 2481 Msg = <<"the quick brown fox jumps over a lazy dog~n">>, 2482 ?P("[master] start server"), 2483 ServerF = 2484 fun() -> 2485 ?P("[server] create listen socket"), 2486 case ?LISTEN(Config, 0, [{active,false},binary, 2487 {reuseaddr,true}, 2488 {packet,0}, 2489 {recbuf,4096}, 2490 {sndbuf,4096}]) of 2491 {ok, L} -> 2492 ?P("[server] listen socket created"), 2493 {ok, Port} = inet:port(L), 2494 Master ! {self(), listen_port, Port}, 2495 ?P("[server] await continue"), 2496 receive 2497 {Master, continue} -> 2498 ?P("[server] received continue"), 2499 busy_send_srv(L, Master, Msg) 2500 end; 2501 {error, Reason} -> 2502 ?P("[server] UNEXPECTED: ~w", [Reason]), 2503 ?SKIPE(listen_failed_str(Reason)) 2504 end 2505 end, 2506 Server = spawn_link(ServerF), 2507 ?P("[master] server: ~p", [Server]), 2508 ListenPort = 2509 receive 2510 {'EXIT', Server, {skip, _} = SKIP} -> 2511 ?P("[master] server issued skip: " 2512 "~n ~p", [SKIP]), 2513 throw(SKIP); 2514 2515 {'EXIT', Server, Reason} -> 2516 ?P("[master] server crashed: " 2517 "~n ~p", [Reason]), 2518 exit({server, Reason}); 2519 2520 {Server, listen_port, LP} -> 2521 ?P("listen port: ~p", [LP]), 2522 LP 2523 end, 2524 ?P("[master] start client"), 2525 ClientF = 2526 fun () -> 2527 ?P("[client] await (connect) server port"), 2528 Port = 2529 receive 2530 {Master, connect, P} -> 2531 P 2532 end, 2533 ?P("[client] connect to ~w", [Port]), 2534 case ?CONNECT(Config, "localhost", Port, 2535 [{active,false}, 2536 binary, 2537 {packet,0}, 2538 {recbuf,4096}, 2539 {sndbuf,4096}]) of 2540 {ok, Socket} -> 2541 Master ! {self(), connected}, 2542 ?P("[client] connected - await recv"), 2543 receive 2544 {Master, recv, N} -> 2545 ?P("[client] received recv:~w", [N]), 2546 busy_send_client_loop(Socket, Master, Msg, N) 2547 end; 2548 {error, eaddrnotavail = CReason} -> 2549 ?P("[client] UNEXPECTED: ~w", [CReason]), 2550 ?SKIPE(connect_failed_str(CReason)) 2551 end 2552 end, 2553 Client = spawn_link(ClientF), 2554 ?P("[master] client: ~p", [Client]), 2555 Server ! {self(), continue}, 2556 Client ! {self(), connect, ListenPort}, 2557 receive 2558 {Client, connected} -> 2559 ?P("[master] client connected"), 2560 ok 2561 end, 2562 busy_send_loop(Server, Client, 0), 2563 process_flag(trap_exit, OldFlag), 2564 ?P("[master] done"), 2565 ok. 2566 2567busy_send_loop(Server, Client, N) -> 2568 %% Master 2569 %% 2570 receive 2571 {Server, send} -> 2572 busy_send_loop(Server, Client, N+1) 2573 2574 after 2000 -> 2575 ?P("[master] send timeout: server send queue full (N = ~w+1)", [N]), 2576 %% Send queue full, sender blocked 2577 %% -> stop sender and release client 2578 Server ! {self(), close}, 2579 Client ! {self(), recv, N+1}, 2580 ?P("[master] await server 'send'..."), 2581 receive 2582 {Server, send} -> 2583 busy_send_2(Server, Client, N+1) 2584 after 10000 -> 2585 %% If this happens, see busy_send_srv 2586 ?P("[master] UNEXPECTED: server send timeout"), 2587 ct:fail({timeout,{server,not_send,flush([])}}) 2588 end 2589 end. 2590 2591busy_send_2(Server, Client, _N) -> 2592 %% Master 2593 %% 2594 ?P("[master] await (server) closed"), 2595 receive 2596 {Server, [closed]} -> 2597 ?P("[master] received expected (server) closed - " 2598 "await client closed"), 2599 receive 2600 {Client, [0,{error,closed}]} -> 2601 ?P("[master] received expected (client) closed"), 2602 ok 2603 end 2604 after 10000 -> 2605 ?P("[master] UNEXPECTED: server closed timeout"), 2606 ct:fail({timeout, {server, not_closed, flush([])}}) 2607 end. 2608 2609busy_send_srv(L, Master, Msg) -> 2610 %% Server 2611 %% Sometimes this accept does not return, do not really know why 2612 %% but it causes the timeout error in busy_send_loop to be 2613 %% triggered. Only happens on OS X Leopard?!? 2614 ?P("[server] try accept"), 2615 case gen_tcp:accept(L) of 2616 {ok, Socket} -> 2617 ?P("[server] accepted"), 2618 busy_send_srv_loop(Socket, Master, Msg); 2619 {error, Reason} -> 2620 ?P("UNEXPECTED: server accept failure: ~p", [Reason]), 2621 ?SKIPE(accept_failed_str(Reason)) 2622 end. 2623 2624busy_send_srv_loop(Socket, Master, Msg) -> 2625 %% Server 2626 %% 2627 receive 2628 {Master, close} -> 2629 ?P("[server] received close"), 2630 ok = gen_tcp:close(Socket), 2631 Master ! {self(),flush([closed])} 2632 after 0 -> 2633 ok = gen_tcp:send(Socket, Msg), 2634 Master ! {self(), send}, 2635 busy_send_srv_loop(Socket, Master, Msg) 2636 end. 2637 2638busy_send_client_loop(Socket, Master, Msg, N) -> 2639 %% Client 2640 %% 2641 Size = byte_size(Msg), 2642 case gen_tcp:recv(Socket, Size) of 2643 {ok, Msg} -> 2644 busy_send_client_loop(Socket, Master, Msg, N-1); 2645 Other -> 2646 ?P("[client] recv response: " 2647 "~n ~p", [Other]), 2648 Master ! {self(), flush([Other,N])} 2649 end. 2650 2651%%% 2652%%% Send to a socket whose other end does not read until the port gets busy. 2653%%% Then close the other end. The writer should get an {error,closed} error. 2654%%% (Passive mode.) 2655%%% 2656 2657busy_disconnect_passive(Config) when is_list(Config) -> 2658 ?TC_TRY(busy_disconnect_passive, 2659 fun() -> do_busy_disconnect_passive(Config) end). 2660 2661do_busy_disconnect_passive(Config) -> 2662 ?P("[passive] begin"), 2663 MuchoData = list_to_binary(ones(64*1024)), 2664 [do_busy_disconnect_passive2(Config, MuchoData, N) || N <- lists:seq(1, 10)], 2665 ?P("[passive] done"), 2666 ok. 2667 2668do_busy_disconnect_passive2(Config, MuchoData, N) -> 2669 ?P("[passive,~w] *** prepare server *** ", [N]), 2670 {_Server, S} = busy_disconnect_prepare_server(Config, [{active,false}]), 2671 ?P("[passive,~w] server prepared - start sending", [N]), 2672 {_OSFam, OSName} = os:type(), 2673 busy_disconnect_passive_send(S, MuchoData, OSName). 2674 2675busy_disconnect_passive_send(S, Data, OS) -> 2676 case gen_tcp:send(S, Data) of 2677 ok -> 2678 busy_disconnect_passive_send(S, Data, OS); 2679 {error, closed} -> 2680 ok; 2681 {error, eprototype = Reason} when (OS =:= darwin) -> 2682 ?P("send failed with ~w", [Reason]), 2683 ok 2684 end. 2685 2686%%% 2687%%% Send to a socket whose other end does not read until the port gets busy. 2688%%% Then close the other end. The writer should get an {error,closed} error and 2689%%% a {tcp_closed,Socket} message. (Active mode.) 2690%%% 2691busy_disconnect_active(Config) when is_list(Config) -> 2692 ?TC_TRY(busy_disconnect_active, 2693 fun() -> do_busy_disconnect_active(Config) end). 2694 2695do_busy_disconnect_active(Config) -> 2696 ?P("[active] begin"), 2697 MuchoData = list_to_binary(ones(64*1024)), 2698 [do_busy_disconnect_active2(Config, MuchoData, N) || N <- lists:seq(1, 10)], 2699 ?P("[active] done"), 2700 ok. 2701 2702do_busy_disconnect_active2(Config, MuchoData, N) -> 2703 ?P("[active,~w] *** prepare server *** ", [N]), 2704 {Server, S} = busy_disconnect_prepare_server(Config, [{active,true}]), 2705 ?P("[active,~w] server prepared - start sending", [N]), 2706 busy_disconnect_active_send(Server, S, MuchoData). 2707 2708busy_disconnect_active_send(Server, S, Data) -> 2709 {_OSFam, OSName} = os:type(), 2710 busy_disconnect_active_send(Server, S, Data, 1, OSName). 2711 2712busy_disconnect_active_send(Server, S, Data, Iter, OS) -> 2713 case gen_tcp:send(S, Data) of 2714 ok -> 2715 busy_disconnect_active_send(Server, S, Data, Iter+1, OS); 2716 {error, closed} -> 2717 ?P("[active-sender,~w] send failed with closed - await tcp-closed", 2718 [Iter]), 2719 busy_disconnect_active_send_await_closed(Server, S); 2720 2721 {error, eprototype = Reason} when (OS =:= darwin) -> 2722 ?P("[active-sender,~w] send failed with ~w - await tcp-closed", 2723 [Iter, Reason]), 2724 busy_disconnect_active_send_await_closed(Server, S); 2725 2726 {error, einval = Reason} -> 2727 ?P("[active-sender,~w] UNEXPECTED send failure:" 2728 "~n ~p", [Iter, Reason]), 2729 ?SKIPT(send_failed_str(Reason)); 2730 2731 {error, Reason} -> 2732 ?P("[active-sender,~w] UNEXPECTED send failure:" 2733 "~n ~p", [Iter, Reason]), 2734 ct:fail({unexpected_send_result, Reason, Iter}) 2735 end. 2736 2737busy_disconnect_active_send_await_closed(Server, S) -> 2738 busy_disconnect_active_send_await_closed(Server, S, false, false). 2739busy_disconnect_active_send_await_closed(Server, S, Closed, Stopped) -> 2740 receive 2741 {tcp_closed, S} when (Stopped =:= true) -> 2742 ?P("[active-sender] received tcp-closed - done"), 2743 ok; 2744 2745 {tcp_closed, S} -> 2746 ?P("[active-sender] received tcp-closed"), 2747 busy_disconnect_active_send_await_closed(Server, S, true, Stopped); 2748 2749 {'EXIT', Server, normal} when (Closed =:= true) -> 2750 ?P("[active-sender] received server (normal) exit - done"), 2751 ok; 2752 2753 {'EXIT', Server, normal} -> 2754 ?P("[active-sender] received server (normal) exit"), 2755 busy_disconnect_active_send_await_closed(Server, S, Closed, true); 2756 2757 Other -> 2758 ?P("[active-sender] received UNEXPECTED message:" 2759 "~n Expected tcp-close of ~p" 2760 "~n Server: ~p" 2761 "~n Unexpected message: ~p", [S, Server, Other]), 2762 ct:fail({unexpected, Other, S, flush([])}) 2763 end. 2764 2765 2766busy_disconnect_prepare_server(Config, ConnectOpts) -> 2767 Sender = self(), 2768 ?P("[prep-server] create server"), 2769 Server = spawn_link(fun() -> busy_disconnect_server(Config, Sender) end), 2770 ?P("[prep-server] await port (from server)"), 2771 receive {port, Server, Port} -> ok end, 2772 ?P("[prep-server] connect to ~w", [Port]), 2773 case ?CONNECT(Config, localhost, Port, ConnectOpts) of 2774 {ok, S} -> 2775 ?P("[prep-server] connected - order server start sending"), 2776 Server ! {Sender, sending}, 2777 ?P("[prep-server] done"), 2778 {Server, S}; 2779 {error, eaddrnotavail = Reason} -> 2780 ?SKIPT(connect_failed_str(Reason)) 2781 end. 2782 2783busy_disconnect_server(Config, Sender) -> 2784 ?P("[server] create listen socket"), 2785 {ok, L} = ?LISTEN(Config, 0, 2786 [{active,false}, 2787 binary, 2788 {reuseaddr,true}, 2789 {packet,0}]), 2790 ?P("[server] created - get port number"), 2791 {ok,Port} = inet:port(L), 2792 ?P("[server] send port ~w (to sender)", [Port]), 2793 Sender ! {port,self(),Port}, 2794 ?P("[server] try accept"), 2795 {ok,S} = gen_tcp:accept(L), 2796 ?P("[server] connection accepted"), 2797 receive 2798 {Sender, sending} -> 2799 ?P("[server] received sending (from sender)"), 2800 busy_disconnect_server_wait_for_busy(Sender, S) 2801 end. 2802 2803%% Close the socket as soon as the Sender process can't send because of 2804%% a busy port. 2805busy_disconnect_server_wait_for_busy(Sender, S) -> 2806 case process_info(Sender, status) of 2807 {status, waiting = Status} -> 2808 %% We KNOW that the sender will be in state 'waiting' only 2809 %% if the port has become busy. (Fallback solution if the 2810 %% implementation changes: Watch Sender's reduction count; 2811 %% when it stops changing, wait 2 seconds and then close.) 2812 ?P("[server] sender status ~p => close socket", [Status]), 2813 gen_tcp:close(S); 2814 {status, Status} -> 2815 ?P("[server] sender status ~p", [Status]), 2816 timer:sleep(100), 2817 busy_disconnect_server_wait_for_busy(Sender, S); 2818 Other -> 2819 ?P("[server] sender status ~p", [Other]), 2820 timer:sleep(100), 2821 busy_disconnect_server_wait_for_busy(Sender, S) 2822 end. 2823 2824 2825%%% 2826%%% Fill send queue 2827%%% 2828fill_sendq(Config) when is_list(Config) -> 2829 ?TC_TRY(fill_sendq, fun() -> do_fill_sendq(Config) end). 2830 2831do_fill_sendq(Config) -> 2832 OldFlag = process_flag(trap_exit, true), 2833 Master = self(), 2834 ServerF = 2835 fun () -> 2836 ?P("[server] try listen"), 2837 case ?LISTEN(Config, 0, [{active,false},binary, 2838 {reuseaddr,true},{packet,0}]) of 2839 {ok, L} -> 2840 ?P("[server] try port"), 2841 case inet:port(L) of 2842 {ok, Port} -> 2843 Master ! {self(), listen_port, Port}, 2844 fill_sendq_srv(L, Master); 2845 {error, PReason} -> 2846 ?SKIPE(port_failed_str(PReason)) 2847 end; 2848 {error, LReason} -> 2849 ?SKIPE(listen_failed_str(LReason)) 2850 end 2851 end, 2852 Server = spawn_link(ServerF), 2853 ?P("[master] server: ~p", [Server]), 2854 ClientF = 2855 fun () -> 2856 ?P("[client] await server port"), 2857 ServerPort = 2858 receive 2859 {Master, server_port, SP} -> 2860 ?P("[client] server port: ~w", [SP]), 2861 SP 2862 end, 2863 %% Just close on order 2864 ?P("[client] try connect"), 2865 case ?CONNECT(Config, 2866 "localhost", ServerPort, 2867 [{active,false},binary,{packet,0}]) of 2868 {ok, S} -> 2869 ?P("[client] connected"), 2870 Master ! {self(), connected}, 2871 receive 2872 {Master, close} -> 2873 ?P("[client] received close"), 2874 ok = gen_tcp:close(S) 2875 end; 2876 {error, eaddrnotavail = Reason} -> 2877 ?SKIPE(connect_failed_str(Reason)) 2878 end 2879 end, 2880 Client = spawn_link(ClientF), 2881 ?P("[master] client: ~p", [client]), 2882 ListenPort = 2883 receive 2884 {Server, listen_port, LP} -> 2885 ?P("[master] listen port: ~w", [LP]), 2886 LP 2887 end, 2888 Client ! {self(), server_port, ListenPort}, 2889 ?P("[master] await client connected"), 2890 receive {Client, connected} -> ok end, 2891 ?P("[master] await reader"), 2892 Res = receive 2893 {Server, reader, Reader} -> 2894 ?P("[master] reader: ~p", [Reader]), 2895 fill_sendq_loop(Server, Client, Reader) 2896 end, 2897 process_flag(trap_exit, OldFlag), 2898 ?P("[master] done"), 2899 Res. 2900 2901fill_sendq_loop(Server, Client, Reader) -> 2902 %% Master 2903 %% 2904 receive 2905 {Server, send} -> 2906 fill_sendq_loop(Server, Client, Reader) 2907 after 2000 -> 2908 %% Send queue full, sender blocked -> close client. 2909 ?P("[master] send timeout, closing client"), 2910 Client ! {self(), close}, 2911 receive 2912 {Server, [{error,closed}] = SErrors} -> 2913 ?P("[master] got expected server closed"), 2914 receive 2915 {Reader, [{error,closed}]} -> 2916 ?P("[master] got expected reader closed"), 2917 ok; 2918 {Reader, RErrors} when is_list(RErrors) -> 2919 ct:fail([{server, SErrors}, {reader, RErrors}]) 2920 after 3000 -> 2921 ct:fail({timeout,{closed,reader}}) 2922 end; 2923 2924 {Server, SErrors} when is_list(SErrors) -> 2925 ?P("UNEXPECTED SERVER ERROR(S): " 2926 "~n ~p" 2927 "~n ~p", [SErrors, flush([])]), 2928 ct:fail([{server, SErrors}, {reader, []}]); 2929 2930 {Reader, [{error,closed}] = RErrors} -> 2931 ?P("[master] got expected reader closed"), 2932 receive 2933 {Server, [{error,closed}]} -> 2934 ?P("[master] got expected server closed"), 2935 ok; 2936 {Server, SErrors} when is_list(SErrors) -> 2937 ct:fail([{server, SErrors}, {reader, RErrors}]) 2938 after 3000 -> 2939 ct:fail({timeout,{closed,server}}) 2940 end; 2941 2942 {Reader, RErrors} when is_list(RErrors) -> 2943 ?P("UNEXPECTED READER ERROR(S): " 2944 "~n ~p" 2945 "~n ~p", [RErrors, flush([])]), 2946 ct:fail([{server, []}, {reader, RErrors}]) 2947 2948 after 3000 -> 2949 Msgs = flush([]), 2950 ct:fail({timeout,{closed,[server,reader]}, Msgs}) 2951 end 2952 end. 2953 2954fill_sendq_srv(L, Master) -> 2955 %% Server 2956 %% 2957 ?P("[server] await accept"), 2958 case gen_tcp:accept(L) of 2959 {ok, S} -> 2960 ?P("[server] accepted ~p", [S]), 2961 Master ! {self(), reader, 2962 spawn_link(fun () -> fill_sendq_read(S, Master) end)}, 2963 Msg = "the quick brown fox jumps over a lazy dog~n", 2964 fill_sendq_write(S, Master, [Msg,Msg,Msg,Msg,Msg,Msg,Msg,Msg]); 2965 E -> 2966 Error = flush([E]), 2967 ?P("[server] accept error: ~p", [E]), 2968 Master ! {self(), Error} 2969 end. 2970 2971fill_sendq_write(S, Master, Msg) -> 2972 %% Server 2973 %% 2974 %% ?P("[server] sending..."), 2975 case gen_tcp:send(S, Msg) of 2976 ok -> 2977 Master ! {self(), send}, 2978 %% ?P("[server] ok."), 2979 fill_sendq_write(S, Master, Msg); 2980 {error, _} = E -> 2981 Error = flush([E]), 2982 ?P("[server] send error: ~p", [Error]), 2983 Master ! {self(), Error} 2984 end. 2985 2986fill_sendq_read(S, Master) -> 2987 %% Reader 2988 %% 2989 ?P("[reader] read infinity..."), 2990 case gen_tcp:recv(S, 0, infinity) of 2991 {ok, Data} -> 2992 ?P("[reader] recv: ~p", [Data]), 2993 fill_sendq_read(S, Master); 2994 E -> 2995 Error = flush([E]), 2996 ?P("[reader] recv error: ~p", [Error]), 2997 Master ! {self(), Error} 2998 end. 2999 3000 3001%%% Try to receive more than available number of bytes from 3002%%% a closed socket. 3003%%% 3004partial_recv_and_close(Config) when is_list(Config) -> 3005 try do_partial_recv_and_close(Config) 3006 catch 3007 throw:{skip, _} = SKIP -> 3008 SKIP 3009 end. 3010 3011do_partial_recv_and_close(Config) -> 3012 Msg = "the quick brown fox jumps over a lazy dog 0123456789\n", 3013 Len = length(Msg), 3014 {ok,L} = ?LISTEN(Config, 0, [{active,false}]), 3015 {ok,P} = inet:port(L), 3016 Sock = 3017 case ?CONNECT(Config, "localhost", P, [{active,false}]) of 3018 {ok, S} -> 3019 S; 3020 {error, eaddrnotavail = Reason} -> 3021 ?SKIPT(connect_failed_str(Reason)) 3022 end, 3023 {ok, A} = gen_tcp:accept(L), 3024 ok = gen_tcp:send(Sock, Msg), 3025 ok = gen_tcp:close(Sock), 3026 {error, closed} = gen_tcp:recv(A, Len+1), 3027 ok. 3028 3029%%% Try to receive more than available number of bytes from 3030%%% a closed socket, this time waiting in the recv before closing. 3031%%% 3032partial_recv_and_close_2(Config) when is_list(Config) -> 3033 OldFlag = process_flag(trap_exit, true), 3034 Res = try do_partial_recv_and_close_2(Config) 3035 catch 3036 exit:{skip, _} = SKIP -> 3037 SKIP 3038 end, 3039 process_flag(trap_exit, OldFlag), 3040 Res. 3041 3042do_partial_recv_and_close_2(Config) -> 3043 Msg = "the quick brown fox jumps over a lazy dog 0123456789\n", 3044 Len = length(Msg), 3045 {ok,L} = ?LISTEN(Config, 0, [{active,false}]), 3046 {ok,P} = inet:port(L), 3047 Server = self(), 3048 Client = 3049 spawn_link( 3050 fun () -> 3051 receive after 2000 -> ok end, 3052 case ?CONNECT(Config, "localhost", P, [{active,false}]) of 3053 {ok, S} -> 3054 ok = gen_tcp:send(S, Msg), 3055 receive {Server,close} -> ok end, 3056 receive after 2000 -> ok end, 3057 ok = gen_tcp:close(S); 3058 {error, eaddrnotavail = Reason} -> 3059 ?SKIPE(connect_failed_str(Reason)) 3060 end 3061 end), 3062 {ok, A} = gen_tcp:accept(L), 3063 Client ! {Server, close}, 3064 {error, closed} = gen_tcp:recv(A, Len+1), 3065 ok. 3066 3067%%% Here we tests that gen_tcp:recv/2 will return {error,closed} following 3068%%% a send operation of a huge amount data when the other end closed the socket. 3069%%% 3070partial_recv_and_close_3(Config) when is_list(Config) -> 3071 OldFlag = process_flag(trap_exit, true), 3072 Res = try do_partial_recv_and_close_3(Config) 3073 catch 3074 throw:{skip, _} = SKIP -> 3075 SKIP 3076 end, 3077 process_flag(trap_exit, OldFlag), 3078 Res. 3079 3080do_partial_recv_and_close_3(Config) -> 3081 [do_partial_recv_and_close_4(Config) || _ <- lists:seq(0, 20)], 3082 ok. 3083 3084do_partial_recv_and_close_4(Config) -> 3085 Parent = self(), 3086 spawn_link(fun() -> 3087 {ok,L} = ?LISTEN(Config, 0, [{active,false}]), 3088 {ok,{_,Port}} = inet:sockname(L), 3089 Parent ! {port,Port}, 3090 {ok,S} = gen_tcp:accept(L), 3091 gen_tcp:recv(S, 1), 3092 gen_tcp:close(S) 3093 end), 3094 receive 3095 {port,Port} -> ok 3096 end, 3097 Much = ones(8*64*1024), 3098 S = case ?CONNECT(Config, localhost, Port, [{active, false}]) of 3099 {ok, Sock} -> 3100 Sock; 3101 {error, eaddrnotavail = Reason} -> 3102 ?SKIPT(connect_failed_str(Reason)) 3103 end, 3104 3105 %% Send a lot of data (most of it will be queued). 3106 %% The receiver will read one byte and close the connection. 3107 %% The write operation will fail. 3108 gen_tcp:send(S, Much), 3109 3110 %% We should always get {error,closed} here. 3111 {error, closed} = gen_tcp:recv(S, 0). 3112 3113 3114test_prio_put_get(Config) -> 3115 Tos = 3 bsl 5, 3116 ?P("test_prio_put_get -> create listen socket"), 3117 {ok,L1} = ?LISTEN(Config, 0, [{active,false}]), 3118 ?P("test_prio_put_get -> set opts prio (= 3)"), 3119 ok = inet:setopts(L1,[{priority,3}]), 3120 ?P("test_prio_put_get -> set opts tos (= ~p)", [Tos]), 3121 ok = inet:setopts(L1,[{tos,Tos}]), 3122 ?P("test_prio_put_get -> verify opts prio and tos"), 3123 {ok,[{priority,3},{tos,Tos}]} = inet:getopts(L1,[priority,tos]), 3124 ?P("test_prio_put_get -> set opts prio (= 3)"), 3125 ok = inet:setopts(L1,[{priority,3}]), % Dont destroy each other 3126 ?P("test_prio_put_get -> verify opts prio and tos"), 3127 {ok,[{priority,3},{tos,Tos}]} = inet:getopts(L1,[priority,tos]), 3128 ?P("test_prio_put_get -> set opts reuseaddr (= true)"), 3129 ok = inet:setopts(L1,[{reuseaddr,true}]), % Dont let others destroy 3130 ?P("test_prio_put_get -> verify opts prio and tos"), 3131 {ok,[{priority,3},{tos,Tos}]} = inet:getopts(L1,[priority,tos]), 3132 ?P("test_prio_put_get -> close listen socket"), 3133 gen_tcp:close(L1), 3134 ?P("test_prio_put_get -> done"), 3135 ok. 3136 3137test_prio_accept(Config) -> 3138 ?P("test_prio_accept -> create listen socket"), 3139 {ok, Sock} = ?LISTEN(Config, 0, [binary,{packet,0},{active,false}, 3140 {reuseaddr,true},{priority,4}]), 3141 ?P("test_prio_accept -> get port number of listen socket"), 3142 {ok, Port} = inet:port(Sock), 3143 ?P("test_prio_accept -> connect to port ~p", [Port]), 3144 Sock2 = case ?CONNECT(Config, "localhost",Port,[binary,{packet,0}, 3145 {active,false}, 3146 {reuseaddr,true}, 3147 {priority,4}]) of 3148 {ok, S2} -> 3149 S2; 3150 {error, eaddrnotavail = Reason} -> 3151 ?SKIPT(connect_failed_str(Reason)) 3152 end, 3153 ?P("test_prio_accept -> connected => accept connection"), 3154 {ok, Sock3} = gen_tcp:accept(Sock), 3155 ?P("test_prio_accept -> accepted => getopts prio for listen socket"), 3156 {ok, [{priority,4}]} = inet:getopts(Sock, [priority]), 3157 ?P("test_prio_accept -> getopts prio for connected socket"), 3158 {ok, [{priority,4}]} = inet:getopts(Sock2, [priority]), 3159 ?P("test_prio_accept -> getopts prio for accepted socket"), 3160 {ok, [{priority,4}]} = inet:getopts(Sock3, [priority]), 3161 ?P("test_prio_accept -> close listen socket"), 3162 gen_tcp:close(Sock), 3163 ?P("test_prio_accept -> close connected socket"), 3164 gen_tcp:close(Sock2), 3165 ?P("test_prio_accept -> close accepted socket"), 3166 gen_tcp:close(Sock3), 3167 ?P("test_prio_accept -> done"), 3168 ok. 3169 3170test_prio_accept2(Config) -> 3171 Tos1 = 4 bsl 5, 3172 Tos2 = 3 bsl 5, 3173 ?P("test_prio_accept2 -> create listen socket"), 3174 {ok, Sock} = ?LISTEN(Config, 0,[binary,{packet,0},{active,false}, 3175 {reuseaddr,true},{priority,4}, 3176 {tos,Tos1}]), 3177 ?P("test_prio_accept2 -> get port number of listen socket"), 3178 {ok, Port} = inet:port(Sock), 3179 ?P("test_prio_accept2 -> connect to port ~p", [Port]), 3180 Sock2 = case ?CONNECT(Config, "localhost",Port,[binary,{packet,0}, 3181 {active,false}, 3182 {reuseaddr,true}, 3183 {priority,4}, 3184 {tos,Tos2}]) of 3185 {ok, S2} -> 3186 S2; 3187 {error, eaddrnotavail = Reason} -> 3188 ?SKIPT(connect_failed_str(Reason)) 3189 end, 3190 ?P("test_prio_accept2 -> connected => accept connection"), 3191 {ok, Sock3} = gen_tcp:accept(Sock), 3192 ?P("test_prio_accept2 -> accepted => getopts prio and tos for listen socket"), 3193 {ok,[{priority,4},{tos,Tos1}]} = inet:getopts(Sock,[priority,tos]), 3194 ?P("test_prio_accept2 -> getopts prio and tos for connected socket"), 3195 {ok,[{priority,4},{tos,Tos2}]} = inet:getopts(Sock2,[priority,tos]), 3196 ?P("test_prio_accept2 -> getopts prio and tos for accepted socket"), 3197 {ok,[{priority,4},{tos,Tos1}]} = inet:getopts(Sock3,[priority,tos]), 3198 ?P("test_prio_accept2 -> close listen socket"), 3199 gen_tcp:close(Sock), 3200 ?P("test_prio_accept2 -> close connected socket"), 3201 gen_tcp:close(Sock2), 3202 ?P("test_prio_accept2 -> close accepted socket"), 3203 gen_tcp:close(Sock3), 3204 ?P("test_prio_accept2 -> done"), 3205 ok. 3206 3207test_prio_accept3(Config) -> 3208 Tos1 = 4 bsl 5, 3209 Tos2 = 3 bsl 5, 3210 ?P("test_prio_accept3 -> create listen socket"), 3211 {ok, Sock} = ?LISTEN(Config, 0,[binary,{packet,0},{active,false}, 3212 {reuseaddr,true}, 3213 {tos,Tos1}]), 3214 ?P("test_prio_accept3 -> get port number of listen socket"), 3215 {ok,Port} = inet:port(Sock), 3216 ?P("test_prio_accept3 -> connect to port ~p", [Port]), 3217 Sock2 = case ?CONNECT(Config, "localhost",Port,[binary,{packet,0}, 3218 {active,false}, 3219 {reuseaddr,true}, 3220 {tos,Tos2}]) of 3221 {ok, S2} -> 3222 S2; 3223 {error, eaddrnotavail = Reason} -> 3224 ?SKIPT(connect_failed_str(Reason)) 3225 end, 3226 ?P("test_prio_accept3 -> connected => accept connection"), 3227 {ok, Sock3} = gen_tcp:accept(Sock), 3228 ?P("test_prio_accept3 -> " 3229 "accepted => getopts prio and tos for listen socket"), 3230 {ok, [{priority,0},{tos,Tos1}]} = inet:getopts(Sock, [priority,tos]), 3231 ?P("test_prio_accept3 -> getopts prio and tos for connected socket"), 3232 {ok, [{priority,0},{tos,Tos2}]} = inet:getopts(Sock2, [priority,tos]), 3233 ?P("test_prio_accept3 -> getopts prio and tos for accepted socket"), 3234 {ok, [{priority,0},{tos,Tos1}]} = inet:getopts(Sock3, [priority,tos]), 3235 ?P("test_prio_accept3 -> close listen socket"), 3236 gen_tcp:close(Sock), 3237 ?P("test_prio_accept3 -> close connected socket"), 3238 gen_tcp:close(Sock2), 3239 ?P("test_prio_accept3 -> close accepted socket"), 3240 gen_tcp:close(Sock3), 3241 ?P("test_prio_accept3 -> done"), 3242 ok. 3243 3244test_prio_accept_async(Config) -> 3245 Tos1 = 4 bsl 5, 3246 Tos2 = 3 bsl 5, 3247 Ref = make_ref(), 3248 ?P("test_prio_accept_async -> create prio server"), 3249 spawn(?MODULE, priority_server, [Config, {self(),Ref}]), 3250 Port = receive 3251 {Ref,P} -> P 3252 after 5000 -> ct:fail({error,"helper process timeout"}) 3253 end, 3254 receive 3255 after 3000 -> ok 3256 end, 3257 ?P("test_prio_accept_async -> connect to port ~p", [Port]), 3258 Sock2 = case ?CONNECT(Config, "localhost",Port,[binary,{packet,0}, 3259 {active,false}, 3260 {reuseaddr,true}, 3261 {priority,4}, 3262 {tos,Tos2}]) of 3263 {ok, S2} -> 3264 S2; 3265 {error, eaddrnotavail = Reason} -> 3266 ?SKIPT(connect_failed_str(Reason)) 3267 end, 3268 ?P("test_prio_accept_async -> " 3269 "connected => await prio and tos for listen socket"), 3270 receive 3271 {Ref,{ok,[{priority,4},{tos,Tos1}]}} -> 3272 ok; 3273 {Ref,Error} -> 3274 ct:fail({missmatch,Error}) 3275 after 5000 -> ct:fail({error,"helper process timeout"}) 3276 end, 3277 ?P("test_prio_accept_async -> await prio and tos for accepted socket"), 3278 receive 3279 {Ref,{ok,[{priority,4},{tos,Tos1}]}} -> 3280 ok; 3281 {Ref,Error2} -> 3282 ct:fail({missmatch,Error2}) 3283 after 5000 -> ct:fail({error,"helper process timeout"}) 3284 end, 3285 3286 ?P("test_prio_accept_async -> getopts prio and tos for connected socket"), 3287 {ok,[{priority,4},{tos,Tos2}]} = inet:getopts(Sock2, [priority,tos]), 3288 ?P("test_prio_accept_async -> close connected socket"), 3289 catch gen_tcp:close(Sock2), 3290 ?P("test_prio_accept_async -> done"), 3291 ok. 3292 3293priority_server(Config, {Parent,Ref}) -> 3294 Tos1 = 4 bsl 5, 3295 {ok,Sock}=?LISTEN(Config, 0,[binary,{packet,0},{active,false}, 3296 {reuseaddr,true},{priority,4}, 3297 {tos,Tos1}]), 3298 {ok,Port} = inet:port(Sock), 3299 Parent ! {Ref,Port}, 3300 {ok,Sock3}=gen_tcp:accept(Sock), 3301 Parent ! {Ref, inet:getopts(Sock,[priority,tos])}, 3302 Parent ! {Ref, inet:getopts(Sock3,[priority,tos])}, 3303 ok. 3304 3305test_prio_fail(Config) -> 3306 ?P("test_prio_fail -> create listen socket"), 3307 {ok,L} = ?LISTEN(Config, 0, [{active,false}]), 3308 ?P("test_prio_fail -> try set (and fail) opts prio (= 1000)"), 3309 {error,_} = inet:setopts(L,[{priority,1000}]), 3310 ?P("test_prio_fail -> close listen socket"), 3311 gen_tcp:close(L), 3312 ?P("test_prio_fail -> done"), 3313 ok. 3314 3315test_prio_udp() -> 3316 Tos = 3 bsl 5, 3317 ?P("test_prio_udp -> create UDP socket (open)"), 3318 {ok,S} = gen_udp:open(0,[{active,false},binary,{tos, Tos}, 3319 {priority,3}]), 3320 ?P("test_prio_udp -> getopts prio and tos"), 3321 {ok,[{priority,3},{tos,Tos}]} = inet:getopts(S,[priority,tos]), 3322 ?P("test_prio_fail -> close socket"), 3323 gen_udp:close(S), 3324 ?P("test_prio_fail -> done"), 3325 ok. 3326 3327%% Tests the so_priority and ip_tos options on sockets when applicable. 3328so_priority(Config) when is_list(Config) -> 3329 ?TC_TRY(so_priority, 3330 %% Normally we should have the condition funm here, 3331 %% but since we are (currently) not platform independant, 3332 %% we can't...check in the test case instead. 3333 fun() -> do_so_priority(Config) end). 3334 3335do_so_priority(Config) -> 3336 ?P("create listen socket"), 3337 L = case ?LISTEN(Config, 0, [{active,false}]) of 3338 {ok, LSock} when not is_port(LSock) -> 3339 try socket:is_supported(options, socket, priority) of 3340 true -> 3341 LSock; 3342 false -> 3343 (catch gen_tcp:close(LSock)), 3344 ?SKIPT("Option 'priority' not supported") 3345 catch 3346 _:_:_ -> 3347 (catch gen_tcp:close(LSock)), 3348 ?SKIPT("Option 'priority' not supported") 3349 end; 3350 {ok, LSock} when is_port(LSock) -> 3351 LSock 3352 end, 3353 ?P("set opts on listen socket: prio to 1"), 3354 ok = inet:setopts(L,[{priority,1}]), 3355 ?P("verify prio"), 3356 case inet:getopts(L,[priority]) of 3357 {ok,[{priority,1}]} -> 3358 ?P("close listen socket"), 3359 gen_tcp:close(L), 3360 test_prio_put_get(Config), 3361 test_prio_accept(Config), 3362 test_prio_accept2(Config), 3363 test_prio_accept3(Config), 3364 test_prio_accept_async(Config), 3365 test_prio_fail(Config), 3366 test_prio_udp(), 3367 ?P("done"), 3368 ok; 3369 _X -> 3370 case os:type() of 3371 {unix,linux} -> 3372 case os:version() of 3373 {X,Y,_} when (X > 2) or ((X =:= 2) and (Y >= 4)) -> 3374 ?P("so prio should work on this version: " 3375 "~n ~p", [_X]), 3376 ct:fail({error, 3377 "so_priority should work on this " 3378 "OS, but does not"}); 3379 _ -> 3380 {skip, "SO_PRIORITY not suppoorted"} 3381 end; 3382 _ -> 3383 {skip, "SO_PRIORITY not suppoorted"} 3384 end 3385 end. 3386 3387 3388 3389%% IP_RECVTOS and IP_RECVTCLASS for IP_PKTOPTIONS 3390%% does not seem to be implemented in Linux until kernel 3.1 3391%% 3392%% It seems pktoptions does not return valid values 3393%% for IPv4 connect sockets. On the accept socket 3394%% we get valid values, but on the connect socket we get 3395%% the default values for TOS and TTL. 3396%% 3397%% Therefore the argument CheckConnect that enables 3398%% checking the returned values for the connect socket. 3399%% It is only used for recvtclass that is an IPv6 option 3400%% and there we get valid values from both socket ends. 3401 3402has_support_ip_pktoptions() -> 3403 has_support_ip_option(pktoptions). 3404 3405has_support_ip_recvtos() -> 3406 has_support_ip_option(recvtos). 3407 3408has_support_ip_recvttl() -> 3409 has_support_ip_option(recvttl). 3410 3411has_support_ipv6_pktoptions() -> 3412 has_support_ipv6_option(pktoptions). 3413 3414has_support_ipv6_tclass() -> 3415 has_support_ipv6_option(tclass). 3416 3417has_support_ip_option(Opt) -> 3418 has_support_option(ip, Opt). 3419 3420has_support_ipv6_option(Opt) -> 3421 has_support_option(ipv6, Opt). 3422 3423has_support_option(Level, Option) -> 3424 try socket:is_supported(options, Level, Option) 3425 catch 3426 _:_:_ -> false % Any platform that does not support socket! 3427 end. 3428 3429has_os_support_recvtos() -> 3430 has_os_support_recvtos(os:type(), os:version()). 3431 3432has_os_support_recvtos({unix, linux}, Version) -> 3433 not semver_lt(Version, {3,1,0}); 3434has_os_support_recvtos(_, _) -> 3435 true. 3436 3437has_os_support_recvttl() -> 3438 has_os_support_recvttl(os:type(), os:version()). 3439 3440has_os_support_recvttl({unix, linux}, Version) -> 3441 not semver_lt(Version, {2,7,0}); 3442has_os_support_recvttl(_, _) -> 3443 %% We should not even get here, but just in case... 3444 false. 3445 3446has_os_support_recvtclass() -> 3447 has_os_support_recvtclass(os:type(), os:version()). 3448 3449has_os_support_recvtclass({unix, linux}, Version) -> 3450 not semver_lt(Version, {3,1,0}); 3451has_os_support_recvtclass(_, _) -> 3452 true. 3453 3454semver_lt({X1,Y1,Z1} = V1, {X2,Y2,Z2} = V2) -> 3455 ?P("semver_lt -> OS version check:" 3456 "~n (Actual) Version 1: ~p" 3457 "~n (Request) Version 2: ~p", [V1, V2]), 3458 if 3459 X1 > X2 -> ?P("semver_lt -> X1 > X2: ~p > ~p", [X1, X2]), false; 3460 X1 < X2 -> ?P("semver_lt -> X1 < X2: ~p < ~p", [X1, X2]), true; 3461 Y1 > Y2 -> ?P("semver_lt -> Y1 > Y2: ~p > ~p", [Y1, Y2]), false; 3462 Y1 < Y2 -> ?P("semver_lt -> Y1 < Y2: ~p < ~p", [Y1, Y2]), true; 3463 Z1 > Z2 -> ?P("semver_lt -> Z1 > Z2: ~p > ~p", [Z1, Z2]), false; 3464 Z1 < Z2 -> ?P("semver_lt -> Z1 < Z2: ~p < ~p", [Z1, Z2]), true; 3465 true -> ?P("semver_lt -> default"), false 3466 end; 3467semver_lt(V1, {_,_,_} = V2) -> 3468 ?P("semver_lt -> fallback OS version check when: " 3469 "~n Version 1: ~p" 3470 "~n Version 2: ~p", [V1, V2]), 3471 false. 3472 3473recvtos(Config) -> 3474 test_pktoptions( 3475 Config, 3476 inet, [{recvtos,tos,96}], 3477 fun() -> 3478 has_support_ip_recvtos() andalso 3479 has_os_support_recvtos() 3480 end, 3481 "recvtos", 3482 false). 3483 3484recvtosttl(Config) -> 3485 test_pktoptions( 3486 Config, 3487 inet, [{recvtos,tos,96},{recvttl,ttl,33}], 3488 fun() -> 3489 has_support_ip_recvtos() andalso 3490 has_support_ip_recvttl() andalso 3491 has_os_support_recvtos() andalso 3492 has_os_support_recvttl() 3493 end, 3494 "recvtos and/or recvttl", 3495 false). 3496 3497recvttl(Config) -> 3498 test_pktoptions( 3499 Config, 3500 inet, [{recvttl,ttl,33}], 3501 fun() -> 3502 has_support_ip_recvttl() andalso 3503 has_os_support_recvttl() 3504 end, 3505 "recvttl", 3506 false). 3507 3508recvtclass(Config) -> 3509 {ok,IFs} = inet:getifaddrs(), 3510 case 3511 [Name || 3512 {Name,Opts} <- IFs, 3513 lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)] 3514 of 3515 [_] -> 3516 test_pktoptions( 3517 Config, 3518 inet6, [{recvtclass,tclass,224}], 3519 fun() -> 3520 has_support_ipv6_tclass() andalso 3521 has_os_support_recvtclass() 3522 end, 3523 "tclass", 3524 true); 3525 [] -> 3526 {skip,{ipv6_not_supported,IFs}} 3527 end. 3528 3529test_pktoptions(Config, Family, Spec, OptCond, OptStr, CheckConnect) -> 3530 ?P("test_pktoptions -> begin test with" 3531 "~n Config: ~p" 3532 "~n Family: ~p" 3533 "~n Spec: ~p" 3534 "~n CheckConnect: ~p", 3535 [Config, Family, Spec, CheckConnect]), 3536 PktOptsCond = fun(inet) -> has_support_ip_pktoptions(); 3537 (inet6) -> has_support_ipv6_pktoptions() 3538 end, 3539 try PktOptsCond(Family) of 3540 true -> 3541 ?P("pktoptions supported for family ~w", [Family]), 3542 case OptCond() of 3543 true -> 3544 ?P("options supported: " 3545 "~n ~p", [Spec]), 3546 test_pktoptions(Config, Family, Spec, CheckConnect); 3547 false -> 3548 {skip, ?F("Option(s) ~s not supported", [OptStr])} 3549 end; 3550 false -> 3551 {skip, 3552 ?F("Option 'pktoptions' not supported for family ~w", [Family])} 3553 catch 3554 _:_:_ -> 3555 {skip, 3556 ?F("Option 'pktoptions' not supported for family ~w", [Family])} 3557 end. 3558%% 3559test_pktoptions(Config, Family, Spec, CheckConnect) -> 3560 ?P("test_pktoptions -> begin test with" 3561 "~n Config: ~p" 3562 "~n Family: ~p" 3563 "~n Spec: ~p" 3564 "~n CheckConnect: ~p", 3565 [Config, Family, Spec, CheckConnect]), 3566 Timeout = 5000, 3567 RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec], 3568 TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec], 3569 FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec], 3570 Opts = [Opt || {_,Opt,_} <- Spec], 3571 OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec], 3572 Address = 3573 case Family of 3574 inet -> 3575 {127,0,0,1}; 3576 inet6 -> 3577 {0,0,0,0,0,0,0,1} 3578 end, 3579 %% 3580 %% Set RecvOpts on listen socket 3581 ?P("try create listen socket with: ~p", [TrueRecvOpts]), 3582 {ok, L} = 3583 ?LISTEN(Config, 3584 0, 3585 [Family,binary,{active,false},{send_timeout,Timeout} 3586 |TrueRecvOpts]), 3587 {ok, P} = inet:port(L), 3588 ?P("get (recv) options for listen socket: " 3589 "~n ~p", [RecvOpts]), 3590 {ok, TrueRecvOpts} = inet:getopts(L, RecvOpts), 3591 ?P("get options for listen socket: " 3592 "~n ~p", [Opts]), 3593 {ok, OptsValsDefault} = inet:getopts(L, Opts), 3594 3595 %% 3596 %% Set RecvOpts and Option values on connect socket 3597 ?P("create connect socket with" 3598 "~n ~p", [TrueRecvOpts ++ OptsVals]), 3599 {ok, S2} = 3600 ?CONNECT(Config, 3601 Address, P, 3602 [Family,binary,{active,false},{send_timeout,Timeout} 3603 |TrueRecvOpts ++ OptsVals], 3604 Timeout), 3605 ?P("get (recv) options for connect socket: " 3606 "~n ~p", [RecvOpts]), 3607 {ok, TrueRecvOpts} = inet:getopts(S2, RecvOpts), 3608 ?P("get options for connect socket: " 3609 "~n ~p", [Opts]), 3610 {ok, OptsVals} = inet:getopts(S2, Opts), 3611 3612 %% 3613 %% Accept socket inherits the options from listen socket 3614 ?P("try create accept socket"), 3615 {ok, S1} = gen_tcp:accept(L, Timeout), 3616 ?P("get (recv) options for accept socket: " 3617 "~n ~p", [RecvOpts]), 3618 {ok, TrueRecvOpts} = inet:getopts(S1, RecvOpts), 3619 3620 ?P("get options for accept socket: " 3621 "~n ~p", [Opts]), 3622 {ok, OptsValsDefault} = inet:getopts(S1, Opts), 3623 ?P("accept socket option values: " 3624 "~n ~p", [OptsValsDefault]), 3625 3626%%% %% 3627%%% %% Handshake 3628%%% ok = gen_tcp:send(S1, <<"hello">>), 3629%%% {ok,<<"hello">>} = gen_tcp:recv(S2, 5, Timeout), 3630%%% ok = gen_tcp:send(S2, <<"hi">>), 3631%%% {ok,<<"hi">>} = gen_tcp:recv(S1, 2, Timeout), 3632 3633 %% 3634 %% Verify returned remote options 3635 VerifyRemOpts = 3636 fun(S, Role) -> 3637 case inet:getopts(S, [pktoptions]) of 3638 {ok, []} -> 3639 ?SKIPT("pktoptions not supported"); 3640 {ok, [{pktoptions, PktOpts1}]} -> 3641 ?P("PktOptions (~w): " 3642 "~n ~p", [Role, PktOpts1]), 3643 PktOpts1; 3644 {ok, UnexpOK1} -> 3645 ?P("Unexpected OK (~w): " 3646 "~n ~p" 3647 "~n", [Role, UnexpOK1]), 3648 exit({unexpected_getopts_ok, 3649 Role, 3650 Spec, 3651 TrueRecvOpts, 3652 OptsVals, 3653 OptsValsDefault, 3654 UnexpOK1}); 3655 {error, UnexpERR1} -> 3656 ?P("Unexpected ERROR (~w): " 3657 "~n ~p" 3658 "~n", [Role, UnexpERR1]), 3659 exit({unexpected_getopts_failure, 3660 Role, 3661 Spec, 3662 TrueRecvOpts, 3663 OptsVals, 3664 OptsValsDefault, 3665 UnexpERR1}) 3666 end 3667 end, 3668 ?P("verify dest (accept)"), 3669 OptsVals1 = VerifyRemOpts(S1, dest), 3670 ?P("verify orig (connect)"), 3671 OptsVals2 = VerifyRemOpts(S2, orig), 3672 %% {ok,[{pktoptions,OptsVals1}]} = inet:getopts(S1, [pktoptions]), 3673 %% {ok,[{pktoptions,OptsVals2}]} = inet:getopts(S2, [pktoptions]), 3674 (Result1 = sets_eq(OptsVals1, OptsVals)) 3675 orelse ?P("Accept differs: ~p neq ~p", [OptsVals1,OptsVals]), 3676 (Result2 = sets_eq(OptsVals2, OptsValsDefault)) 3677 orelse ?P("Connect differs: ~p neq ~p", 3678 [OptsVals2, OptsValsDefault]), 3679 %% 3680 ?P("close connect socket"), 3681 ok = gen_tcp:close(S2), 3682 ?P("close accept socket"), 3683 ok = gen_tcp:close(S1), 3684 %% 3685 %% 3686 %% Clear RecvOpts on listen socket and set Option values 3687 ?P("clear (recv) options on listen socket"), 3688 ok = inet:setopts(L, FalseRecvOpts ++ OptsVals), 3689 {ok,FalseRecvOpts} = inet:getopts(L, RecvOpts), 3690 ?P("set options on listen socket"), 3691 {ok,OptsVals} = inet:getopts(L, Opts), 3692 3693 %% 3694 %% Set RecvOpts on connecting socket 3695 %% 3696 ?P("create connect socket with" 3697 "~n ~p", [TrueRecvOpts]), 3698 {ok,S4} = 3699 ?CONNECT(Config, 3700 Address, P, 3701 [Family,binary,{active,false},{send_timeout,Timeout} 3702 |TrueRecvOpts], 3703 Timeout), 3704 ?P("get (recv) options on connect socket"), 3705 {ok,TrueRecvOpts} = inet:getopts(S4, RecvOpts), 3706 ?P("get options on connect socket"), 3707 {ok,OptsValsDefault} = inet:getopts(S4, Opts), 3708 3709 %% 3710 %% Accept socket inherits the options from listen socket 3711 ?P("create accept socket"), 3712 {ok,S3} = gen_tcp:accept(L, Timeout), 3713 ?P("get (recv) options on accept socket"), 3714 {ok,FalseRecvOpts} = inet:getopts(S3, RecvOpts), 3715 {ok,OptsVals} = inet:getopts(S3, Opts), 3716 %% 3717 %% Verify returned remote options 3718 ?P("verify pktoptions on accept socket"), 3719 {ok,[{pktoptions,[]}]} = inet:getopts(S3, [pktoptions]), 3720 ?P("verify pktoptions on connect socket"), 3721 {ok,[{pktoptions,OptsVals4}]} = inet:getopts(S4, [pktoptions]), 3722 ?P("verify options set"), 3723 (Result3 = sets_eq(OptsVals4, OptsVals)) 3724 orelse ?P("Accept2 differs: ~p neq ~p", [OptsVals4, OptsVals]), 3725 %% 3726 ?P("close connect socket"), 3727 ok = gen_tcp:close(S4), 3728 ?P("close accept socket"), 3729 ok = gen_tcp:close(S3), 3730 ?P("close listen socket"), 3731 ok = gen_tcp:close(L), 3732 ?P("verify final result" 3733 "~n Result1: ~p" 3734 "~n Check Connect: ~p" 3735 "~n Result2: ~p" 3736 "~n Result3: ~p", 3737 [Result1, CheckConnect, Result2, Result3]), 3738 (Result1 and ((not CheckConnect) or (Result2 and Result3))) 3739 orelse 3740 exit({failed, 3741 [{OptsVals1,OptsVals4,OptsVals}, 3742 {OptsVals2,OptsValsDefault}]}), 3743 ?P("done"), 3744 ok. 3745 3746sets_eq(L1, L2) -> 3747 lists:sort(L1) == lists:sort(L2). 3748 3749 3750 3751%% Accept test utilities (suites are below) 3752 3753millis() -> 3754 erlang:monotonic_time(millisecond). 3755 3756collect_accepts(0,_) -> []; 3757collect_accepts(N,Tmo) -> 3758 A = millis(), 3759 receive 3760 {accepted, P, {error, eaddrnotavail = Reason}} -> 3761 ?P("~p Failed accept: ~p", [P, Reason]), 3762 ?SKIPT(accept_failed_str(Reason)); 3763 3764 {accepted,P,Msg} -> 3765 ?P("received accepted from ~p: " 3766 "~n ~p", [P, Msg]), 3767 NextN = if N =:= infinity -> N; true -> N - 1 end, 3768 [{P,Msg}] ++ collect_accepts(NextN, Tmo - (millis()-A)) 3769 3770 after Tmo -> 3771 ?P("accept timeout (~w)", [Tmo]), 3772 [] 3773 end. 3774 3775-define(EXPECT_ACCEPTS(Pattern,N,Timeout), 3776 (fun() -> 3777 case collect_accepts((N), (Timeout)) of 3778 Pattern -> 3779 ok; 3780 Other__ -> 3781 {error,{unexpected,{Other__,process_info(self(),messages)}}} 3782 end 3783 end)()). 3784 3785collect_connects(Tmo) -> 3786 A = millis(), 3787 receive 3788 {connected, P, {error, eaddrnotavail = Reason}} -> 3789 ?P("~p Failed connect: ~p", [P, Reason]), 3790 ?SKIPT(connect_failed_str(Reason)); 3791 3792 {connected,P,Msg} -> 3793 ?P("received connected from ~p: " 3794 "~n ~p", [P, Msg]), 3795 [{P,Msg}] ++ collect_connects(Tmo-(millis() - A)) 3796 3797 after Tmo -> 3798 [] 3799 end. 3800 3801-define(EXPECT_CONNECTS(Pattern,Timeout), 3802 (fun() -> 3803 case collect_connects(Timeout) of 3804 Pattern -> 3805 ok; 3806 Other -> 3807 {error,{unexpected,Other}} 3808 end 3809 end)()). 3810 3811mktmofun(Tmo,Parent,LS) -> 3812 fun() -> Parent ! {accepted,self(), catch gen_tcp:accept(LS,Tmo)} end. 3813 3814%% Accept tests 3815%% Test singular accept. 3816primitive_accept(Config) when is_list(Config) -> 3817 try do_primitive_accept(Config) 3818 catch 3819 throw:{skip, _} = SKIP -> 3820 SKIP 3821 end. 3822 3823do_primitive_accept(Config) -> 3824 LSock = 3825 case ?LISTEN(Config, 0,[]) of 3826 {ok, LS} -> 3827 LS; 3828 {error, LReason} -> 3829 ?SKIPT(listen_failed_str(LReason)) 3830 end, 3831 {ok, PortNo} = inet:port(LSock), 3832 Parent = self(), 3833 F = fun() -> Parent ! {accepted,self(),gen_tcp:accept(LSock)} end, 3834 P = spawn(F), 3835 case ?CONNECT(Config, "localhost", PortNo, []) of 3836 {ok, _} -> 3837 ok; 3838 {error, eaddrnotavail = CReason} -> 3839 ?SKIPT(connect_failed_str(CReason)) 3840 end, 3841 receive 3842 {accepted,P,{ok,P0}} when is_port(P0) -> 3843 ok; 3844 {accepted,P,Other0} -> 3845 {error,Other0} 3846 after 500 -> 3847 {error,timeout} 3848 end. 3849 3850 3851%% Closing listen socket when multi-accepting. 3852multi_accept_close_listen(Config) when is_list(Config) -> 3853 ?TC_TRY(multi_accept_close_listen, 3854 fun() -> do_multi_accept_close_listen(Config) end). 3855 3856do_multi_accept_close_listen(Config) -> 3857 ?P("try create listen socket"), 3858 LS = case ?LISTEN(Config, 0,[]) of 3859 {ok, LSocket} -> 3860 LSocket; 3861 {error, eaddrnotavail = Reason} -> 3862 ?SKIPT(listen_failed_str(Reason)) 3863 end, 3864 Parent = self(), 3865 F = fun() -> 3866 ?P("started"), 3867 Accepted = gen_tcp:accept(LS), 3868 ?P("accept result: ~p", [Accepted]), 3869 Parent ! {accepted,self(),Accepted} 3870 end, 3871 ?P("create acceptor processes"), 3872 spawn(F), 3873 spawn(F), 3874 spawn(F), 3875 spawn(F), 3876 ?P("sleep some"), 3877 ct:sleep(?SECS(2)), 3878 ?P("close (listen) socket"), 3879 gen_tcp:close(LS), 3880 ?P("await accepts"), 3881 ok = ?EXPECT_ACCEPTS([{_,{error,closed}},{_,{error,closed}}, 3882 {_,{error,closed}},{_,{error,closed}}],4,500), 3883 ?P("done"), 3884 ok. 3885 3886%% Single accept with timeout. 3887accept_timeout(Config) when is_list(Config) -> 3888 try do_accept_timeout(Config) 3889 catch 3890 throw:{skip, _} = SKIP -> 3891 SKIP 3892 end. 3893 3894do_accept_timeout(Config) -> 3895 LS = case ?LISTEN(Config, 0,[]) of 3896 {ok, LSocket} -> 3897 LSocket; 3898 {error, eaddrnotavail = Reason} -> 3899 ?SKIPT(listen_failed_str(Reason)) 3900 end, 3901 Parent = self(), 3902 F = fun() -> Parent ! {accepted,self(),gen_tcp:accept(LS,1000)} end, 3903 P = spawn(F), 3904 ok = ?EXPECT_ACCEPTS([{P,{error,timeout}}],1,2000). 3905 3906%% Check that multi-accept timeouts happen in the correct order. 3907accept_timeouts_in_order(Config) when is_list(Config) -> 3908 try do_accept_timeouts_in_order(Config) 3909 catch 3910 throw:{skip, _} = SKIP -> 3911 SKIP 3912 end. 3913 3914do_accept_timeouts_in_order(Config) -> 3915 LS = case ?LISTEN(Config, 0,[]) of 3916 {ok, LSocket} -> 3917 LSocket; 3918 {error, eaddrnotavail = Reason} -> 3919 ?SKIPT(listen_failed_str(Reason)) 3920 end, 3921 Parent = self(), 3922 P1 = spawn(mktmofun(1000,Parent,LS)), 3923 P2 = spawn(mktmofun(1200,Parent,LS)), 3924 P3 = spawn(mktmofun(1300,Parent,LS)), 3925 P4 = spawn(mktmofun(1400,Parent,LS)), 3926 ok = ?EXPECT_ACCEPTS([{P1,{error,timeout}},{P2,{error,timeout}}, 3927 {P3,{error,timeout}},{P4,{error,timeout}}],infinity,2000). 3928 3929%% Check that multi-accept timeouts happen in the correct order (more). 3930accept_timeouts_in_order2(Config) when is_list(Config) -> 3931 try do_accept_timeouts_in_order2(Config) 3932 catch 3933 throw:{skip, _} = SKIP -> 3934 SKIP 3935 end. 3936 3937do_accept_timeouts_in_order2(Config) -> 3938 LS = case ?LISTEN(Config, 0,[]) of 3939 {ok, LSocket} -> 3940 LSocket; 3941 {error, eaddrnotavail = Reason} -> 3942 ?SKIPT(listen_failed_str(Reason)) 3943 end, 3944 Parent = self(), 3945 P1 = spawn(mktmofun(1400,Parent,LS)), 3946 P2 = spawn(mktmofun(1300,Parent,LS)), 3947 P3 = spawn(mktmofun(1200,Parent,LS)), 3948 P4 = spawn(mktmofun(1000,Parent,LS)), 3949 ok = ?EXPECT_ACCEPTS([{P4,{error,timeout}},{P3,{error,timeout}}, 3950 {P2,{error,timeout}},{P1,{error,timeout}}],infinity,2000). 3951 3952%% Check that multi-accept timeouts happen in the correct order (even more). 3953accept_timeouts_in_order3(Config) when is_list(Config) -> 3954 try do_accept_timeouts_in_order3(Config) 3955 catch 3956 throw:{skip, _} = SKIP -> 3957 SKIP 3958 end. 3959 3960do_accept_timeouts_in_order3(Config) -> 3961 LS = case ?LISTEN(Config, 0,[]) of 3962 {ok, LSocket} -> 3963 LSocket; 3964 {error, eaddrnotavail = Reason} -> 3965 ?SKIPT(listen_failed_str(Reason)) 3966 end, 3967 Parent = self(), 3968 P1 = spawn(mktmofun(1200,Parent,LS)), 3969 P2 = spawn(mktmofun(1400,Parent,LS)), 3970 P3 = spawn(mktmofun(1300,Parent,LS)), 3971 P4 = spawn(mktmofun(1000,Parent,LS)), 3972 ok = ?EXPECT_ACCEPTS([{P4,{error,timeout}},{P1,{error,timeout}}, 3973 {P3,{error,timeout}},{P2,{error,timeout}}],infinity,2000). 3974 3975%% Check that multi-accept timeouts happen in the correct order after 3976%% mixing millsec and sec timeouts. 3977accept_timeouts_in_order4(Config) when is_list(Config) -> 3978 try do_accept_timeouts_in_order4(Config) 3979 catch 3980 throw:{skip, _} = SKIP -> 3981 SKIP 3982 end. 3983 3984do_accept_timeouts_in_order4(Config) -> 3985 LS = case ?LISTEN(Config, 0,[]) of 3986 {ok, LSocket} -> 3987 LSocket; 3988 {error, eaddrnotavail = Reason} -> 3989 ?SKIPT(listen_failed_str(Reason)) 3990 end, 3991 Parent = self(), 3992 P1 = spawn(mktmofun(200,Parent,LS)), 3993 P2 = spawn(mktmofun(400,Parent,LS)), 3994 P3 = spawn(mktmofun(1000,Parent,LS)), 3995 P4 = spawn(mktmofun(600,Parent,LS)), 3996 ok = ?EXPECT_ACCEPTS([{P1,{error,timeout}},{P2,{error,timeout}}, 3997 {P4,{error,timeout}},{P3,{error,timeout}}],infinity,2000). 3998 3999%% Check that multi-accept timeouts happen in the correct order after 4000%% mixing millsec and sec timeouts (more). 4001accept_timeouts_in_order5(Config) when is_list(Config) -> 4002 try do_accept_timeouts_in_order5(Config) 4003 catch 4004 throw:{skip, _} = SKIP -> 4005 SKIP 4006 end. 4007 4008do_accept_timeouts_in_order5(Config) -> 4009 LS = case ?LISTEN(Config, 0,[]) of 4010 {ok, LSocket} -> 4011 LSocket; 4012 {error, eaddrnotavail = Reason} -> 4013 ?SKIPT(listen_failed_str(Reason)) 4014 end, 4015 Parent = self(), 4016 P1 = spawn(mktmofun(400,Parent,LS)), 4017 P2 = spawn(mktmofun(1000,Parent,LS)), 4018 P3 = spawn(mktmofun(600,Parent,LS)), 4019 P4 = spawn(mktmofun(200,Parent,LS)), 4020 ok = ?EXPECT_ACCEPTS([{P4,{error,timeout}},{P1,{error,timeout}}, 4021 {P3,{error,timeout}},{P2,{error,timeout}}],infinity,2000). 4022 4023%% Check that multi-accept timeouts happen in the correct order after 4024%% mixing millsec and sec timeouts (even more). 4025accept_timeouts_in_order6(Config) when is_list(Config) -> 4026 try do_accept_timeouts_in_order6(Config) 4027 catch 4028 throw:{skip, _} = SKIP -> 4029 SKIP 4030 end. 4031 4032do_accept_timeouts_in_order6(Config) -> 4033 LS = case ?LISTEN(Config, 0,[]) of 4034 {ok, LSocket} -> 4035 LSocket; 4036 {error, eaddrnotavail = Reason} -> 4037 ?SKIPT(listen_failed_str(Reason)) 4038 end, 4039 Parent = self(), 4040 P1 = spawn(mktmofun(1000,Parent,LS)), 4041 P2 = spawn(mktmofun(400,Parent,LS)), 4042 P3 = spawn(mktmofun(600,Parent,LS)), 4043 P4 = spawn(mktmofun(200,Parent,LS)), 4044 ok = ?EXPECT_ACCEPTS([{P4,{error,timeout}},{P2,{error,timeout}}, 4045 {P3,{error,timeout}},{P1,{error,timeout}}],infinity,2000). 4046 4047%% Check that multi-accept timeouts happen in the correct order after 4048%% mixing millsec and sec timeouts (even more++). 4049accept_timeouts_in_order7(Config) when is_list(Config) -> 4050 try do_accept_timeouts_in_order7(Config) 4051 catch 4052 throw:{skip, _} = SKIP -> 4053 SKIP 4054 end. 4055 4056do_accept_timeouts_in_order7(Config) -> 4057 LS = case ?LISTEN(Config, 0,[]) of 4058 {ok, LSocket} -> 4059 LSocket; 4060 {error, eaddrnotavail = Reason} -> 4061 ?SKIPT(listen_failed_str(Reason)) 4062 end, 4063 Parent = self(), 4064 P1 = spawn(mktmofun(1000,Parent,LS)), 4065 P2 = spawn(mktmofun(200,Parent,LS)), 4066 P3 = spawn(mktmofun(1200,Parent,LS)), 4067 P4 = spawn(mktmofun(600,Parent,LS)), 4068 P5 = spawn(mktmofun(400,Parent,LS)), 4069 P6 = spawn(mktmofun(800,Parent,LS)), 4070 P7 = spawn(mktmofun(1600,Parent,LS)), 4071 P8 = spawn(mktmofun(1400,Parent,LS)), 4072 ok = ?EXPECT_ACCEPTS([{P2,{error,timeout}},{P5,{error,timeout}}, 4073 {P4,{error,timeout}},{P6,{error,timeout}}, 4074 {P1,{error,timeout}},{P3,{error,timeout}}, 4075 {P8,{error,timeout}},{P7,{error,timeout}}],infinity,2000). 4076 4077%% Check that multi-accept timeouts behave correctly when 4078%% mixed with successful timeouts. 4079accept_timeouts_mixed(Config) when is_list(Config) -> 4080 ?TC_TRY(accept_timeouts_mixed, 4081 fun() -> do_accept_timeouts_mixed(Config) end). 4082 4083do_accept_timeouts_mixed(Config) -> 4084 ?P("create listen socket"), 4085 LS = case ?LISTEN(Config, 0,[]) of 4086 {ok, LSocket} -> 4087 LSocket; 4088 {error, eaddrnotavail = Reason} -> 4089 ?SKIPT(listen_failed_str(Reason)) 4090 end, 4091 Parent = self(), 4092 {ok,PortNo}=inet:port(LS), 4093 4094 ?P("create acceptor process 1 (with timeout 1000)"), 4095 P1 = spawn(mktmofun(1000,Parent,LS)), 4096 4097 ?P("await ~p accepting", [P1]), 4098 wait_until_accepting(P1,500), 4099 4100 ?P("create acceptor process 2 (with timeout 2000)"), 4101 P2 = spawn(mktmofun(2000,Parent,LS)), 4102 4103 ?P("await ~p accepting", [P2]), 4104 wait_until_accepting(P2,500), 4105 4106 ?P("create acceptor process 3 (with timeout 3000)"), 4107 P3 = spawn(mktmofun(3000,Parent,LS)), 4108 4109 ?P("await ~p accepting", [P3]), 4110 wait_until_accepting(P3,500), 4111 4112 ?P("create acceptor process 4 (with timeout 4000)"), 4113 P4 = spawn(mktmofun(4000,Parent,LS)), 4114 4115 ?P("await ~p accepting", [P4]), 4116 wait_until_accepting(P4,500), 4117 4118 ?P("expect accept from 1 (~p) with timeout", [P1]), 4119 ok = ?EXPECT_ACCEPTS([{P1,{error,timeout}}],infinity,1500), 4120 4121 ?P("connect"), 4122 case ?CONNECT(Config, "localhost", PortNo, []) of 4123 {ok, _} -> 4124 ok; 4125 {error, eaddrnotavail = Reason1} -> 4126 ?SKIPT(connect_failed_str(Reason1)) 4127 end, 4128 4129 ?P("expect accept from 2 (~p) with success", [P2]), 4130 if is_port(LS) -> 4131 ok = ?EXPECT_ACCEPTS([{P2,{ok,Port0}}] when is_port(Port0), 4132 infinity,100); 4133 true -> 4134 ok = ?EXPECT_ACCEPTS([{P2,{ok,_}}],infinity,100) 4135 end, 4136 4137 ?P("expect accept from 3 (~p) with timeout", [P3]), 4138 ok = ?EXPECT_ACCEPTS([{P3,{error,timeout}}],infinity,2000), 4139 4140 ?P("connect"), 4141 case ?CONNECT(Config, "localhost", PortNo, []) of 4142 {error, eaddrnotavail = Reason2} -> 4143 ?SKIPT(connect_failed_str(Reason2)); 4144 _ -> 4145 ok 4146 end, 4147 4148 ?P("expect accept from 4 (~p) with success", [P4]), 4149 if is_port(LS) -> 4150 ok = ?EXPECT_ACCEPTS([{P4,{ok,Port1}}] when is_port(Port1), 4151 infinity,100); 4152 true -> 4153 ok = ?EXPECT_ACCEPTS([{P4,{ok,_Port1}}],infinity,100) 4154 end, 4155 4156 ?P("done"), 4157 ok. 4158 4159%% Check that single acceptor behaves as expected when killed. 4160killing_acceptor(Config) when is_list(Config) -> 4161 ?TC_TRY(killing_acceptor, fun() -> do_killing_acceptor(Config) end). 4162 4163do_killing_acceptor(Config) -> 4164 ?P("create listen socket"), 4165 case ?LISTEN(Config, 0,[]) of 4166 {ok, LSocket} when is_port(LSocket) -> 4167 do_killing_acceptor_inet(LSocket); 4168 {ok, LSocket} -> 4169 do_killing_acceptor_socket(LSocket); 4170 {error, eaddrnotavail = Reason} -> 4171 ?SKIPT(listen_failed_str(Reason)) 4172 end, 4173 ?P("done"), 4174 ok. 4175 4176do_killing_acceptor_inet(LS) -> 4177 ?P("validate state - listening"), 4178 validate_acceptor_state(LS, [listen], []), 4179 4180 ?P("create acceptor process"), 4181 Pid = spawn( 4182 fun() -> 4183 erlang:display({accepted,self(),gen_tcp:accept(LS)}) 4184 end), 4185 ?P("sleep some"), 4186 receive after 100 -> ok 4187 end, 4188 4189 ?P("validate state - accepting"), 4190 validate_acceptor_state(LS, [accepting], []), 4191 4192 ?P("kill acceptor"), 4193 exit(Pid, kill), 4194 ?P("sleep some"), 4195 receive after 100 -> ok 4196 end, 4197 4198 ?P("validate state - listening"), 4199 validate_acceptor_state(LS, [listen], [accepting]), 4200 4201 ?P("cleanup"), 4202 (catch gen_tcp:close(LS)), 4203 ok. 4204 4205do_killing_acceptor_socket(LS) -> 4206 ?P("validate state - listening"), 4207 validate_acceptor_state(LS, 0, [listening], []), 4208 4209 ?P("create acceptor process"), 4210 Pid = spawn( 4211 fun() -> 4212 erlang:display({accepted,self(),gen_tcp:accept(LS)}) 4213 end), 4214 ?P("sleep some"), 4215 ct:sleep(100), 4216 4217 ?P("validate state - accepting"), 4218 validate_acceptor_state(LS, 1, [accepting], []), 4219 4220 ?P("kill acceptor"), 4221 exit(Pid, kill), 4222 ?P("sleep some"), 4223 ct:sleep(100), 4224 4225 ?P("validate state - listening"), 4226 validate_acceptor_state(LS, 0, [listening], [accepting]), 4227 4228 ?P("cleanup"), 4229 (catch gen_tcp:close(LS)), 4230 ok. 4231 4232validate_acceptor_state(LS, ExpStates, ExpNotStates) when is_port(LS) -> 4233 case inet:info(LS) of 4234 #{states := States} -> 4235 4236 ?P("try validate state when: " 4237 "~n Exp States: ~p" 4238 "~n Exp Not States: ~p" 4239 "~n States: ~p", [ExpStates, ExpNotStates, States]), 4240 4241 %% State *shall* contain ExpStates => States1 =/= States 4242 States1 = States -- ExpStates, 4243 4244 %% State shall *not* contain ExpNotStates => States2 =:= States 4245 States2 = States -- ExpNotStates, 4246 4247 if 4248 (States1 =/= States) andalso 4249 (States2 =:= States) -> 4250 ?P("validated: " 4251 "~n Expected States: ~p" 4252 "~n Expected Not States: ~p", 4253 [ExpStates, ExpNotStates]), 4254 ok; 4255 true -> 4256 ?P("invalid states: " 4257 "~n Expected States: ~p" 4258 "~n Expected Not States: ~p" 4259 "~n States: ~p", 4260 [ExpStates, ExpNotStates, States]), 4261 ct:fail("Invalid state(s)") 4262 end; 4263 4264 InvalidInfo -> 4265 ?P("invalid info: " 4266 "~n Expected States: ~p" 4267 "~n Expected Not States: ~p" 4268 "~n Invalid Info: ~p", 4269 [ExpStates, ExpNotStates, InvalidInfo]), 4270 ct:fail("Invalid state") 4271 end. 4272 4273validate_acceptor_state(LS, ExpNumAcc, ExpState, ExpNotState) -> 4274 case inet:info(LS) of 4275 #{num_acceptors := ExpNumAcc, rstates := States} -> 4276 ?P("try validate state when: " 4277 "~n Expected State: ~p" 4278 "~n Expected Not State: ~p" 4279 "~n RStates: ~p", [ExpState, ExpNotState, States]), 4280 4281 %% States *shall* contain ExpState => States1 =/= States 4282 States1 = States -- ExpState, 4283 4284 %% States shall *not* contain ExpNotState => States2 =:= States 4285 States2 = States -- ExpNotState, 4286 4287 if 4288 (States1 =/= States) andalso 4289 (States2 =:= States) -> 4290 ?P("validated: " 4291 "~n Expected States: ~p" 4292 "~n Expected Not States: ~p", 4293 [ExpState, ExpNotState]), 4294 ok; 4295 true -> 4296 ?P("invalid states: " 4297 "~n Expected State: ~p" 4298 "~n Expected Not State: ~p" 4299 "~n States: ~p", 4300 [ExpState, ExpNotState, States]), 4301 ct:fail("Invalid state(s)") 4302 end; 4303 4304 #{num_acceptors := NumAcc, rstates := RStates, wstates := WStates} -> 4305 ?P("invalid state: " 4306 "~n Expected Num Acceptors: ~w" 4307 "~n Num Acceptors: ~w" 4308 "~n Expected State: ~p" 4309 "~n Expected Not State: ~p" 4310 "~n RStates: ~p" 4311 "~n WStates: ~p", 4312 [ExpNumAcc, NumAcc, ExpState, RStates, WStates]), 4313 ct:fail("Invalid state"); 4314 4315 InvalidInfo -> 4316 ?P("invalid info: " 4317 "~n Expected Num Acceptors: ~w" 4318 "~n Expected State: ~p" 4319 "~n Expected Not State: ~p" 4320 "~n Invalid Info: ~p", 4321 [ExpNumAcc, ExpNumAcc, ExpState, InvalidInfo]), 4322 ct:fail("Invalid state") 4323 end. 4324 4325 4326%% Check that multi acceptors behaves as expected when killed. 4327killing_multi_acceptors(Config) when is_list(Config) -> 4328 ?TC_TRY(killing_multi_acceptors, 4329 fun() -> do_killing_multi_acceptors(Config) end). 4330 4331do_killing_multi_acceptors(Config) -> 4332 ?P("create listen socket"), 4333 case ?LISTEN(Config, 0,[]) of 4334 {ok, LSocket} when is_port(LSocket) -> 4335 do_killing_multi_acceptors_inet(LSocket); 4336 {ok, LSocket} -> 4337 do_killing_multi_acceptors_socket(LSocket); 4338 {error, eaddrnotavail = Reason} -> 4339 ?SKIPT(listen_failed_str(Reason)) 4340 end, 4341 ?P("done"), 4342 ok. 4343 4344do_killing_multi_acceptors_inet(LS) -> 4345 ?P("validate state - listen"), 4346 validate_acceptor_state(LS, [listen], []), 4347 4348 Parent = self(), 4349 F = fun() -> Parent ! {accepted,self(),gen_tcp:accept(LS)} end, 4350 F2 = mktmofun(1000,Parent,LS), 4351 ?P("create first acceptor"), 4352 Pid = spawn(F), 4353 ?P("create second acceptor - with timeout"), 4354 Pid2 = spawn(F2), 4355 4356 ?P("sleep some"), 4357 receive after 100 -> ok 4358 end, 4359 4360 ?P("validate state - accepting"), 4361 validate_acceptor_state(LS, [accepting], []), 4362 4363 ?P("kill first acceptor"), 4364 exit(Pid, kill), 4365 4366 ?P("sleep some"), 4367 receive after 100 -> ok 4368 end, 4369 4370 ?P("validate state - still accepting"), 4371 validate_acceptor_state(LS, [accepting], []), 4372 4373 ?P("await second acceptor exit - timeout"), 4374 case ?EXPECT_ACCEPTS([{Pid2, {error,timeout}}], 1, 1000) of 4375 ok -> 4376 ?P("second acceptor - expected result"), 4377 ok; 4378 Any -> 4379 ?P("second acceptor - failed:" 4380 "~n ~p", [Any]), 4381 %% Check what Pid2 is doing 4382 Pid2Info1 = process_info(Pid2), 4383 Pid2Msgs1 = process_info(Pid2, messages), 4384 %% Check if this is just a race... 4385 ?SLEEP(?SECS(1)), 4386 Pid2Info2 = process_info(Pid2), 4387 Pid2Msgs2 = process_info(Pid2, messages), 4388 ?P("second acceptor failed - check ~p" 4389 "~n Info 1: ~p" 4390 "~n Msgs 1: ~p" 4391 "~n After 1 sec sleep:" 4392 "~n Info 2: ~p" 4393 "~n Msgs 2: ~p", 4394 [Pid2, Pid2Info1, Pid2Msgs1, Pid2Info2, Pid2Msgs2]), 4395 ct:fail({unexpected_accepts, Any}) 4396 end, 4397 4398 ?P("validate state - *not* accepting"), 4399 validate_acceptor_state(LS, [listen], [accepting]), 4400 4401 ?P("cleanup"), 4402 (catch gen_tcp:close(LS)), 4403 ok. 4404 4405do_killing_multi_acceptors_socket(LS) -> 4406 ?P("validate state - listening"), 4407 validate_acceptor_state(LS, 0, [listening], []), 4408 4409 Parent = self(), 4410 F = fun() -> Parent ! {accepted,self(),gen_tcp:accept(LS)} end, 4411 F2 = mktmofun(1000,Parent,LS), 4412 ?P("create first acceptor"), 4413 Pid = spawn(F), 4414 ?P("create second acceptor - with timeout"), 4415 Pid2 = spawn(F2), 4416 4417 ?P("sleep some"), 4418 ct:sleep(100), 4419 4420 ?P("validate state - accepting"), 4421 validate_acceptor_state(LS, 2, [accepting], []), 4422 4423 ?P("kill first acceptor"), 4424 exit(Pid, kill), 4425 ?P("sleep some"), 4426 ct:sleep(100), 4427 4428 ?P("validate state - (still) accepting"), 4429 validate_acceptor_state(LS, 1, [accepting], []), 4430 4431 ?P("await second acceptor exit - timeout"), 4432 ok = ?EXPECT_ACCEPTS([{Pid2,{error,timeout}}],1,1000), 4433 4434 ?P("validate state - listening"), 4435 validate_acceptor_state(LS, 0, [listening], [accepting]), 4436 4437 ?P("cleanup"), 4438 (catch gen_tcp:close(LS)), 4439 ok. 4440 4441 4442%% Check that multi acceptors behaves as expected when killed (more). 4443killing_multi_acceptors2(Config) when is_list(Config) -> 4444 ?TC_TRY(killing_multi_acceptors2, 4445 fun() -> do_killing_multi_acceptors2(Config) end). 4446 4447do_killing_multi_acceptors2(Config) -> 4448 ?P("create listen socket"), 4449 case ?LISTEN(Config, 0,[]) of 4450 {ok, LSocket} when is_port(LSocket) -> 4451 do_killing_multi_acceptors2_inet(Config, LSocket); 4452 {ok, LSocket} -> 4453 do_killing_multi_acceptors2_socket(Config, LSocket); 4454 {error, eaddrnotavail = Reason} -> 4455 ?SKIPT(listen_failed_str(Reason)) 4456 end, 4457 ?P("done"), 4458 ok. 4459 4460do_killing_multi_acceptors2_inet(Config, LS) -> 4461 ?P("validate state - listen"), 4462 validate_acceptor_state(LS, [listen], []), 4463 4464 Parent = self(), 4465 ?P("get port number for listen socket"), 4466 {ok, PortNo} = inet:port(LS), 4467 4468 F = fun() -> Parent ! {accepted,self(),gen_tcp:accept(LS)} end, 4469 F2 = mktmofun(1000,Parent,LS), 4470 4471 ?P("create acceptor process 1"), 4472 Pid = spawn(F), 4473 ?P("create acceptor process 2"), 4474 Pid2 = spawn(F), 4475 ?P("wait some"), 4476 receive after 100 -> ok 4477 end, 4478 4479 ?P("validate state - accepting"), 4480 validate_acceptor_state(LS, [accepting], []), 4481 4482 ?P("kill acceptor 1"), 4483 exit(Pid,kill), 4484 4485 ?P("sleep some"), 4486 receive after 100 -> ok 4487 end, 4488 4489 ?P("validate state - (still) accepting"), 4490 {ok, L2} = prim_inet:getstatus(LS), 4491 true = lists:member(accepting, L2), 4492 4493 ?P("kill acceptor 2"), 4494 exit(Pid2, kill), 4495 4496 ?P("sleep some"), 4497 receive after 100 -> ok 4498 end, 4499 4500 ?P("validate state - listening"), 4501 validate_acceptor_state(LS, [listen], [accepting]), 4502 4503 ?P("create acceptor 3"), 4504 Pid3 = spawn(F2), 4505 4506 ?P("wait some"), 4507 receive after 100 -> ok 4508 end, 4509 4510 ?P("validate state - accepting"), 4511 validate_acceptor_state(LS, [accepting], []), 4512 4513 ?P("connect to port ~p", [PortNo]), 4514 ?CONNECT(Config, "localhost", PortNo,[]), 4515 4516 ?P("await accept"), 4517 ok = ?EXPECT_ACCEPTS([{Pid3,{ok,CSock}}] when is_port(CSock),1,100), 4518 4519 ?P("validate state - listening"), 4520 validate_acceptor_state(LS, [listen], [accepting]), 4521 4522 ?P("cleanup"), 4523 (catch gen_tcp:close(LS)), 4524 ok. 4525 4526do_killing_multi_acceptors2_socket(Config, LS) -> 4527 ?P("validate state - listening"), 4528 validate_acceptor_state(LS, 0, [listening], []), 4529 4530 Parent = self(), 4531 ?P("get port number for listen socket"), 4532 {ok, PortNo} = inet:port(LS), 4533 4534 F = fun() -> Parent ! {accepted,self(),gen_tcp:accept(LS)} end, 4535 F2 = mktmofun(1000,Parent,LS), 4536 4537 ?P("create acceptor process 1"), 4538 Pid = spawn(F), 4539 ?P("create acceptor process 2"), 4540 Pid2 = spawn(F), 4541 4542 ?P("wait some"), 4543 ct:sleep(100), 4544 4545 ?P("validate state - accepting"), 4546 validate_acceptor_state(LS, 2, [accepting], []), 4547 4548 ?P("kill acceptor 1"), 4549 exit(Pid,kill), 4550 4551 ?P("sleep some"), 4552 ct:sleep(100), 4553 4554 ?P("validate state - (still) accepting"), 4555 validate_acceptor_state(LS, 1, [accepting], []), 4556 4557 ?P("kill acceptor 2"), 4558 exit(Pid2, kill), 4559 4560 ?P("sleep some"), 4561 receive after 100 -> ok 4562 end, 4563 4564 ?P("validate state - listening"), 4565 validate_acceptor_state(LS, 0, [listening], [accepting]), 4566 4567 ?P("create acceptor 3"), 4568 Pid3 = spawn(F2), 4569 4570 ?P("wait some"), 4571 ct:sleep(100), 4572 4573 ?P("validate state - accepting"), 4574 validate_acceptor_state(LS, 1, [accepting], []), 4575 4576 ?P("connect to port ~p", [PortNo]), 4577 ?CONNECT(Config, "localhost", PortNo,[]), 4578 4579 ?P("await accept"), 4580 ok = ?EXPECT_ACCEPTS([{Pid3,{ok, _CSock}}],1,100), 4581 4582 ?P("validate state - listening"), 4583 validate_acceptor_state(LS, 0, [listening], [accepting]), 4584 4585 ?P("cleanup"), 4586 (catch gen_tcp:close(LS)), 4587 ok. 4588 4589 4590%% Checks that multi-accept works when more than one accept can be 4591%% done at once (wb test of inet_driver). 4592several_accepts_in_one_go(Config) when is_list(Config) -> 4593 ?TC_TRY(several_accepts_in_one_go, 4594 fun() -> do_several_accepts_in_one_go(Config) end). 4595 4596do_several_accepts_in_one_go(Config) -> 4597 ?P("create listen socket"), 4598 NumActors = 8, 4599 LS = case ?LISTEN(Config, 0, [{backlog, NumActors}]) of 4600 {ok, LSock} -> 4601 LSock; 4602 {error, eaddrnotavail = Reason} -> 4603 ?SKIPT(listen_failed_str(Reason)) 4604 end, 4605 Parent = self(), 4606 {ok, PortNo} = inet:port(LS), 4607 F1 = fun() -> 4608 ?P("acceptor starting"), 4609 Parent ! {accepted,self(),gen_tcp:accept(LS)} 4610 end, 4611 F2 = fun() -> 4612 ?P("connector starting"), 4613 Parent ! {connected,self(),?CONNECT(Config, "localhost",PortNo,[])} 4614 end, 4615 Ns = lists:seq(1, NumActors), 4616 ?P("start acceptors"), 4617 _ = [spawn(F1) || _ <- Ns], 4618 ?P("await accept timeouts"), 4619 ok = ?EXPECT_ACCEPTS([],1,500), % wait for tmo 4620 ?P("start connectors"), 4621 _ = [spawn(F2) || _ <- Ns], 4622 ?P("await accepts"), 4623 ok = ?EXPECT_ACCEPTS([{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}}],NumActors,15000), 4624 ?P("await connects"), 4625 ok = ?EXPECT_CONNECTS([{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}},{_,{ok,_}}],1000), 4626 ?P("done"), 4627 ok. 4628 4629flush(Msgs) -> 4630 erlang:yield(), 4631 receive Msg -> flush([Msg|Msgs]) 4632 after 0 -> lists:reverse(Msgs) 4633 end. 4634 4635wait_until_accepting(Proc,0) -> 4636 exit({timeout_waiting_for_accepting,Proc}); 4637wait_until_accepting(Proc,N) -> 4638 case process_info(Proc,current_function) of 4639 {current_function, {prim_inet, accept0, 3}} -> 4640 case process_info(Proc, status) of 4641 {status,waiting} -> 4642 ok; 4643 _O1 -> 4644 receive 4645 after 5 -> 4646 wait_until_accepting(Proc, N-1) 4647 end 4648 end; 4649 {current_function, {gen, do_call, 4}} -> 4650 case process_info(Proc, status) of 4651 {status,waiting} -> 4652 ok; 4653 _O1 -> 4654 receive 4655 after 5 -> 4656 wait_until_accepting(Proc, N-1) 4657 end 4658 end; 4659 _O2 -> 4660 receive 4661 after 5 -> 4662 wait_until_accepting(Proc, N-1) 4663 end 4664 end. 4665 4666 4667%% Check that accept returns {error, system_limit} 4668%% (and not {error, enfile}) when running out of ports. 4669accept_system_limit(Config) when is_list(Config) -> 4670 Cond = fun() -> 4671 case ?IS_SOCKET_BACKEND(Config) of 4672 true -> 4673 {skip, "Not complient with socket"}; 4674 false -> 4675 ok 4676 end 4677 end, 4678 TC = fun() -> do_accept_system_limit(Config) end, 4679 ?TC_TRY(accept_system_limit, Cond, TC). 4680 4681do_accept_system_limit(Config) -> 4682 ?P("create listen socket"), 4683 LS = case ?LISTEN(Config, 0, []) of 4684 {ok, LSocket} -> 4685 LSocket; 4686 {error, eaddrnotavail = Reason} -> 4687 ?SKIPT(listen_failed_str(Reason)) 4688 end, 4689 {ok, {Addr, Port}} = inet:sockname(LS), 4690 ?P("listen socket \"bound\" to:" 4691 "~n Address: ~p" 4692 "~n Port: ~p", [Addr, Port]), 4693 Me = self(), 4694 ?P("create connector"), 4695 Connector = spawn_link(fun() -> 4696 connector(Config, Port, Me) 4697 end), 4698 ?P("sync with connector (~p)", [Connector]), 4699 receive {Connector, sync} -> Connector ! {self(), continue} end, 4700 ?P("begin accepting"), 4701 ok = acceptor(Connector, LS, false, []), 4702 ?P("stop connector (~p)", [Connector]), 4703 Connector ! stop, 4704 ?P("done"), 4705 ok. 4706 4707acceptor(Connector, LS, GotSL, A) -> 4708 case gen_tcp:accept(LS, 1000) of 4709 {ok, S} -> 4710 acceptor(Connector, LS, GotSL, [S|A]); 4711 {error, eaddrnotavail = Reason} -> 4712 ?SKIPE(accept_failed_str(Reason)); 4713 {error, system_limit} -> 4714 ?P("acceptor: " 4715 "system limit => *almost* done (~w)", [length(A)]), 4716 acceptor(Connector, LS, true, A); 4717 {error, timeout} when GotSL -> 4718 ?P("acceptor: timeout (with system limit) => done (~w)", 4719 [length(A)]), 4720 ok; 4721 {error, timeout} -> 4722 ?P("acceptor: timeout *without* system limit => failure" 4723 "~n Number of Accepted: ~w", 4724 [length(A)]), 4725 error 4726 end. 4727 4728connector(Config, AccPort, Tester) -> 4729 ?P("[connector] start"), 4730 ManyPorts = open_ports([]), 4731 ?P("[connector] length(ManyPorts): ~p", [length(ManyPorts)]), 4732 Tester ! {self(), sync}, 4733 ?P("[connector] await continute from tester (~p)", [Tester]), 4734 receive {Tester, continue} -> timer:sleep(100) end, 4735 ?P("[connector] begin connecting"), 4736 ConnF = 4737 fun(Port) -> 4738 case (catch ?CONNECT(Config, {127,0,0,1}, AccPort)) of 4739 {ok, Sock} -> 4740 ?P("[connector] success: " 4741 "~n ~p", [Sock]), 4742 Sock; 4743 {error, eaddrnotavail = Reason} -> 4744 ?SKIPE(connect_failed_str(Reason)); 4745 _Error -> 4746 ?P("[connector] failure: " 4747 "~n ~p", [_Error]), 4748 port_close(Port) 4749 end 4750 end, 4751 R = [ConnF(Port) || Port <- lists:sublist(ManyPorts, 10)], 4752 ?P("[connector] await stop"), 4753 receive stop -> ?P("[connector] stop (~w)", [length(R)]), R end. 4754 4755open_ports(L) -> 4756 case catch open_port({spawn_driver, "ram_file_drv"}, []) of 4757 Port when is_port(Port) -> 4758 open_ports([Port|L]); 4759 {'EXIT', {system_limit, _}} -> 4760 {L1, L2} = lists:split(5, L), 4761 [port_close(Port) || Port <- L1], 4762 L2 4763 end. 4764 4765 4766%% Check that active once and tcp_close messages behave as expected. 4767active_once_closed(Config) when is_list(Config) -> 4768 ?TC_TRY(active_once_closed, fun() -> do_active_once_closed(Config) end). 4769 4770do_active_once_closed(Config) -> 4771 ?P("stage 1"), 4772 (fun() -> 4773 ?P("[stage1] begin setup"), 4774 {Loop,A} = setup_closed_ao(Config), 4775 ?P("[stage1] begin send"), 4776 Loop({{error,closed},{error,econnaborted}}, 4777 fun() -> gen_tcp:send(A,"Hello") end), 4778 ?P("[stage1] try set active:once => expect success"), 4779 ok = inet:setopts(A, [{active,once}]), 4780 ?P("[stage1] await socket closed"), 4781 ok = receive {tcp_closed, A} -> ok after 1000 -> error end, 4782 ?P("[stage1] try set active:once => expect failure (einval)"), 4783 {error,einval} = inet:setopts(A,[{active,once}]), 4784 ?P("[stage1] await socket closed - expect timeout"), 4785 ok = receive {tcp_closed, A} -> error after 1000 -> ok end, 4786 ?P("[stage1] done"), 4787 ok 4788 end)(), 4789 ?P("stage 2"), 4790 (fun() -> 4791 ?P("[stage2] begin setup"), 4792 {Loop,A} = setup_closed_ao(Config), 4793 ?P("[stage2] begin send"), 4794 Loop({{error,closed},{error,econnaborted}}, 4795 fun() -> gen_tcp:send(A,"Hello") end), 4796 ?P("[stage2] try set active:true => expect success"), 4797 ok = inet:setopts(A,[{active,true}]), 4798 ?P("[stage2] await socket closed"), 4799 ok = receive {tcp_closed, A} -> ok after 1000 -> error end, 4800 ?P("[stage2] try set active:true => expect failure (einval)"), 4801 {error,einval} = inet:setopts(A,[{active,true}]), 4802 ?P("[stage2] await socket closed - expect timeout"), 4803 ok = receive {tcp_closed, A} -> error after 1000 -> ok end, 4804 ?P("[stage2] done"), 4805 ok 4806 end)(), 4807 ?P("stage 3"), 4808 (fun() -> 4809 ?P("[stage3] begin setup"), 4810 {Loop,A} = setup_closed_ao(Config), 4811 ?P("[stage3] begin send"), 4812 Loop({{error,closed},{error,econnaborted}}, 4813 fun() -> gen_tcp:send(A,"Hello") end), 4814 ?P("[stage3] try set active:true => expect success"), 4815 ok = inet:setopts(A,[{active,true}]), 4816 ?P("[stage3] await socket closed"), 4817 ok = receive {tcp_closed, A} -> ok after 1000 -> error end, 4818 ?P("[stage3] try set active:once => expect failure (einval)"), 4819 {error,einval} = inet:setopts(A,[{active,once}]), 4820 ?P("[stage3] await socket closed - expect timeout"), 4821 ok = receive {tcp_closed, A} -> error after 1000 -> ok end, 4822 ?P("[stage3] done"), 4823 ok 4824 end)(), 4825 ?P("stage 4"), 4826 (fun() -> 4827 ?P("[stage4] begin setup"), 4828 {Loop,A} = setup_closed_ao(Config), 4829 ?P("[stage4] begin send"), 4830 Loop({{error,closed},{error,econnaborted}}, 4831 fun() -> gen_tcp:send(A,"Hello") end), 4832 ?P("[stage1] try set active:once => expect success"), 4833 ok = inet:setopts(A,[{active,once}]), 4834 ?P("[stage4] await socket closed"), 4835 ok = receive {tcp_closed, A} -> ok after 1000 -> error end, 4836 ?P("[stage4] try set active:true => expect failure (einval)"), 4837 {error,einval} = inet:setopts(A,[{active,true}]), 4838 ?P("[stage4] await socket closed - expect timeout"), 4839 ok = receive {tcp_closed, A} -> error after 1000 -> ok end, 4840 ?P("[stage4] done"), 4841 ok 4842 end)(), 4843 ?P("stage 5"), 4844 (fun() -> 4845 ?P("[stage5] begin setup"), 4846 {Loop,A} = setup_closed_ao(Config), 4847 ?P("[stage5] begin send"), 4848 Loop({{error,closed},{error,econnaborted}}, 4849 fun() -> gen_tcp:send(A,"Hello") end), 4850 ?P("[stage5] try set active:false => expect success"), 4851 ok = inet:setopts(A,[{active,false}]), 4852 ?P("[stage5] await socket closed => expect timeout"), 4853 ok = receive {tcp_closed, A} -> error after 1000 -> ok end, 4854 ?P("[stage5] try set active:once => expect success"), 4855 ok = inet:setopts(A,[{active,once}]), 4856 ?P("[stage5] await socket closed"), 4857 ok = receive {tcp_closed, A} -> ok after 1000 -> error end, 4858 ?P("[stage5] done"), 4859 ok 4860 end)(), 4861 ?P("done"), 4862 ok. 4863 4864%% Check that active n and tcp_close messages behave as expected. 4865active_n_closed(Config) when is_list(Config) -> 4866 ?TC_TRY(active_n_closed, fun() -> do_active_n_closed(Config) end). 4867 4868do_active_n_closed(Config) -> 4869 ?P("create listen socket"), 4870 {ok, L} = ?LISTEN(Config, 0, [binary, {active, false}]), 4871 4872 P = self(), 4873 4874 {ok, Port} = inet:port(L), 4875 4876 ClientF = 4877 fun() -> 4878 ?P("[client] started"), 4879 Payload = <<0:50000/unit:8>>, 4880 Cnt = 10000, 4881 ?P("[client] send size"), 4882 P ! {size, Cnt * byte_size(Payload)}, 4883 ?P("[client] try connect"), 4884 S = case ?CONNECT(Config, "localhost", Port, 4885 [binary, {active, false}]) of 4886 {ok, CS} -> 4887 ?P("[client] connected"), 4888 P ! {continue, self()}, 4889 CS; 4890 {error, eaddrnotavail = Reason} -> 4891 ?SKIPE(connect_failed_str(Reason)) 4892 end, 4893 ?P("[client] send payload"), 4894 _ = [gen_tcp:send(S, Payload) || _ <- lists:seq(1, Cnt)], 4895 ?P("[client] close socket"), 4896 gen_tcp:close(S), 4897 ?P("[client] done"), 4898 exit(ok) 4899 end, 4900 ?P("create client process"), 4901 {Pid, MRef} = spawn_monitor(ClientF), 4902 4903 ?P("await size"), 4904 receive {size, SendSize} -> SendSize end, 4905 ?P("await continue or down"), 4906 receive 4907 {continue, Pid} -> 4908 ?P("got continue"), 4909 ok; 4910 {'DOWN', MRef, process, Pid, {skip, _} = SKIP} -> 4911 ?P("got *unexpected* skip"), 4912 gen_tcp:close(L), 4913 throw(SKIP); 4914 {'DOWN', MRef, process, Pid, ConnectRes} -> 4915 ?P("got *unexpected* crash: " 4916 "~n ~p", [ConnectRes]), 4917 exit({unexpected, connect, ConnectRes}) 4918 end, 4919 {ok, S} = gen_tcp:accept(L), 4920 inet:setopts(S, [{active, 10}]), 4921 ?P("start collecting data"), 4922 RecvSize = anc_await_closed_and_down(S, Pid, MRef), 4923 4924 ?P("close listen socket"), 4925 gen_tcp:close(L), 4926 4927 ?P("validate size"), 4928 if SendSize =:= RecvSize -> 4929 ?P("done"), 4930 ok; 4931 true -> 4932 ct:fail("Send and Recv size not equal: ~p ~p", [SendSize, RecvSize]) 4933 end. 4934 4935 4936anc_await_closed_and_down(S, Pid, MRef) -> 4937 anc_await_closed_and_down(S, Pid, MRef, 0, false, false). 4938 4939anc_await_closed_and_down(_S, _Pid, _MRef, Size, true, true) -> 4940 Size; 4941anc_await_closed_and_down(S, Pid, MRef, Size, Closed, Down) -> 4942 receive 4943 {tcp, S, Bin} -> 4944 %% ?P("got a chunk (~w) of data", [byte_size(Bin)]), 4945 anc_await_closed_and_down(S, Pid, MRef, 4946 byte_size(Bin) + Size, Closed, Down); 4947 {tcp_closed, S} -> 4948 ?P("got closed -> we are done: ~w", [Size]), 4949 anc_await_closed_and_down(S, Pid, MRef, Size, true, Down); 4950 {tcp_passive, S} -> 4951 %% ?P("got passive -> active"), 4952 inet:setopts(S, [{active, 10}]), 4953 anc_await_closed_and_down(S, Pid, MRef, Size, Closed, true); 4954 {'DOWN', MRef, process, Pid, ok} -> 4955 ?P("Received expected down message regarding client"), 4956 anc_await_closed_and_down(S, Pid, MRef, Size, Closed, true); 4957 4958 {'DOWN', MRef, process, Pid, Reason} -> 4959 ?P("Received UNEXPECTED down message regarding client:" 4960 "~n Reason: ~p" 4961 "~n Port Info: ~p", 4962 [Reason, (catch erlang:port_info(S))]), 4963 ct:fail({unexpected_client_down, Reason}); 4964 4965 Msg -> 4966 ?P("ignore: ~p", [Msg]), 4967 anc_await_closed_and_down(S, Pid, MRef, Size, Closed, Down) 4968 end. 4969 4970%% Test the send_timeout socket option. 4971send_timeout(Config) when is_list(Config) -> 4972 ?TC_TRY(send_timeout, fun() -> do_send_timeout(Config) end). 4973 4974do_send_timeout(Config) -> 4975 ?P("begin"), 4976 Dir = filename:dirname(code:which(?MODULE)), 4977 ?P("create (slave) node"), 4978 {ok, RNode} = ?START_SLAVE_NODE(?UNIQ_NODE_NAME, "-pa " ++ Dir), 4979 4980 {TslTimeout, SndTimeout, BinData, SndBuf} = 4981 case ?IS_SOCKET_BACKEND(Config) of 4982 true -> 4983 {100, 3000, binary:copy(<<$a:8>>, 10*1024), 5*1024}; 4984 false -> 4985 {1, 1000, binary:copy(<<$a:8>>, 1*1024), 16*1024} 4986 end, 4987 4988 %% Basic 4989 ?P("basic check wo autoclose"), 4990 send_timeout_basic(Config, BinData, SndBuf, TslTimeout, SndTimeout, 4991 false, RNode), 4992 ?P("basic check w autoclose"), 4993 send_timeout_basic(Config, BinData, SndBuf, TslTimeout, SndTimeout, 4994 true, RNode), 4995 4996 %% Check timeout length. 4997 ?P("spawn sink process (check timeout length)"), 4998 Self = self(), 4999 {Pid, Mon} = spawn_monitor( 5000 fun() -> 5001 {A, _} = setup_timeout_sink(Config, 5002 RNode, SndTimeout, 5003 true, SndBuf), 5004 Send = fun() -> 5005 Res = gen_tcp:send(A, BinData), 5006 Self ! Res, 5007 Res 5008 end, 5009 {{error, timeout}, _} = 5010 timeout_sink_loop(Send, TslTimeout) 5011 end), 5012 Diff = get_max_diff(), 5013 ?P("Max time for send: ~p", [Diff]), 5014 true = (Diff > (SndTimeout - 500)) and (Diff < (SndTimeout + 500)), 5015 5016 %% Wait for the process to die. 5017 ?P("await (timeout checker) process death"), 5018 receive {'DOWN', Mon, process, Pid, _} -> ok end, 5019 5020 %% Check that parallell writers do not hang forever 5021 ?P("check parallell writers wo autoclose"), 5022 send_timeout_para(Config, BinData, SndBuf, TslTimeout, SndTimeout, 5023 false, RNode), 5024 ?P("check parallell writers w autoclose"), 5025 send_timeout_para(Config, BinData, SndBuf, TslTimeout, SndTimeout, 5026 true, RNode), 5027 5028 ?P("stop (slave) node"), 5029 ?STOP_NODE(RNode), 5030 5031 ?P("done"), 5032 ok. 5033 5034send_timeout_basic(Config, BinData, SndBuf, TslTimeout, SndTimeout, 5035 AutoClose, RNode) -> 5036 ?P("[basic] sink"), 5037 {A, Pid} = setup_timeout_sink(Config, RNode, SndTimeout, 5038 AutoClose, SndBuf), 5039 Send = fun() -> gen_tcp:send(A, BinData) end, 5040 {{error, timeout}, _} = timeout_sink_loop(Send, TslTimeout), 5041 5042 %% Check that the socket is not busy/closed... 5043 ?P("[basic] verify socket not busy/closed"), 5044 case gen_tcp:send(A, BinData) of 5045 {error, Reason} -> 5046 ?P("[basic] (expected) send failure"), 5047 after_send_timeout(AutoClose, Reason), 5048 (catch gen_tcp:close(A)), 5049 exit(Pid, kill), 5050 ok; 5051 ok -> 5052 %% Note that there is no active reader on the other end, 5053 %% so a 'channel' has been filled, should remain filled. 5054 ?P("[basic] UNEXPECTED send success"), 5055 (catch gen_tcp:close(A)), 5056 exit(Pid, kill), 5057 ct:fail("Unexpected send success") 5058 end. 5059 5060send_timeout_para(Config, BinData, BufSz, TslTimeout, SndTimeout, 5061 AutoClose, RNode) -> 5062 ?P("[para] sink -> entry with" 5063 "~n size(BinData): ~p" 5064 "~n BufSz: ~p" 5065 "~n SndTimeout: ~p" 5066 "~n AutoClose: ~p", 5067 [byte_size(BinData), BufSz, SndTimeout, AutoClose]), 5068 {A, Pid} = setup_timeout_sink(Config, RNode, SndTimeout, AutoClose, BufSz), 5069 Self = self(), 5070 SenderFun = fun() -> 5071 ?P("[para:sender] start"), 5072 Send = fun() -> gen_tcp:send(A, BinData) end, 5073 Self ! {self(), timeout_sink_loop(Send, TslTimeout)} 5074 end, 5075 ?P("[para] spawn process 1 with sender fun"), 5076 Snd1 = spawn_link(SenderFun), 5077 ?P("[para] spawn process 2 with sender fun"), 5078 Snd2 = spawn_link(SenderFun), 5079 5080 SockInfo = fun() -> (catch inet:info(A)) end, 5081 SockTimeout = fun() -> 5082 try inet:getopts(A, [send_timeout]) of 5083 {ok, [V2]} -> 5084 V2; 5085 {error, R2} -> 5086 ?F("ERROR: ~p", [R2]); 5087 X2 -> 5088 ?F("UNKNOWN: ~p", [X2]) 5089 catch 5090 C2:E2:S2 -> 5091 ?F("CATCHED: ~p, ~p, ~p", [C2, E2, S2]) 5092 end 5093 end, 5094 5095 ?P("[para] await first sender timeout when" 5096 "~n Sender 1: ~p" 5097 "~n Sender 2: ~p", [Snd1, Snd2]), 5098 First = 5099 receive 5100 {Snd1, {{error, timeout}, N}} -> 5101 ?P("[para] timeout received from sender 1 (~p, ~p)", [Snd1, N]), 5102 1; 5103 {Snd2, {{error, timeout}, N}} -> 5104 ?P("[para] timeout received from sender 2 (~p, ~p)", [Snd2, N]), 5105 2; 5106 5107 {'EXIT', _Pid, {timetrap_timeout, _Timeout, _Stack}} -> 5108 %% The test case (timetrap) has timed out, which either means 5109 %% we are running on very slow hw or some system functions 5110 %% are slowing us down (this test case should never normally 5111 %% time out like this). 5112 ?P("Test case timetrap timeout - check for system events"), 5113 case kernel_test_global_sys_monitor:events(?SECS(5)) of 5114 SysEvs when (SysEvs =/= []) -> 5115 ?P("timetrap timeout with system events: " 5116 "~n System Events: ~p" 5117 "~n Sender 1 Info: ~p" 5118 "~n Sender 2 Info: ~p" 5119 "~n Socket Info: ~p", 5120 [SysEvs, 5121 process_info(Snd1), process_info(Snd2), 5122 SockInfo()]), 5123 ?SKIPT(?F("TC system ~w events", [length(SysEvs)])); 5124 {error, Reason} -> 5125 ?P("TC timetrap timeout but failed get system events: " 5126 "~n Reason: ~p" 5127 "~n Sender 1 Info: ~p" 5128 "~n Sender 2 Info: ~p" 5129 "~n Socket Info: ~p", 5130 [Reason, 5131 process_info(Snd1), process_info(Snd2), 5132 SockInfo()]), 5133 exit({timetrap, {failed_get_sys_evs, Reason}}); 5134 [] -> 5135 ?P("TC timetrap *without* system events: " 5136 "~n Sender 1 Info: ~p" 5137 "~n Sender 2 Info: ~p" 5138 "~n Socket Info: ~p", 5139 [process_info(Snd1), process_info(Snd2), 5140 SockInfo()]), 5141 exit(timetrap) 5142 end 5143 5144 after 20000 -> 5145 SockInfo1 = SockInfo(), 5146 SockTo1 = SockTimeout(), 5147 ?P("[para] UNEXPECTED timeout(1,~w) when:" 5148 "~n Sender 1 Info: ~p" 5149 "~n Sender 2 Info: ~p" 5150 "~n Socket Info: ~p" 5151 "~n Send Timeout: ~p" 5152 "~n Message Queue: ~p", 5153 [AutoClose, 5154 (catch process_info(Snd1)), 5155 (catch process_info(Snd2)), 5156 SockInfo1, SockTo1, 5157 flush([])]), 5158 Snd1 ! {info_and_die, SockInfo, SockTimeout}, 5159 Snd2 ! {info_and_die, SockInfo, SockTimeout}, 5160 ct:sleep(?SECS(1)), 5161 exit({timeout, AutoClose}) 5162 end, 5163 5164 Second = if (First =:= 1) -> 2; true -> 1 end, 5165 ?P("[para] await second sender ~w error", [Second]), 5166 receive 5167 {Snd1, {{error, Error_1}, N_1}} -> 5168 ?P("[para] error (~p) received from sender 1 (~p, ~p)", 5169 [Error_1, Snd1, N_1]), 5170 after_send_timeout(AutoClose, Error_1); 5171 {Snd2, {{error, Error_1}, N_1}} -> 5172 ?P("[para] error (~p) received from sender 2 (~p, ~p)", 5173 [Error_1, Snd2, N_1]), 5174 after_send_timeout(AutoClose, Error_1) 5175 after 10000 -> 5176 if (Second =:= 1) -> 5177 SockInfo21 = SockInfo(), 5178 SockTo21 = SockTimeout(), 5179 ?P("[para] UNEXPECTED timeout(2, ~w):" 5180 "~n Sender 1 Info: ~p" 5181 "~n Socket Info: ~p" 5182 "~n Send Timeout: ~p" 5183 "~n Message Queue: ~p", 5184 [AutoClose, 5185 (catch process_info(Snd1)), 5186 SockInfo21, SockTo21, 5187 flush([])]), 5188 Snd1 ! {info_and_die, SockInfo, SockTimeout}; 5189 true -> 5190 SockInfo22 = SockInfo(), 5191 SockTo22 = SockTimeout(), 5192 ?P("[para] UNEXPECTED timeout(2, ~w):" 5193 "~n Sender 2 Info: ~p" 5194 "~n Socket Info: ~p" 5195 "~n Send Timeout: ~p" 5196 "~n Message Queue: ~p", 5197 [AutoClose, 5198 (catch process_info(Snd2)), 5199 SockInfo22, SockTo22, 5200 flush([])]), 5201 Snd2 ! {info_and_die, SockInfo, SockTimeout} 5202 end, 5203 ct:sleep(?SECS(1)), 5204 exit({timeout, AutoClose, Second}) 5205 end, 5206 5207 ?P("[para] socket info: " 5208 "~n ~p", [SockInfo()]), 5209 {error, Error_2} = gen_tcp:send(A, BinData), 5210 after_send_timeout(AutoClose, Error_2), 5211 ?P("[para] cleanup - await sender terminations"), 5212 st_await_sender_termination(Snd1, Snd2), 5213 ?P("[para] cleanup - close socket"), 5214 (catch gen_tcp:close(A)), 5215 ?P("[para] cleanup - kill sink"), 5216 exit(Pid, kill), 5217 ?P("[para] done"), 5218 ok. 5219 5220st_await_sender_termination(undefined, undefined) -> 5221 ok; 5222st_await_sender_termination(Sender1, Sender2) -> 5223 receive 5224 {'EXIT', Pid, Reason} when (Pid =:= Sender1) -> 5225 ?P("sender 1 (~p) terminated: " 5226 "~n ~p", [Pid, Reason]), 5227 st_await_sender_termination(undefined, Sender2); 5228 {'EXIT', Pid, Reason} when (Pid =:= Sender2) -> 5229 ?P("sender 2 (~p) terminated: " 5230 "~n ~p", [Pid, Reason]), 5231 st_await_sender_termination(Sender1, undefined) 5232 end. 5233 5234get_max_diff() -> 5235 receive 5236 ok -> 5237 get_max_diff(0) 5238 after 10000 -> 5239 exit(timeout) 5240 end. 5241 5242get_max_diff(Max) -> 5243 T1 = millis(), 5244 receive 5245 ok -> 5246 Diff = millis() - T1, 5247 if 5248 Diff > Max -> 5249 ?P("new max send time: ~w", [Diff]), 5250 get_max_diff(Diff); 5251 true -> 5252 get_max_diff(Max) 5253 end; 5254 {error,timeout} -> 5255 Diff = millis() - T1, 5256 if 5257 Diff > Max -> 5258 ?P("timeout diff (> prev max send to): ~w", [Diff]), 5259 Diff; 5260 true -> 5261 Max 5262 end 5263 after 10000 -> 5264 exit(timeout) 5265 end. 5266 5267after_send_timeout(AutoClose, Reason) -> 5268 case Reason of 5269 timeout when AutoClose =:= false -> ok; 5270 {timeout, _RestData} when AutoClose =:= false -> ok; 5271 enotconn when AutoClose =:= true -> ok; 5272 closed when AutoClose -> ok; 5273 _ -> 5274 ?P("after_send_timeout -> " 5275 "~n AutoClose: ~w" 5276 "~n Reason: ~p", [AutoClose, Reason]), 5277 exit({after_send_timeout, AutoClose, Reason}) 5278 end. 5279 5280 5281%% Test the send_timeout socket option for active sockets. 5282send_timeout_active(Config) when is_list(Config) -> 5283 ?TC_TRY(send_timeout_active, fun() -> do_send_timeout_active(Config) end). 5284 5285do_send_timeout_active(Config) -> 5286 Dir = filename:dirname(code:which(?MODULE)), 5287 {ok, RNode} = ?START_SLAVE_NODE(?UNIQ_NODE_NAME, "-pa " ++ Dir), 5288 do_send_timeout_active(Config, false, RNode), 5289 do_send_timeout_active(Config, true, RNode), 5290 ?STOP_NODE(RNode), 5291 ok. 5292 5293do_send_timeout_active(Config, AutoClose, RNode) -> 5294 {A,C} = setup_active_timeout_sink(Config, RNode, 1, AutoClose), 5295 inet:setopts(A, [{active, once}]), 5296 Mad = spawn_link(RNode, fun() -> mad_sender(C) end), 5297 ListData = lists:duplicate(1000, $a), 5298 F = fun() -> 5299 ?P("[sink action] await data"), 5300 receive 5301 {tcp, _Sock, _Data} -> 5302 ?P("[sink action] active -> once"), 5303 inet:setopts(A, [{active, once}]), 5304 ?P("[sink action] send payload"), 5305 Res = gen_tcp:send(A, ListData), 5306 Res; 5307 Unexpected -> 5308 ?P("[sink action] unexpected message: " 5309 "~n ~p", [Unexpected]), 5310 Unexpected 5311 end 5312 end, 5313 {{error, timeout}, _} = timeout_sink_loop(F, 1), 5314 unlink(Mad), 5315 exit(Mad, kill), 5316 flush(), 5317 ok. 5318 5319mad_sender(S) -> 5320 put(action, nothing), 5321 put(sent, 0), 5322 put(elapsed, 0), 5323 mad_sender(S, 0). 5324 5325mad_sender(S, N) -> 5326 U = rand:uniform(1000000), 5327 put(action, send), 5328 Start = erlang:monotonic_time(), 5329 Ret = gen_tcp:send(S, integer_to_list(U)), 5330 Stop = erlang:monotonic_time(), 5331 Elapsed = get(elapsed), 5332 put(elapsed, Elapsed + (Stop - Start)), 5333 put(action, sent), 5334 N2 = N + 1, 5335 put(sent, N2), 5336 case Ret of 5337 ok -> 5338 mad_sender(S, N + 1); 5339 {error, timeout} = ERROR1 -> 5340 ?P("mad_sender -> send failed: timeout" 5341 "~n Number of sends: ~w" 5342 "~n Elapsed (send) time: ~w msec", 5343 [N2, 5344 erlang:convert_time_unit(get(elapsed), native, millisecond)]), 5345 ERROR1; 5346 {error, {timeout, RestData}} = ERROR2 -> 5347 ?P("mad_sender -> " 5348 "send failed: timeout with ~w bytes of rest data" 5349 "~n Number of sends: ~w" 5350 "~n Elapsed (send) time: ~w msec", 5351 [byte_size(RestData), 5352 N2, 5353 erlang:convert_time_unit(get(elapsed), native, millisecond)]), 5354 ERROR2; 5355 {error, Reason} = ERROR3 -> 5356 ?P("mad_sender -> send failed: " 5357 "~n ~p" 5358 "~n Number of sends: ~w" 5359 "~n Elapsed (send) time: ~w msec", 5360 [Reason, 5361 N2, 5362 erlang:convert_time_unit(get(elapsed), native, millisecond)]), 5363 ERROR3; 5364 ERROR4 -> 5365 ?P("mad_sender -> send failed: " 5366 "~n ~p" 5367 "~n Number of sends: ~w" 5368 "~n Elapsed (send) time: ~w msec", 5369 [ERROR4, 5370 N2, 5371 erlang:convert_time_unit(get(elapsed), native, millisecond)]), 5372 ERROR4 5373 end. 5374 5375flush() -> 5376 receive 5377 _X -> 5378 flush() 5379 after 0 -> 5380 ok 5381 end. 5382 5383setup_closed_ao(Config) -> 5384 Dir = filename:dirname(code:which(?MODULE)), 5385 ?P("[setup] start slave node"), 5386 R = case ?START_SLAVE_NODE(?UNIQ_NODE_NAME, "-pa " ++ Dir) of 5387 {ok, Slave} -> 5388 Slave; 5389 {error, Reason} -> 5390 ?SKIPT(?F("failed starting slave node: ~p", [Reason])) 5391 end, 5392 Host = get_hostname(node()), 5393 ?P("[setup] create listen socket"), 5394 L = case ?LISTEN(Config, 0, [{active,false},{packet,2}]) of 5395 {ok, LSock} -> 5396 LSock; 5397 {error, eaddrnotavail = LReason} -> 5398 (catch ?STOP_NODE(R)), 5399 ?SKIPT(listen_failed_str(LReason)) 5400 end, 5401 Fun = fun(F) -> 5402 receive 5403 {From,X} when is_function(X) -> 5404 From ! {self(),X()}, F(F); 5405 die -> ok 5406 end 5407 end, 5408 ?P("[setup] create remote runner"), 5409 Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]), 5410 {ok, Port} = inet:port(L), 5411 Remote = fun(Fu) -> 5412 Pid ! {self(), Fu}, 5413 receive {Pid,X} -> X end 5414 end, 5415 Connect = fun() -> 5416 ?CONNECT(Config, Host, Port, 5417 [{active, false}, {packet, 2}]) 5418 end, 5419 ?P("[setup] create (remote) connection"), 5420 C = case Remote(Connect) of 5421 {ok, CSock} -> 5422 CSock; 5423 {error, eaddrnotavail = CReason} -> 5424 (catch ?STOP_NODE(R)), 5425 ?SKIPT(connect_failed_str(CReason)) 5426 end, 5427 ?P("[setup] accept (local) connection"), 5428 A = case gen_tcp:accept(L) of 5429 {ok, ASock} -> 5430 ASock; 5431 {error, eaddrnotavail = AReason} -> 5432 (catch ?STOP_NODE(R)), 5433 ?SKIPT(accept_failed_str(AReason)) 5434 end, 5435 ?P("[setup] send (local) and receive (remote) message"), 5436 gen_tcp:send(A,"Hello"), 5437 {ok, "Hello"} = Remote(fun() -> gen_tcp:recv(C,0) end), 5438 ?P("[setup] close (remote) connection"), 5439 ok = Remote(fun() -> gen_tcp:close(C) end), 5440 Loop2 = fun(_,_,_,0) -> 5441 {failure, timeout}; 5442 (L2,{MA,MB},F2,N) -> 5443 case F2() of 5444 MA -> ?P("[setup] action result (MA): ~p", [MA] ), MA; 5445 MB -> ?P("[setup] action result (MB): ~p", [MB] ), MB; 5446 Other -> ?P("[setup] Loop2: ~p",[Other]), 5447 receive after 1000 -> ok end, 5448 L2(L2,{MA,MB},F2,N-1) 5449 end 5450 end, 5451 Loop = fun(Match2,F3) -> Loop2(Loop2,Match2,F3,10) end, 5452 ?P("[setup] stop slave node"), 5453 ?STOP_NODE(R), 5454 ?P("[setup] done"), 5455 {Loop,A}. 5456 5457setup_timeout_sink(Config, RNode, Timeout, AutoClose, BufSz) -> 5458 Host = get_hostname(node()), 5459 ?P("[sink] create listen socket"), 5460 {ok, L} = ?LISTEN(Config, 0, [{active, false}, 5461 {packet, 4}, 5462 {sndbuf, BufSz}, 5463 {send_timeout, Timeout}, 5464 {send_timeout_close, AutoClose}]), 5465 Fun = fun(F) -> 5466 receive 5467 {From,X} when is_function(X) -> 5468 From ! {self(),X()}, F(F); 5469 die -> ok 5470 end 5471 end, 5472 ?P("[sink] start remote runner process (on ~p)", [RNode]), 5473 Pid = rpc:call(RNode, erlang, spawn, [fun() -> Fun(Fun) end]), 5474 {ok, Port} = inet:port(L), 5475 Remote = fun(Fu) -> 5476 Pid ! {self(), Fu}, 5477 receive {Pid,X} -> X 5478 end 5479 end, 5480 ?P("[sink] connect from remote node (~p)", [RNode]), 5481 {ok, C} = Remote(fun() -> 5482 ?CONNECT(Config, Host,Port, 5483 [{active, false}, 5484 {packet, 4}, 5485 {sndbuf, BufSz div 2}]) 5486 end), 5487 ?P("[sink] accept"), 5488 {ok, A} = gen_tcp:accept(L), 5489 ?P("[sink] accepted - send test message"), 5490 gen_tcp:send(A, "Hello"), 5491 ?P("[sink] message sent - " 5492 "recv 'check' message on remote node (~p)", [RNode]), 5493 {ok, "Hello"} = Remote(fun() -> gen_tcp:recv(C,0) end), 5494 ?P("[sink] cleanup - close listen socket"), 5495 (catch gen_tcp:close(L)), 5496 ?P("[sink] done with socket: " 5497 "~n ~p", [A]), 5498 {A, Pid}. 5499 5500setup_active_timeout_sink(Config, RNode, Timeout, AutoClose) -> 5501 Host = get_hostname(node()), 5502 ListenOpts = [binary, 5503 {active, false}, 5504 {packet, 0}, 5505 {nodelay, true}, 5506 {keepalive, true}, 5507 {send_timeout, Timeout}, 5508 {send_timeout_close, AutoClose}], 5509 {ok, L} = ?LISTEN(Config, 0, ListenOpts), 5510 Fun = fun(F) -> 5511 receive 5512 {From,X} when is_function(X) -> 5513 From ! {self(),X()}, 5514 F(F); 5515 die -> ok 5516 end 5517 end, 5518 Pid = rpc:call(RNode, erlang, spawn, [fun() -> Fun(Fun) end]), 5519 {ok, Port} = inet:port(L), 5520 Remote = fun(Fu) -> 5521 Pid ! {self(), Fu}, 5522 receive {Pid,X} -> X 5523 end 5524 end, 5525 {ok, C} = Remote(fun() -> 5526 ?CONNECT(Config, Host, Port, [{active,false}]) 5527 end), 5528 {ok, A} = gen_tcp:accept(L), 5529 gen_tcp:send(A, "Hello"), 5530 {ok, "H"++_} = Remote(fun() -> gen_tcp:recv(C, 0) end), 5531 {A, C}. 5532 5533%% timeout_sink_loop(Action) -> 5534%% timeout_sink_loop(Action, 1). 5535 5536timeout_sink_loop(Action, To) -> 5537 put(action, nothing), 5538 put(sent, 0), 5539 put(elapsed, 0), 5540 timeout_sink_loop(Action, To, 0). 5541 5542timeout_sink_loop(Action, To, N) -> 5543 put(action, send), 5544 Start = erlang:monotonic_time(), 5545 Ret = Action(), 5546 Stop = erlang:monotonic_time(), 5547 Elapsed = get(elapsed), 5548 put(elapsed, Elapsed + (Stop - Start)), 5549 put(action, sent), 5550 N2 = N + 1, 5551 put(sent, N2), 5552 case Ret of 5553 ok -> 5554 receive 5555 {info_and_die, SockInfo, SockTimeout} -> 5556 ?P("[sink-loop] info and die: " 5557 "~n Socket Info: ~p" 5558 "~n Send Timeout: ~p", 5559 [SockInfo(), SockTimeout()]), 5560 exit(normal) 5561 after To -> ok end, 5562 timeout_sink_loop(Action, To, N+1); 5563 {error, {timeout, RestData}} -> 5564 ?P("[sink-loop] action result: " 5565 "~n Number of actions: ~p" 5566 "~n Elapsed time: ~p msec" 5567 "~n Result: timeout with ~w of rest data", 5568 [N2, 5569 erlang:convert_time_unit(get(elapsed), native, millisecond), 5570 byte_size(RestData)]), 5571 {{error, timeout}, N2}; 5572 Other -> 5573 ?P("[sink-loop] action result: " 5574 "~n Number of actions: ~p" 5575 "~n Elapsed time: ~p msec" 5576 "~n Result: ~p", 5577 [N2, 5578 erlang:convert_time_unit(get(elapsed), native, millisecond), 5579 Other]), 5580 {Other, N2} 5581 end. 5582 5583has_superfluous_schedulers() -> 5584 case {erlang:system_info(schedulers), 5585 erlang:system_info(logical_processors)} of 5586 {S, unknown} when S > 1 -> true; 5587 {S, P} when S > P -> true; 5588 _ -> false 5589 end. 5590 5591 5592%% Leaking message from inet_drv {inet_reply,P,ok} 5593%% when a socket sending resumes working after a send_timeout. 5594%% Should we even bother testing this if 'inet_backend = socket'? 5595otp_7731(Config) when is_list(Config) -> 5596 ?TC_TRY(otp_7731, fun() -> do_otp_7731(Config) end). 5597 5598do_otp_7731(Config) when is_list(Config) -> 5599 ?P("[ctrl] create server"), 5600 ServerPid = spawn_link(?MODULE, otp_7731_server, [Config, self()]), 5601 ?P("[ctrl] await listening port (number) from server"), 5602 receive {ServerPid, ready, PortNum} -> ok end, 5603 5604 ?P("[ctrl] connect to server on port ~w", [PortNum]), 5605 {ok, Socket} = ?CONNECT(Config, "localhost", PortNum, 5606 [binary, {active, false}, {packet, raw}, 5607 {send_timeout, 1000}]), 5608 5609 ?P("[ctrl] send data"), 5610 otp_7731_send(Socket), 5611 ?P("[ctrl] sending complete - order server to recv"), 5612 ServerPid ! {self(), recv}, 5613 ?P("[ctrl] await 'recv complete' from server"), 5614 receive {ServerPid, ok} -> ?P("[ctrl] received 'recv complete'"), ok end, 5615 5616 %% Now make sure inet_drv does not leak any internal messages. 5617 ?P("[ctrl] waiting for leaking messages..."), 5618 receive Msg -> 5619 ?P("[ctrl] got unexpected message: " 5620 "~n ~p", [Msg]), 5621 ct:fail({unexpected, Msg}) 5622 after 1000 -> 5623 ok 5624 end, 5625 ?P("[ctrl] no leaking messages - cleanup"), 5626 (catch gen_tcp:close(Socket)), 5627 ServerPid ! {self(), die}, 5628 ?P("[ctrl] done."), 5629 ok. 5630 5631otp_7731_send(Socket) -> 5632 Bin = <<1:10000>>, 5633 ?P("[client] sending ~p bytes...", [byte_size(Bin)]), 5634 case gen_tcp:send(Socket, Bin) of 5635 ok -> 5636 otp_7731_send(Socket); 5637 {error, {timeout, RestData}} -> 5638 ?P("[client] send timeout with ~w bytes of rest data", 5639 [byte_size(RestData)]), 5640 ok; 5641 {error, timeout} -> 5642 ?P("[client] send timeout"), 5643 ok 5644 end. 5645 5646otp_7731_server(Config, Ctrl) -> 5647 ?P("[server] create listen socket"), 5648 {ok, LSocket} = ?LISTEN(Config, 0, [binary, {packet, raw}, 5649 {active, false}]), 5650 {ok, {_, PortNum}} = inet:sockname(LSocket), 5651 ?P("[server] listening on port number ~p", [PortNum]), 5652 Ctrl ! {self(), ready, PortNum}, 5653 5654 ?P("[server] accept"), 5655 {ok, CSocket} = gen_tcp:accept(LSocket), 5656 ?P("[server] accepted - close listen socket"), 5657 gen_tcp:close(LSocket), 5658 5659 ?P("[server] await recv order"), 5660 receive {Ctrl, recv} -> ok end, 5661 5662 ?P("[server] start receiving..."), 5663 otp_7731_recv(CSocket), 5664 5665 ?P("[server] announce recv done"), 5666 Ctrl ! {self(), ok}, 5667 5668 ?P("[server] finished, (connection) closing..."), 5669 gen_tcp:close(CSocket), 5670 receive {Ctrl, die} -> ok end, 5671 ?P("[server] done"), 5672 exit(normal). 5673 5674 5675otp_7731_recv(Socket) -> 5676 case gen_tcp:recv(Socket, 0, 1000) of 5677 {ok, Bin} -> 5678 ?P("[server] received ~p bytes", [size(Bin)]), 5679 otp_7731_recv(Socket); 5680 {error, timeout} -> 5681 ?P("[server] receive timeout - done recv"), 5682 ok 5683 end. 5684 5685 5686%% OTP-7615: TCP-ports hanging in CLOSING state when sending large 5687%% buffer followed by a recv() that returns error due to closed 5688%% connection. 5689%% OTP-7615 Leaking closed ports. 5690zombie_sockets(Config) when is_list(Config) -> 5691 register(zombie_collector,self()), 5692 Calls = 10, 5693 ?P("create zombie server"), 5694 Server = spawn_link(?MODULE, zombie_server, [Config, self(), Calls]), 5695 {Server, ready, PortNum} = receive Msg -> Msg end, 5696 ?P("Ports before = ~p",[lists:sort(erlang:ports())]), 5697 zombie_client_loop(Config, Calls, PortNum), 5698 Ports = lists:sort(zombie_collector(Calls, [])), 5699 Server ! terminate, 5700 ?P("Collected ports = ~p", [Ports]), 5701 [] = zombies_alive(Ports, 10), 5702 timer:sleep(1000), 5703 ?P("done"), 5704 ok. 5705 5706zombie_client_loop(_Config, 0, _) -> 5707 ?P("[zombie client] done"), 5708 ok; 5709zombie_client_loop(Config, N, PortNum) when is_integer(PortNum) -> 5710 ?P("[zombie client][~w] try connect", [N]), 5711 {ok, Socket} = ?CONNECT(Config, "localhost", PortNum, 5712 [binary, {active, false}, {packet, raw}]), 5713 ?P("[zombie client] connected - now close ~p", [Socket]), 5714 gen_tcp:close(Socket), % to make server recv fail 5715 zombie_client_loop(Config, N-1, PortNum). 5716 5717 5718zombie_collector(0, Acc) -> 5719 ?P("[zombie collector] done: " 5720 "~n ~p", [Acc]), 5721 Acc; 5722zombie_collector(N, Acc) -> 5723 receive 5724 {closed, Socket} -> 5725 ?P("[zombie collector] ~p closed", [Socket]), 5726 zombie_collector(N-1, [Socket|Acc]); 5727 E -> 5728 {unexpected, E, Acc} 5729 end. 5730 5731zombies_alive(Ports, WaitSec) -> 5732 Alive = lists:sort(erlang:ports()), 5733 ?P("[zombies alive][~w] Alive: ~p", [WaitSec, Alive]), 5734 Zombies = lists:filter(fun(P) -> lists:member(P, Alive) end, Ports), 5735 case Zombies of 5736 [] -> []; 5737 _ -> 5738 case WaitSec of 5739 0 -> Zombies; 5740 _ -> timer:sleep(1000), % Wait some more for zombies to die 5741 zombies_alive(Zombies, WaitSec-1) 5742 end 5743 end. 5744 5745zombie_server(Config, Pid, Calls) -> 5746 ?P("[zombie server] try create listen socket with backlog: ~w", [Calls]), 5747 {ok, LSock} = ?LISTEN(Config, 0, [binary, {packet, raw}, 5748 {active, false}, {backlog, Calls}]), 5749 {ok, {_, PortNum}} = inet:sockname(LSock), 5750 ?P("[zombie server] Listening on ~w with port number ~p", [LSock, PortNum]), 5751 BigBin = list_to_binary(lists:duplicate(100*1024, 77)), 5752 ?P("[zombie server] send ready"), 5753 Pid ! {self(), ready, PortNum}, 5754 zombie_accept_loop(LSock, BigBin, Calls), 5755 ?P("[zombie server] await terminate"), 5756 terminate = receive Msg -> Msg end, 5757 ?P("[zombie server] terminating"), 5758 ok. 5759 5760zombie_accept_loop(_, _, 0) -> 5761 ?P("[zombie server] accept loop done"), 5762 ok; 5763zombie_accept_loop(Socket, BigBin, Calls) -> 5764 ?P("[zombie server][~w] try accept", [Calls]), 5765 case gen_tcp:accept(Socket) of 5766 {ok, NewSocket} -> 5767 ?P("[zombie server][~w] accepted ~p - create handler", 5768 [Calls, NewSocket]), 5769 spawn_link(fun() -> zombie_server_handler(NewSocket, BigBin) end), 5770 zombie_accept_loop(Socket, BigBin, Calls-1); 5771 E -> 5772 E 5773 end. 5774 5775zombie_server_handler(Socket, Bin) -> 5776 ?P("[zombie server handler] got connection on ~p - attempt send", [Socket]), 5777 gen_tcp:send(Socket, Bin), 5778 ?P("[zombie server handler] Sent data, waiting for reply on ~p", [Socket]), 5779 case gen_tcp:recv(Socket, 4) of 5780 {error, closed} -> 5781 ?P("[zombie server handler] recv: closed (expected)"), 5782 ok; 5783 {error, econnaborted} -> % may be returned on Windows 5784 ?P("[zombie server handler] recv: econnaborted (expected)"), 5785 ok; 5786 {error, Reason} -> 5787 ?P("[zombie server handler] UNEXPECTED recv failure reason: ~p", 5788 [Reason]), 5789 exit({unexpected_recv_error_reason, Reason}); 5790 {ok, _} -> 5791 ?P("[zombie server handler] UNEXPECTED recv success"), 5792 exit(unexpected_recv_success) 5793 end, 5794 ?P("[zombie server handler] close socket ~p", [Socket]), 5795 gen_tcp:close(Socket), 5796 ?P("[zombie server handler] socket closed: inform collector"), 5797 zombie_collector ! {closed, Socket}. 5798 5799 5800%% Hanging send on windows when sending iolist with more than 16 binaries. 5801otp_7816(Config) when is_list(Config) -> 5802 ?TC_TRY(otp_7816, fun() -> do_otp_7816(Config) end). 5803 5804do_otp_7816(Config) -> 5805 Ctrl = self(), 5806 ?P("[ctrl] create server process..."), 5807 Server = spawn_link(fun() -> otp_7816_server(Config, Ctrl) end), 5808 ?P("[ctrl] await server process ready..."), 5809 receive {Server, ready, PortNum} -> ok end, 5810 5811 ?P("[ctrl] connect to server..."), 5812 {ok, Socket} = ?CONNECT(Config, "localhost", PortNum, 5813 [binary, {active, false}, {packet, 4}, 5814 {send_timeout, 10}]), 5815 5816 %% We use the undocumented feature that sending can be resumed after 5817 %% a send_timeout without any data loss if the peer starts to receive data. 5818 %% Unless of course the 7816-bug is in affect, in which case the write event 5819 %% for the socket is lost on windows and not all data is sent. 5820 5821 ?P("[ctrl] begin sending..."), 5822 5823 [otp_7816_ctrl(Socket, 18, BinSize, Server) || 5824 BinSize <- lists:seq(1000, 2000, 123)], 5825 5826 ?P("[ctrl] sending complete..."), 5827 5828 ok = gen_tcp:close(Socket), 5829 Server ! {self(), closed}, 5830 {Server, closed} = receive M -> M end. 5831 5832 5833otp_7816_ctrl(Socket, BinNr, BinSize, Server) -> 5834 ?P("[ctrl] create payload (BinSz: ~w)...", [BinSize]), 5835 Data = lists:duplicate(BinNr, <<1:(BinSize*8)>>), 5836 ?P("[ctrl] socket info prior to start sending: " 5837 "~n ~p", [inet:info(Socket)]), 5838 Ctrl = self(), 5839 Client = spawn_link(fun() -> otp_7816_send_data(Ctrl, Socket, Data) end), 5840 SentBytes = 5841 receive 5842 {Client, continue, Loops} -> 5843 ?P("[ctrl] received continue from client: ~p", [Loops]), 5844 SB = Loops * BinNr * BinSize, 5845 Server ! {self(), recv, SB}, 5846 SB 5847 end, 5848 ct:sleep(1000), 5849 ?P("[ctrl] socket info after sending ~w bytes: " 5850 "~n ~p", [SentBytes, inet:info(Socket)]), 5851 ?P("[ctrl] await server result..."), 5852 ok = receive 5853 {Server, SR} -> 5854 ?P("[ctrl] server result: ~p", [SR]), 5855 SR 5856 end, 5857 ?P("[ctrl] await client termination..."), 5858 ok = receive 5859 {'EXIT', Client, normal} -> 5860 ?P("[ctrl] client normal exit"), 5861 ok; 5862 {'EXIT', Client, CR} -> 5863 ?P("[ctrl] client unexpected exit reason: ~p", [CR]), 5864 CR 5865 end, 5866 ?P("[ctrl] done with BinSz: ~p", [BinSize]), 5867 ok. 5868 5869 5870otp_7816_send_data(Ctrl, Socket, Data) -> 5871 otp_7816_send_data(Ctrl, Socket, Data, 0). 5872 5873otp_7816_send_data(Ctrl, Socket, Data, Loops) -> 5874 ?P("[client] sending data (~w bytes, ~w)...", [iolist_size(Data), Loops]), 5875 case gen_tcp:send(Socket, Data) of 5876 ok -> 5877 otp_7816_send_data(Ctrl, Socket, Data, Loops+1); 5878 5879 {error, timeout} when is_port(Socket) -> 5880 %% For the 'classic' sockets, when the OS buffers are 5881 %% full, the rest data are put into the (inet driver) 5882 %% internal, for later sending. SO, it can be counted 5883 %% as sent. 5884 ?P("[client] send timeout when Loops: ~p (+1)", [Loops]), 5885 Ctrl ! {self(), continue, Loops + 1}, 5886 exit(normal); 5887 5888 {error, timeout} -> 5889 %% For inet_backend = 'socket' when we nothing of the 5890 %% message was sent. 5891 ?P("[client] send timeout when Loops: ~p", [Loops]), 5892 Ctrl ! {self(), continue, Loops}, 5893 exit(normal); 5894 5895 {error, {timeout, RestData}} -> 5896 %% A timeout means that **some** of the data was not sent, 5897 %% currently there is no way to know how much. 5898 %% NOTE THAT THIS MEANS THAT WE HAVE A PARTIAL PACKAGE 5899 %% WRITTEN, INCLUDING A HEADER THAT INDUCATES A DATA 5900 %% SIZE THAT IS **NOT** PRESENT!! 5901 %% So for this trest case to work, we need to write the rest. 5902 %% But we cannot do that without first setting the package to raw. 5903 %% 5904 ?P("[client] send timeout" 5905 "~n with ~w bytes of rest data" 5906 "~n when Loops: ~p", [byte_size(RestData), Loops]), 5907 Ctrl ! {self(), continue, Loops + 1}, 5908 ?P("[client] packet to 'raw'..."), 5909 ok = inet:setopts(Socket, [{packet, raw}, {send_timeout, 1000}]), 5910 ?P("[client] send ~w bytes of rest data...", 5911 [byte_size(RestData)]), 5912 ok = gen_tcp:send(Socket, RestData), 5913 ?P("[client] packet (back) to '4'..."), 5914 ok = inet:setopts(Socket, [{packet, 4}, {send_timeout, 10}]), 5915 ?P("[client] done"), 5916 exit(normal) 5917 5918 5919 end. 5920 5921 5922otp_7816_server(Config, Ctrl) -> 5923 ?P("[server] create listening socket"), 5924 {ok, LSocket} = ?LISTEN(Config, 0, [binary, {packet, 4}, 5925 {active, false}]), 5926 {ok, {_, PortNum}} = inet:sockname(LSocket), 5927 ?P("[server] listening on ~w with port number ~p", [LSocket, PortNum]), 5928 Ctrl ! {self(), ready, PortNum}, 5929 5930 ?P("[server] accept connection..."), 5931 {ok, ASocket} = gen_tcp:accept(LSocket), 5932 ?P("[server] got connection..."), 5933 gen_tcp:close(LSocket), 5934 5935 otp_7816_server_loop(ASocket, Ctrl), 5936 5937 ?P("[server] terminating"). 5938 5939 5940otp_7816_server_loop(Socket, Ctrl) -> 5941 ?P("[server] waiting for order..."), 5942 receive 5943 {Ctrl, recv, RecvBytes} -> 5944 ?P("[server] start receiving (~w bytes)...", [RecvBytes]), 5945 5946 ok = otp_7816_recv(Socket, RecvBytes), 5947 5948 Ctrl ! {self(), ok}, 5949 otp_7816_server_loop(Socket, Ctrl); 5950 5951 {Ctrl, closed} -> 5952 {error, closed} = gen_tcp:recv(Socket, 0, 1000), 5953 Ctrl ! {self(), closed} 5954 end. 5955 5956otp_7816_recv(Socket, BytesLeft) -> 5957 otp_7816_recv(Socket, BytesLeft, 1). 5958 5959otp_7816_recv(_, 0, _) -> 5960 ?P("[server] got all data"), 5961 ok; 5962otp_7816_recv(Socket, BytesLeft, N) -> 5963 ?P("[server] try recv ~w (~p bytes left)", [N, BytesLeft]), 5964 case gen_tcp:recv(Socket, 0, 1000) of 5965 {ok, Bin} when (byte_size(Bin) =< BytesLeft) andalso 5966 (byte_size(Bin) > 0) -> 5967 ?P("[server] received ~p of ~p bytes", 5968 [size(Bin), BytesLeft]), 5969 otp_7816_recv(Socket, BytesLeft - byte_size(Bin), N+1); 5970 {ok, Bin} -> 5971 ?P("[server] received unexpected data (~w): " 5972 "~n Expected: ~p bytes" 5973 "~n Received: ~p bytes" 5974 "~n Socket Info: ~p", 5975 [N, BytesLeft, byte_size(Bin), inet:info(Socket)]), 5976 {error, {unexpected_data, BytesLeft, byte_size(Bin)}}; 5977 {error, timeout} -> 5978 ?P("[server] got receive timeout when expecting more data:" 5979 "~n Socket Info: ~p", [inet:info(Socket)]), 5980 {error, timeout} 5981 end. 5982 5983 5984%% ---------------------------------------------------------------------- 5985 5986%% Receive a packet with a faulty packet header. 5987otp_8102(Config) when is_list(Config) -> 5988 {ok, LSocket} = ?LISTEN(Config, 0, []), 5989 {ok, {_, PortNum}} = inet:sockname(LSocket), 5990 ?P("Listening on ~w with port number ~p", [LSocket, PortNum]), 5991 5992 [otp_8102_do(Config, LSocket, PortNum, otp_8102_packet(Type,Size)) 5993 || Size <- lists:seq(-10,-1), 5994 Type <- [4, {cdr,big}, {cdr,little}]], 5995 5996 gen_tcp:close(LSocket), 5997 ok. 5998 5999otp_8102_packet(4, Size) -> 6000 {<<Size:32/big>>, 4}; 6001otp_8102_packet({cdr,big}, Size) -> 6002 {<<"GIOP",0,0,0,0,Size:32/big>>, cdr}; 6003otp_8102_packet({cdr,little}, Size) -> 6004 {<<"GIOP",0,0,1,0,Size:32/little>>, cdr}. 6005 6006otp_8102_do(Config, LSocket, PortNum, {Bin,PType}) -> 6007 6008 ?P("Connect with packet option ~p ...",[PType]), 6009 {ok, RSocket} = ?CONNECT(Config, "localhost", PortNum, [binary, 6010 {packet,PType}, 6011 {active,true}]), 6012 {ok, SSocket} = gen_tcp:accept(LSocket), 6013 6014 ?P("Got connection, sending ~p...",[Bin]), 6015 6016 ok = gen_tcp:send(SSocket, Bin), 6017 6018 ?P("Sending complete...",[]), 6019 6020 {tcp_error,RSocket,emsgsize} = receive M -> M end, 6021 6022 ?P("Got error msg, ok."), 6023 gen_tcp:close(SSocket), 6024 gen_tcp:close(RSocket). 6025 6026%% Verify packet_size handles long HTTP header lines. 6027otp_9389(Config) when is_list(Config) -> 6028 {ok, LS} = ?LISTEN(Config, 0, [{active,false}]), 6029 {ok, {_, PortNum}} = inet:sockname(LS), 6030 ?P("Listening on ~w with port number ~p", [LS, PortNum]), 6031 OrigLinkHdr = "/" ++ string:chars($S, 8192), 6032 _Server = spawn_link( 6033 fun() -> 6034 {ok, S} = gen_tcp:accept(LS), 6035 ok = inet:setopts(S, [{packet_size, 16384}]), 6036 ok = otp_9389_loop(S, OrigLinkHdr), 6037 ok = gen_tcp:close(S) 6038 end), 6039 {ok, S} = ?CONNECT(Config, "localhost", PortNum, 6040 [binary, {active, false}]), 6041 Req = "GET / HTTP/1.1\r\n" 6042 ++ "Host: localhost\r\n" 6043 ++ "Link: " ++ OrigLinkHdr ++ "\r\n\r\n", 6044 ok = gen_tcp:send(S, Req), 6045 ok = inet:setopts(S, [{packet, http}]), 6046 {ok, {http_response, {1,1}, 200, "OK"}} = gen_tcp:recv(S, 0), 6047 ok = inet:setopts(S, [{packet, httph}, {packet_size, 16384}]), 6048 {ok, {http_header, _, 'Content-Length', _, "0"}} = gen_tcp:recv(S, 0), 6049 {ok, {http_header, _, "Link", _, LinkHdr}} = gen_tcp:recv(S, 0), 6050 true = (LinkHdr == OrigLinkHdr), 6051 ok = gen_tcp:close(S), 6052 ok = gen_tcp:close(LS), 6053 ok. 6054 6055otp_9389_loop(S, OrigLinkHdr) -> 6056 ok = inet:setopts(S, [{active,once},{packet,http}]), 6057 receive 6058 {http, S, {http_request, 'GET', _, _}} -> 6059 ok = otp_9389_loop(S, OrigLinkHdr, undefined) 6060 after 6061 3000 -> 6062 error({timeout,request_line}) 6063 end. 6064otp_9389_loop(S, OrigLinkHdr, ok) -> 6065 Resp = "HTTP/1.1 200 OK\r\nContent-length: 0\r\n" ++ 6066 "Link: " ++ OrigLinkHdr ++ "\r\n\r\n", 6067 ok = gen_tcp:send(S, Resp); 6068otp_9389_loop(S, OrigLinkHdr, State) -> 6069 ok = inet:setopts(S, [{active,once}, {packet,httph}]), 6070 receive 6071 {http, S, http_eoh} -> 6072 otp_9389_loop(S, OrigLinkHdr, ok); 6073 {http, S, {http_header, _, "Link", _, LinkHdr}} -> 6074 LinkHdr = OrigLinkHdr, 6075 otp_9389_loop(S, OrigLinkHdr, State); 6076 {http, S, {http_header, _, _Hdr, _, _Val}} -> 6077 otp_9389_loop(S, OrigLinkHdr, State); 6078 {http, S, {http_error, Err}} -> 6079 error({error, Err}) 6080 after 6081 3000 -> 6082 error({timeout,header}) 6083 end. 6084 6085wrapping_oct() -> 6086 [{timetrap, {minutes,20}}]. 6087 6088%% Check that 64bit octet counters work. 6089wrapping_oct(Config) when is_list(Config) -> 6090 ?TC_TRY(wrapping_oct, fun() -> do_wrapping_oct(Config) end). 6091 6092%% {recbuf, 8192}, {sndbuf, 8192} 6093do_wrapping_oct(Config) -> 6094 ?P("[ctrl] create listen socket"), 6095 Ctrl = self(), 6096 {ok, LSock} = ?LISTEN(Config, 0, [{active,false},{mode,binary}]), 6097 {ok, LPort} = inet:port(LSock), 6098 ?P("[ctrl] spawn acceptor"), 6099 Acceptor = spawn_link(fun() -> oct_acceptor(Ctrl, LSock) end), 6100 ?P("[ctrl] spawn pump"), 6101 Pump = spawn_link(fun() -> 6102 oct_datapump(Ctrl, 6103 Config, LPort, 16#10000FFFF) 6104 end), 6105 ?P("[ctrl] await acceptor socket"), 6106 ASock = wc_await_socket("acceptor", Acceptor), 6107 ?P("[ctrl] await pump socket"), 6108 PSock = wc_await_socket("pump", Pump), 6109 ?P("[ctrl] await completion (from pump)"), 6110 Res = wc_await_completion(Acceptor, ASock, Pump, PSock), 6111 ?P("[ctrl] close listen socket"), 6112 gen_tcp:close(LSock), 6113 ?P("[ctrl] verify result"), 6114 ok = Res, 6115 ?P("[ctrl] done"), 6116 ok. 6117 6118wc_await_socket(Tag, Pid) -> 6119 receive 6120 {Pid, socket, AS} -> 6121 ?P("received ~s socket: " 6122 "~n ~p", [Tag, AS]), 6123 AS 6124 end. 6125 6126wc_await_completion(Acceptor, ASock, Pump, PSock) -> 6127 wc_await_completion(Acceptor, ASock, Pump, PSock, 1, undefined). 6128 6129wc_await_completion(undefined = _Acceptor, _ASock, 6130 undefined = _Pump, _PSock, 6131 Loops, Res) -> 6132 ?P("completed after ~w loops", [Loops]), 6133 Res; 6134wc_await_completion(Acceptor, ASock, Pump, PSock, Loops, CRes) -> 6135 receive 6136 {'EXIT', Pump, Res} -> 6137 ?P("[ctrl] Received pump exit: " 6138 "~n Loops: ~w" 6139 "~n Reason: ~p", [Loops, Res]), 6140 wc_await_completion(Acceptor, ASock, 6141 undefined, PSock, 6142 Loops + 1, Res); 6143 {'EXIT', Acceptor, Res} -> 6144 ?P("[ctrl] Received acceptor exit: " 6145 "~n Loops: ~w" 6146 "~n Reason: ~p", [Loops, Res]), 6147 wc_await_completion(undefined, ASock, 6148 Pump, PSock, 6149 Loops + 1, CRes) 6150 6151 after 10000 -> 6152 ASockInfo = wc_sock_info(ASock), 6153 AccInfo = wc_proc_info(Acceptor), 6154 PSockInfo = wc_sock_info(PSock), 6155 PumpInfo = wc_proc_info(Pump), 6156 ?P("Info ~w while waiting for clompletion: " 6157 "~n Acceptor Socket Info: ~p" 6158 "~n Acceptor Info: ~p" 6159 "~n Pump Socket Info: ~p" 6160 "~n Pump Info: ~p", 6161 [Loops, ASockInfo, AccInfo, PSockInfo, PumpInfo]), 6162 wc_await_completion(Acceptor, ASock, 6163 Pump, PSock, 6164 Loops + 1, CRes) 6165 end. 6166 6167wc_sock_info(S) -> 6168 try inet:info(S) 6169 catch 6170 _:_:_ -> 6171 undefined 6172 end. 6173 6174wc_proc_info(P) when is_pid(P) -> 6175 try erlang:process_info(P) 6176 catch 6177 _:_:_ -> 6178 undefined 6179 end; 6180wc_proc_info(_) -> 6181 undefined. 6182 6183%% {recbuf, 16*1024}, {sndbuf, 16*1024} 6184oct_datapump(Ctrl, Config, Port, N) -> 6185 ?P("[pump] connect to listener"), 6186 {ok, CSock} = ?CONNECT(Config, "localhost", Port, 6187 [{active, false}, {mode, binary}]), 6188 ?P("[pump] announce to ctrl"), 6189 Ctrl ! {self(), socket, CSock}, 6190 {ok, [{sndbuf,SndBuf}]} = inet:getopts(CSock, [sndbuf]), 6191 ?P("[pump] connected - start 'pumping' with" 6192 "~n SndBuf: ~w", [SndBuf]), 6193 put(action, nothing), 6194 put(sent, 0), 6195 put(elapsed, 0), 6196 put(rem_bytes, N), 6197 oct_pump(CSock, N, binary:copy(<<$a:8>>,100000), 0, 0). 6198 6199oct_pump(S, N, _, _, _Sent) when N =< 0 -> 6200 ?P("[pump] done"), 6201 (catch gen_tcp:close(S)), 6202 exit(ok); 6203oct_pump(S, N, Bin, Last, Sent) -> 6204 put(action, send), 6205 Start = erlang:monotonic_time(nanosecond), 6206 Res = gen_tcp:send(S, Bin), 6207 Stop = erlang:monotonic_time(nanosecond), 6208 Elapsed = get(elapsed), 6209 put(elapsed, Elapsed + (Stop - Start)), 6210 put(action, sent), 6211 put(sent, Sent+1), 6212 case Res of 6213 ok -> 6214 case inet:getstat(S) of 6215 {ok, Stat} -> 6216 {_, R} = lists:keyfind(send_oct, 1, Stat), 6217 case (R < Last) of 6218 true -> 6219 ?P("[pump] send counter error ~p < ~p", [R, Last]), 6220 (catch gen_tcp:close(S)), 6221 exit({error, {output_counter, R, Last, N}}); 6222 false -> 6223 put(rem_bytes, N - byte_size(Bin)), 6224 oct_pump(S, N-byte_size(Bin), Bin, R, Sent+1) 6225 end; 6226 {error, StatReason} -> 6227 ?P("[pump] get stat failed:" 6228 "~n Reason: ~p" 6229 "~n when" 6230 "~n Remaining: ~p" 6231 "~n Last: ~p", [StatReason, N, Last]), 6232 (catch gen_tcp:close(S)), 6233 exit({error, {stat_failure, StatReason, N, Last}}) 6234 end; 6235 {error, SendReason} -> 6236 ?P("[pump] send failed:" 6237 "~n Reason: ~p" 6238 "~n when" 6239 "~n Remaining: ~p" 6240 "~n Last: ~p", [SendReason, N, Last]), 6241 (catch gen_tcp:close(S)), 6242 exit({error, {send_failure, SendReason, N, Last}}) 6243 end. 6244 6245 6246oct_acceptor(Ctrl, LSock) -> 6247 ?P("[acceptor] accept connection"), 6248 {ok, ASock} = gen_tcp:accept(LSock), 6249 ?P("[acceptor] announce to ctrl"), 6250 Ctrl ! {self(), socket, ASock}, 6251 {ok, [{recbuf,RecBuf}]} = inet:getopts(ASock, [recbuf]), 6252 ?P("[acceptor] connection accepted - start receiving with: " 6253 "~n RecBuf: ~w", [RecBuf]), 6254 put(action, nothing), 6255 put(recv, 0), 6256 put(elapsed, 0), 6257 oct_aloop(ASock, inet:info(ASock), 0, 0). 6258 6259oct_aloop(S, LastInfo, Received, Times) -> 6260 put(action, recv), 6261 Start = erlang:monotonic_time(), 6262 Res = gen_tcp:recv(S, 0), 6263 Stop = erlang:monotonic_time(), 6264 Elapsed = get(elapsed), 6265 put(elapsed, Elapsed + (Stop - Start)), 6266 put(action, received), 6267 put(recv, Times+1), 6268 case Res of 6269 {ok, _} -> 6270 #{counters := #{recv_oct := R} = _Stat} = Info = inet:info(S), 6271 case (R < Received) of 6272 true -> 6273 ?P("[acceptor] recv counter error:" 6274 "~n Recv Cnt: ~p" 6275 "~n Received: ~p" 6276 "~n Times: ~p" 6277 "~n Info: ~p" 6278 "~n Last Info: ~p", 6279 [R, Received, Times, Info, LastInfo]), 6280 (catch gen_tcp:close(S)), 6281 {error, {output_counter, R, Received, Times}}; 6282 false -> 6283 case Times rem 16#FFFFF of 6284 0 -> 6285 ?P("[acceptor] read: ~p" 6286 "~n Times: ~w" 6287 "~n Info: ~p", 6288 [R, Times, Info]); 6289 _ -> 6290 ok 6291 end, 6292 oct_aloop(S, Info, R, Times+1) 6293 end; 6294 6295 {error, RecvReason} -> 6296 ?P("[acceptor] receive failed:" 6297 "~n Reason: ~p" 6298 "~n when" 6299 "~n Received: ~p" 6300 "~n Times: ~p", [RecvReason, Received, Times]), 6301 (catch gen_tcp:close(S)), 6302 ct:sleep(1000), % Just give the 'pump' a chance to get there first 6303 exit(closed) 6304 end. 6305 6306ok({ok,V}) -> V. 6307 6308get_hostname(Name) -> 6309 "@"++Host = lists:dropwhile(fun(C) -> C =/= $@ end, atom_to_list(Name)), 6310 Host. 6311 6312otp_13939(doc) -> 6313 ["Check that writing to a remotely closed socket doesn't block forever " 6314 "when exit_on_close is false."]; 6315otp_13939(suite) -> 6316 []; 6317otp_13939(Config) when is_list(Config) -> 6318 {Pid, Ref} = spawn_opt( 6319 fun() -> 6320 {ok, Listener} = ?LISTEN(Config, 0, [{exit_on_close, false}]), 6321 {ok, Port} = inet:port(Listener), 6322 6323 spawn_link( 6324 fun() -> 6325 {ok, Client} = ?CONNECT(Config, "localhost", Port, 6326 [{active, false}]), 6327 ok = gen_tcp:close(Client) 6328 end), 6329 6330 {ok, Accepted} = gen_tcp:accept(Listener), 6331 6332 ok = gen_tcp:send(Accepted, <<0:(10*1024*1024*8)>>), 6333 6334 %% The bug surfaces when there's a delay between the send 6335 %% operations; inet:getstat is a red herring. 6336 timer:sleep(100), 6337 6338 {error, Code} = gen_tcp:send(Accepted, <<0:(10*1024*1024*8)>>), 6339 ct:pal("gen_tcp:send returned ~p~n", [Code]) 6340 end, [link, monitor]), 6341 6342 receive 6343 {'DOWN', Ref, process, Pid, normal} -> 6344 ok 6345 after 1000 -> 6346 demonitor(Ref, [flush]), 6347 exit(Pid, normal), 6348 ct:fail("Server process blocked on send.") 6349 end. 6350 6351 6352%% No point in running this as the test case with inet_backend = socket 6353%% as it tests a bug in the inet driver that cannot reproduced with 6354%% inet_backend = socket. 6355otp_12242(Config) when is_list(Config) -> 6356 Cond = fun() -> 6357 case os:type() of 6358 {win32,_} -> 6359 %% Even if we set sndbuf and recbuf to small sizes 6360 %% Windows either happily accepts to send GBytes of 6361 %% data in no time, so the second send below that 6362 %% is supposed to time out just succedes, or the 6363 %% first send that is supposed to fill the inet_drv 6364 %% I/O queue and start waiting for when more data 6365 %% can be sent instead sends all data but suffers 6366 %% a send failure that closes the socket. 6367 {skip, backpressure_broken_on_win32}; 6368 _ -> 6369 case ?IS_SOCKET_BACKEND(Config) of 6370 true -> 6371 {skip, "Not complient with socket"}; 6372 false -> 6373 ok 6374 end 6375 end 6376 end, 6377 TC = fun() -> do_otp_12242(Config) end, 6378 ?TC_TRY(otp_12242, Cond, TC). 6379 6380do_otp_12242(Config) when is_list(Config) -> 6381 %% Find the IPv4 address of an up and running interface 6382 %% that is not loopback nor pointtopoint 6383 {ok, IFList} = inet:getifaddrs(), 6384 ?P("IFList " 6385 "~n ~p", [IFList]), 6386 case 6387 lists:flatten( 6388 [lists:filtermap( 6389 fun ({addr, Addr}) when (tuple_size(Addr) =:= 4) -> 6390 {true, Addr}; 6391 (_) -> 6392 false 6393 end, Opts) 6394 || {_,Opts} <- IFList, 6395 case lists:keyfind(flags, 1, Opts) of 6396 {_,Flags} -> 6397 lists:member(up, Flags) 6398 andalso 6399 lists:member(running, Flags) 6400 andalso 6401 not lists:member(loopback, Flags) 6402 andalso 6403 not lists:member(pointtopoint, Flags); 6404 false -> 6405 false 6406 end]) 6407 of 6408 [Addr|_] -> 6409 otp_12242(Config, Addr); 6410 Other -> 6411 ?SKIPT({no_external_address, Other}) 6412 end. 6413 6414%% 6415otp_12242(Config, Addr) when (tuple_size(Addr) =:= 4) -> 6416 ct:timetrap(30000), 6417 ?P("Using address ~p", [Addr]), 6418 Bufsize = 16 * 1024, 6419 Datasize = 128 * 1024 * 1024, % At least 1 s on GBit interface 6420 Blob = binary:copy(<<$x>>, Datasize), 6421 LOpts = 6422 [{backlog, 4}, 6423 {reuseaddr, true}, 6424 {ip, Addr}, 6425 binary, 6426 {active, false}, 6427 {recbuf, Bufsize}, 6428 {sndbuf, Bufsize}, 6429 {buffer, Bufsize}], 6430 COpts = 6431 [binary, 6432 {active, false}, 6433 {ip, Addr}, 6434 {linger, {true, 1}}, % 1 s 6435 {send_timeout, 500}, 6436 {recbuf, Bufsize}, 6437 {sndbuf, Bufsize}, 6438 {buffer, Bufsize}], 6439 Dir = filename:dirname(code:which(?MODULE)), 6440 {ok, ListenerNode} = ?START_SLAVE_NODE(?UNIQ_NODE_NAME, "-pa " ++ Dir), 6441 Tester = self(), 6442 ?P("create listener"), 6443 {Listener, ListenerMRef} = 6444 spawn_opt( 6445 ListenerNode, 6446 fun () -> 6447 ?P("create listen socket"), 6448 {ok,L} = ?LISTEN(Config, 0, LOpts), 6449 {ok,LPort} = inet:port(L), 6450 ?P("inform tester about port number: ~w", [LPort]), 6451 Tester ! {self(), port, LPort}, 6452 ?P("try accept"), 6453 {ok, A} = gen_tcp:accept(L), 6454 ?P("accepted - close listen socket"), 6455 ok = gen_tcp:close(L), 6456 ?P("await close order"), 6457 receive 6458 {Tester, stop} -> 6459 ?P("close order received - close accepted socket"), 6460 ok = gen_tcp:close(A) 6461 end 6462 end, [link, monitor]), 6463 ?P("await listen port"), 6464 LPort = receive {Listener,port,P} -> P end, 6465 ?P("try connect to ~w", [LPort]), 6466 {ok,C} = ?CONNECT(Config, Addr, LPort, COpts, infinity), 6467 ?P("connected - get buffers"), 6468 {ok, ReadCOpts} = inet:getopts(C, [recbuf,sndbuf,buffer]), 6469 ?P("connected sockets buffers:" 6470 "~n ~p", [ReadCOpts]), 6471 6472 otp_12242_2(C, Blob, Datasize), 6473 6474 ?P("send listener stop"), 6475 Listener ! {Tester, stop}, 6476 ?P("await listener termination"), 6477 wait(ListenerMRef), 6478 ?P("stop listener node"), 6479 ?STOP_NODE(ListenerNode), 6480 ?P("done"), 6481 ok. 6482 6483 6484otp_12242_2(C, Blob, Datasize) -> 6485 %% Fill the buffers 6486 ?P("sending ~p bytes", [Datasize]), 6487 case gen_tcp:send(C, Blob) of 6488 ok -> 6489 ?P("sent ~p bytes", [Datasize]), 6490 otp_12242_3(C, Blob, Datasize); 6491 {error, {timeout, _RestData}} -> 6492 %% We filled the buffers and timed out; 6493 %% this is probably the socket backend - give up. 6494 ok; 6495 {error, timeout} -> 6496 %% The same as the previous clause 6497 ok 6498 end, 6499 _ = gen_tcp:close(C), 6500 ok. 6501 6502otp_12242_3(C, Blob, Datasize) -> 6503 %% Try to ensure that the close call is in progress 6504 %% before the owner proceeds with sending 6505 CloserMRef = otp_12242_closer(C), 6506 6507 ?P("await tref"), 6508 receive 6509 {tref,Tref} -> 6510 ?P("tref received - now await trigger timeout"), 6511 receive {timeout,Tref,_} -> ok end, 6512 ?P("trigger timeout received - try send ~p bytes again", 6513 [Datasize]), 6514 %% Now should the close be in progress... 6515 %% All buffers are full, remote end is not reading, 6516 %% and the send timeout is 1 s so this will timeout: 6517 {error, timeout} = gen_tcp:send(C, Blob), 6518 ?P("expected timeout - update send_timeout (to 10000)"), 6519 ok = inet:setopts(C, [{send_timeout, 10000}]), 6520 %% There is a hidden timeout here. Port close is sampled 6521 %% every 5 s by prim_inet:send_recv_reply. 6522 %% Linger is 3 s so the Closer will finish this send: 6523 ?P("try send ~p bytes - expect error (closed)", [Datasize]), 6524 {error, closed} = gen_tcp:send(C, Blob), 6525 ?P("await closer termination"), 6526 normal = wait(CloserMRef), 6527 ok 6528 end. 6529 6530otp_12242_closer(C) -> 6531 Owner = self(), 6532 {_Closer, CloserMref} = 6533 spawn_opt( 6534 fun () -> 6535 ?P("[closer] starting"), 6536 Owner ! {tref, erlang:start_timer(50, Owner, closing)}, 6537 ?P("[closer] calling gen_tcp:close(C)"), 6538 try gen_tcp:close(C) of 6539 Result -> 6540 ?P("[closer] gen_tcp:close(C) -> ~p", [Result]), 6541 ok = Result 6542 catch 6543 Class:Reason:Stacktrace -> 6544 ?P("[closer] catched gen_tcp:close(C):" 6545 "~n Error Class: ~p" 6546 "~n Error: ~p" 6547 "~n Stack trace: ~p", 6548 [Class, Reason, Stacktrace]), 6549 erlang:raise(Class, Reason, Stacktrace) 6550 end 6551 end, [link, monitor]), 6552 CloserMref. 6553 6554 6555wait(Mref) -> 6556 receive {'DOWN',Mref,_,_,Reason} -> Reason end. 6557 6558%% OTP-15536 6559%% Test that send error works correctly for delay_send 6560delay_send_error(Config) -> 6561 ?P("create listen socket"), 6562 {ok, L} = 6563 ?LISTEN(Config, 6564 0, [{reuseaddr, true}, {packet, 1}, {active, false}]), 6565 {ok,{{0,0,0,0},PortNum}}=inet:sockname(L), 6566 6567 delay_send_error(Config, L, PortNum, false), 6568 delay_send_error(Config, L, PortNum, true). 6569delay_send_error(Config, L, PortNum, Active) -> 6570 ?P("try connect - with delay_send:true active:~p",[Active]), 6571 {ok, C} = 6572 ?CONNECT(Config, 6573 "localhost", PortNum, 6574 [{packet, 1}, {active, Active}, {delay_send, true}]), 6575 ?P("try accept"), 6576 {ok, S} = gen_tcp:accept(L), 6577 %% Do a couple of sends first to see that it works 6578 ?P("send data"), 6579 ok = gen_tcp:send(C, "hello"), 6580 ?P("send data"), 6581 ok = gen_tcp:send(C, "hello"), 6582 ?P("send data"), 6583 ok = gen_tcp:send(C, "hello"), 6584 %% Close the receiver 6585 ?P("close receiver (accepted socket)"), 6586 ok = gen_tcp:shutdown(C, write), 6587 %% 6588 ?P("send data"), 6589 case gen_tcp:send(C, "hello") of 6590 ok -> 6591 ?P("send data"), 6592 case gen_tcp:send(C, "hello") of 6593 ok -> 6594 delay_send_error2(C); 6595 {error, closed} -> 6596 ?P("closed (expected)"), 6597 ok 6598 end; 6599 {error, closed} -> 6600 ?P("closed (expected)"), 6601 ok 6602 end, 6603 ok = gen_tcp:close(C). 6604 6605 6606delay_send_error2(Sock) -> 6607 delay_send_error2(Sock, 3). 6608 6609delay_send_error2(Sock, 0) -> 6610 gen_tcp:close(Sock), 6611 ct:fail("Unxpected send success"); 6612delay_send_error2(Sock, N) -> 6613 %% Sleep in order for delay_send to have time to trigger 6614 %% This used to result in a double free 6615 timer:sleep(1000), 6616 case gen_tcp:send(Sock, "hello") of 6617 ok -> 6618 delay_send_error2(Sock, N-1); 6619 {error, closed} -> 6620 ?P("closed (expected, ~w)", [N]), 6621 ok; 6622 {error, Reason} -> 6623 ct:fail(?F("Unexpected send error: ~p", [Reason])) 6624 end. 6625 6626 6627 6628 6629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6630 6631 6632-define(ACTIVE_N, 20). 6633 6634%% 30-second test for gen_tcp in {active, N} mode, 6635%% ensuring it does not get stuck. 6636%% Verifies that erl_check_io properly handles extra EPOLLIN signals. 6637bidirectional_traffic(Config) when is_list(Config) -> 6638 ?TC_TRY(bidirectional_traffic, 6639 fun() -> do_bidirectional_traffic(Config) end). 6640 6641do_bidirectional_traffic(Config) -> 6642 ?P("begin"), 6643 Workers = erlang:system_info(schedulers_online) * 2, 6644 ?P("Use ~w workers", [Workers]), 6645 Payload = crypto:strong_rand_bytes(32), 6646 {ok, LSock} = ?LISTEN(Config, 6647 0, 6648 [binary, 6649 {packet, 0}, 6650 {active, false}, 6651 {reuseaddr, true}]), 6652 %% get all sockets to know failing ends 6653 ?P("listen socket created: " 6654 "~n ~p", [LSock]), 6655 {ok, Port} = inet:port(LSock), 6656 ?P("listen socket port number ~w", [Port]), 6657 Control = self(), 6658 ?P("create ~w receivers", [Workers]), 6659 Receivers = [spawn_link(fun () -> 6660 exchange(Config, LSock, Port, Payload, Control) 6661 end) || _ <- lists:seq(1, Workers)], 6662 ?P("await the result"), 6663 Result = 6664 %% If any of the receivers report, we have an error 6665 receive 6666 {timeout, Socket, Total} -> 6667 ?P("timeout msg for ~p: ~w", [Socket, Total]), 6668 {fail, {timeout, Socket, Total}}; 6669 {error, Socket, Reason} -> 6670 ?P("error msg for ~p: ~p", [Socket, Reason]), 6671 {fail, {error, Socket, Reason}} 6672 after 30000 -> 6673 %% if it does not fail in 30 seconds, it most likely works 6674 ?P("timeout => success"), 6675 ok 6676 end, 6677 ?P("ensure all receivers terminated"), 6678 [begin unlink(Rec), exit(Rec, kill) end || Rec <- Receivers], 6679 ?P("close listen socket"), 6680 (catch gen_tcp:close(LSock)), 6681 ?P("done"), 6682 Result. 6683 6684 6685exchange(Config, LSock, Port, Payload, Control) -> 6686 %% spin up client 6687 _ClntRcv = spawn_link( 6688 fun () -> 6689 ?P("connect"), 6690 {ok, Client} = 6691 ?CONNECT(Config, 6692 "localhost", 6693 Port, 6694 [binary, {packet, 0}, {active, ?ACTIVE_N}]), 6695 ?P("connected: ~p", [Client]), 6696 send_recv_loop(Client, Payload, Control) 6697 end), 6698 ?P("accept"), 6699 {ok, Socket} = gen_tcp:accept(LSock), 6700 ?P("accepted: ~p", [Socket]), 6701 %% sending process 6702 send_recv_loop(Socket, Payload, Control). 6703 6704send_recv_loop(Socket, Payload, Control) -> 6705 %% {active, N} must be set to active > 12 to trigger the issue 6706 %% {active, 30} seems to trigger it quite often & reliably 6707 ?P("set (initial) active: ~p", [?ACTIVE_N]), 6708 inet:setopts(Socket, [{active, ?ACTIVE_N}]), 6709 ?P("spawn sender"), 6710 _Snd = spawn_link( 6711 fun Sender() -> 6712 case gen_tcp:send(Socket, Payload) of 6713 ok -> 6714 Sender(); 6715 {error, Reason} -> 6716 ?P("Send failed: " 6717 "~n ~p", [Reason]), 6718 exit({send_failed, Reason}) 6719 end 6720 end), 6721 ?P("begin recv"), 6722 recv(Socket, 0, Control). 6723 6724recv(Socket, Total, Control) -> 6725 receive 6726 {tcp, Socket, Data} -> 6727 recv(Socket, Total + byte_size(Data), Control); 6728 {tcp_passive, Socket} -> 6729 inet:setopts(Socket, [{active, ?ACTIVE_N}]), 6730 recv(Socket, Total, Control); 6731 {tcp_closed, Socket} -> 6732 ?P("[recv] closed when total received: ~w" 6733 "~n Socket Info: ~p", 6734 [Total, (catch inet:info(Socket))]), 6735 ok; 6736 Other -> 6737 ?P("[recv] received unexpected when total received: ~w" 6738 "~n ~p" 6739 "~n Socket: ~p" 6740 "~n Socket Info: ~p", 6741 [Total, Other, Socket, (catch inet:info(Socket))]), 6742 Control ! {error, Socket, Other} 6743 after 2000 -> 6744 %% no data received in 2 seconds => test failed 6745 ?P("[recv] received nothing when total received: ~w" 6746 "~n Socket: ~p" 6747 "~n Socket Info: ~p", 6748 [Total, Socket, (catch inet:info(Socket))]), 6749 Control ! {timeout, Socket, Total} 6750 end. 6751 6752 6753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6754 6755%% This is the most basic of tests. 6756%% We create a listen socket, then spawns processes that create 6757%% monitors to it... 6758socket_monitor1(Config) when is_list(Config) -> 6759 ct:timetrap(?MINS(1)), 6760 ?TC_TRY(socket_monitor1, 6761 fun() -> do_socket_monitor1(Config) end). 6762 6763do_socket_monitor1(Config) -> 6764 ?P("begin"), 6765 Self = self(), 6766 Type = ?SOCKET_TYPE(Config), 6767 {ok, LSock1} = ?LISTEN(Config), 6768 F = fun(S, Fun) -> spawn_monitor(fun() -> Fun(S, Self) end) end, 6769 F1 = fun(Socket, Parent) when is_pid(Parent) -> 6770 ?P("[client] create monitor"), 6771 MRef = inet:monitor(Socket), 6772 Parent ! {self(), ready}, 6773 sm_await_socket_down(MRef, Socket, Type) 6774 end, 6775 ?P("spawn client"), 6776 {Pid1, Mon1} = F(LSock1, F1), 6777 ?P("await client ready"), 6778 sm_await_client_ready(Pid1), 6779 ?P("close socket"), 6780 gen_tcp:close(LSock1), 6781 ?P("await client termination"), 6782 sm_await_down(Pid1, Mon1, ok), 6783 ?P("done"), 6784 ok. 6785 6786sm_await_socket_down(ExpMon, ExpSock, ExpType) -> 6787 sm_await_socket_down(ExpMon, ExpSock, ExpType, "client"). 6788 6789sm_await_socket_down(ExpMon, ExpSock, ExpType, Name) -> 6790 receive 6791 {'DOWN', Mon, Type, Sock, Info} when (Type =:= ExpType) andalso 6792 (Mon =:= ExpMon) andalso 6793 (Sock =:= ExpSock) -> 6794 ?P("[~s] received expected (socket) down message: " 6795 "~n Mon: ~p" 6796 "~n Type: ~p" 6797 "~n Sock: ~p" 6798 "~n Info: ~p", [Name, Mon, Type, Sock, Info]), 6799 exit(ok); 6800 6801 Any -> 6802 ?P("[~s] received unexpected message: " 6803 "~n ~p", [Name, Any]), 6804 exit({unexpected_message, Any}) 6805 end. 6806 6807sm_await_client_ready(Pid) -> 6808 sm_await_client_ready(Pid, "client"). 6809 6810sm_await_client_ready(Pid, Name) -> 6811 receive 6812 {Pid, ready} -> 6813 ?P("received ~s ready", [Name]) 6814 end. 6815 6816sm_await_down(Pid, Mon, ExpRes) -> 6817 receive 6818 {'DOWN', Mon, process, Pid, ExpRes} -> 6819 ?P("received expected process down message from ~p", [Pid]), 6820 ok; 6821 {'DOWN', Mon, process, Pid, UnexpRes} -> 6822 ?P("received unexpected process down message from ~p: " 6823 "~n ~p", [Pid, UnexpRes]), 6824 ct:fail({unexpected_down, UnexpRes}) 6825 end. 6826 6827 6828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6829 6830%% This is the most basic of tests. 6831%% We create "many" listen socket(s), then spawns processes that create 6832%% monitors to them... 6833socket_monitor1_manys(Config) when is_list(Config) -> 6834 ct:timetrap(?MINS(1)), 6835 ?TC_TRY(socket_monitor1_manys, 6836 fun() -> do_socket_monitor1_manys(Config) end). 6837 6838do_socket_monitor1_manys(Config) -> 6839 ?P("begin"), 6840 Self = self(), 6841 Type = ?SOCKET_TYPE(Config), 6842 ?P("[client] create socket(s)"), 6843 {ok, LSock1} = ?LISTEN(Config), 6844 {ok, LSock2} = ?LISTEN(Config), 6845 {ok, LSock3} = ?LISTEN(Config), 6846 {ok, LSock4} = ?LISTEN(Config), 6847 {ok, LSock5} = ?LISTEN(Config), 6848 F = fun(S, Fun) -> spawn_monitor(fun() -> Fun(S, Self) end) end, 6849 F1 = fun(Sockets, Parent) when is_list(Sockets) andalso is_pid(Parent) -> 6850 ?P("[client] create monitor(s)"), 6851 Monitors = [{inet:monitor(Socket), Socket} || 6852 Socket <- Sockets], 6853 Parent ! {self(), ready}, 6854 sm_await_socket_down2(Monitors, Type) 6855 end, 6856 ?P("spawn client"), 6857 {Pid1, Mon1} = F([LSock1, LSock2, LSock3, LSock4, LSock5], F1), 6858 ?P("await client ready"), 6859 sm_await_client_ready(Pid1), 6860 ?P("close socket(s)"), 6861 gen_tcp:close(LSock1), 6862 gen_tcp:close(LSock2), 6863 gen_tcp:close(LSock3), 6864 gen_tcp:close(LSock4), 6865 gen_tcp:close(LSock5), 6866 ?P("await client termination"), 6867 sm_await_down(Pid1, Mon1, ok), 6868 ?P("done"), 6869 ok. 6870 6871 6872sm_await_socket_down2(Monitors, ExpType) -> 6873 sm_await_socket_down2(Monitors, ExpType, "client"). 6874 6875sm_await_socket_down2([], _ExpType, Name) -> 6876 ?P("[~s] all sockets down", [Name]), 6877 exit(ok); 6878sm_await_socket_down2(Mons, ExpType, Name) when is_list(Mons) -> 6879 ?P("[~s] await socket down", [Name]), 6880 receive 6881 {'DOWN', Mon, Type, Sock, Info} when (Type =:= ExpType) -> 6882 ?P("[~s] received expected (socket) down message: " 6883 "~n Mon: ~p" 6884 "~n Type: ~p" 6885 "~n Sock: ~p" 6886 "~n Info: ~p", [Name, Mon, Type, Sock, Info]), 6887 case lists:keysearch(Mon, 1, Mons) of 6888 {value, {Mon, Sock}} -> 6889 Mons2 = lists:keydelete(Mon, 1, Mons), 6890 sm_await_socket_down2(Mons2, ExpType, Name); 6891 {value, Value} -> 6892 ?P("[~s] Unexpected socket down: " 6893 "~n Value: ~p", [Name, Value]), 6894 ct:fail({unexpected_monitor, Mon, Value}); 6895 false -> 6896 ct:fail({unknown_monitor, Mon}) 6897 end 6898 end. 6899 6900 6901 6902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6903 6904%% This is the most basic of tests. 6905%% We create a listen socket, then spawn client process(es) that create 6906%% monitors to it... 6907socket_monitor1_manyc(Config) when is_list(Config) -> 6908 ct:timetrap(?MINS(1)), 6909 ?TC_TRY(socket_monitor1_manyc, 6910 fun() -> do_socket_monitor1_manyc(Config) end). 6911 6912do_socket_monitor1_manyc(Config) -> 6913 ?P("begin"), 6914 Self = self(), 6915 Type = ?SOCKET_TYPE(Config), 6916 {ok, LSock1} = ?LISTEN(Config), 6917 F = fun(S, Fun, Name) -> 6918 spawn_monitor(fun() -> Fun(S, Name, Self) end) 6919 end, 6920 F1 = fun(Socket, Name, Parent) when is_list(Name) andalso is_pid(Parent) -> 6921 ?P("[~s] monitor socket", [Name]), 6922 MRef = inet:monitor(Socket), 6923 Parent ! {self(), ready}, 6924 sm_await_socket_down(MRef, Socket, Type) 6925 end, 6926 ?P("spawn client(s)"), 6927 {Pid1, Mon1} = F(LSock1, F1, "client1"), 6928 {Pid2, Mon2} = F(LSock1, F1, "client2"), 6929 {Pid3, Mon3} = F(LSock1, F1, "client3"), 6930 {Pid4, Mon4} = F(LSock1, F1, "client4"), 6931 {Pid5, Mon5} = F(LSock1, F1, "client5"), 6932 ?P("await client(s) ready"), 6933 sm_await_client_ready(Pid1, "client1"), 6934 sm_await_client_ready(Pid2, "client2"), 6935 sm_await_client_ready(Pid3, "client3"), 6936 sm_await_client_ready(Pid4, "client4"), 6937 sm_await_client_ready(Pid5, "client5"), 6938 ?P("close socket"), 6939 gen_tcp:close(LSock1), 6940 ?P("await client(s) termination"), 6941 sm_await_down(Pid1, Mon1, ok), 6942 sm_await_down(Pid2, Mon2, ok), 6943 sm_await_down(Pid3, Mon3, ok), 6944 sm_await_down(Pid4, Mon4, ok), 6945 sm_await_down(Pid5, Mon5, ok), 6946 ?P("done"), 6947 ok. 6948 6949 6950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6951 6952%% This is the most basic of tests. 6953%% We create a listen socket, then spawns processes that create 6954%% monitors to it... 6955socket_monitor1_demon_after(Config) when is_list(Config) -> 6956 ct:timetrap(?MINS(1)), 6957 ?TC_TRY(socket_monitor1_demon_after, 6958 fun() -> do_socket_monitor1_demon_after(Config) end). 6959 6960do_socket_monitor1_demon_after(Config) -> 6961 ?P("begin"), 6962 Self = self(), 6963 Type = ?SOCKET_TYPE(Config), 6964 {ok, LSock1} = ?LISTEN(Config), 6965 F = fun(S, Fun) -> spawn_monitor(fun() -> Fun(S, Self) end) end, 6966 F1 = fun(Socket, Parent) when is_pid(Parent) -> 6967 ?P("[client] create monitor"), 6968 MRef = inet:monitor(Socket), 6969 ?P("[client] sleep some"), 6970 ?SLEEP(?SECS(1)), 6971 ?P("[client] cancel (socket) monitor"), 6972 inet:cancel_monitor(MRef), 6973 ?P("[client] announce ready"), 6974 Parent ! {self(), ready}, 6975 sm_await_no_socket_down(MRef, Socket, Type) 6976 end, 6977 ?P("spawn client"), 6978 {Pid1, Mon1} = F(LSock1, F1), 6979 ?P("await client ready"), 6980 sm_await_client_ready(Pid1), 6981 ?P("close socket"), 6982 gen_tcp:close(LSock1), 6983 ?P("await client termination"), 6984 sm_await_down(Pid1, Mon1, ok), 6985 ?P("done"), 6986 ok. 6987 6988 6989sm_await_no_socket_down(ExpMon, ExpSock, ExpType) -> 6990 sm_await_no_socket_down(ExpMon, ExpSock, ExpType, "client"). 6991 6992sm_await_no_socket_down(ExpMon, ExpSock, ExpType, Name) -> 6993 receive 6994 {'DOWN', Mon, Type, Sock, Info} when (Type =:= ExpType) andalso 6995 (Mon =:= ExpMon) andalso 6996 (Sock =:= ExpSock) -> 6997 ?P("[~s] received unexpected (socket) down message: " 6998 "~n Mon: ~p" 6999 "~n Type: ~p" 7000 "~n Sock: ~p" 7001 "~n Info: ~p", [Name, Mon, Type, Sock, Info]), 7002 exit({unexpected_down, Mon, Type, Sock, Info}); 7003 7004 Any -> 7005 ?P("[~s] received unexpected message: " 7006 "~n ~p", [Name, Any]), 7007 exit({unexpected_message, Any}) 7008 7009 after 1000 -> 7010 ?P("[~s] expected message timeout", [Name]), 7011 exit(ok) 7012 end. 7013 7014 7015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7016 7017%% This is the most basic of tests. 7018%% Spawn a process that creates a (listen) socket, then spawns processes 7019%% that create monitors to it... 7020socket_monitor2(Config) when is_list(Config) -> 7021 ct:timetrap(?MINS(1)), 7022 ?TC_TRY(socket_monitor2, 7023 fun() -> do_socket_monitor2(Config) end). 7024 7025do_socket_monitor2(Config) -> 7026 ?P("begin"), 7027 Type = ?SOCKET_TYPE(Config), 7028 Self = self(), 7029 {OwnerPid, OwnerMon} = 7030 spawn_monitor(fun() -> 7031 ?P("[owner] create (listen) socket"), 7032 {ok, L} = ?LISTEN(Config), 7033 ?P("[owner] send (listen) socket to ctrl"), 7034 Self ! {socket, L}, 7035 ?P("[owner] ready"), 7036 receive 7037 {Self, die} -> 7038 exit(normal) 7039 end 7040 end), 7041 LSock1 = receive 7042 {socket, L} -> 7043 ?P("received socket from owner"), 7044 L; 7045 {'DOWN', OwnerMon, process, OwnerPid, OwnerReason} -> 7046 ?P("received unexpected owner termination: " 7047 "~n ~p", [OwnerReason]), 7048 ct:fail({unexpected_owner_termination, OwnerReason}) 7049 end, 7050 F = fun(S, Fun) -> spawn_monitor(fun() -> Fun(S, Self) end) end, 7051 F1 = fun(Socket, Parent) when is_pid(Parent) -> 7052 ?P("[client] create monitor"), 7053 MRef = inet:monitor(Socket), 7054 Parent ! {self(), ready}, 7055 sm_await_socket_down(MRef, Socket, Type) 7056 end, 7057 ?P("spawn client"), 7058 {Pid1, Mon1} = F(LSock1, F1), 7059 ?P("spawn client"), 7060 sm_await_client_ready(Pid1), 7061 ?P("kill owner"), 7062 exit(OwnerPid, kill), 7063 ?P("await owner termination"), 7064 sm_await_down(OwnerPid, OwnerMon, killed), 7065 ?P("await client termination"), 7066 sm_await_down(Pid1, Mon1, ok), 7067 ?P("done"), 7068 ok. 7069 7070 7071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7072 7073%% This is the most basic of tests. 7074%% Spawn a process that creates "many" (listen) socket(s), then spawns 7075%% a process that create monitors to them... 7076 7077socket_monitor2_manys(Config) when is_list(Config) -> 7078 ct:timetrap(?MINS(1)), 7079 ?TC_TRY(socket_monitor2_manys, 7080 fun() -> do_socket_monitor2_manys(Config) end). 7081 7082do_socket_monitor2_manys(Config) -> 7083 ?P("begin"), 7084 Type = ?SOCKET_TYPE(Config), 7085 Self = self(), 7086 ?P("spawn owner"), 7087 {OwnerPid, OwnerMon} = 7088 spawn_monitor(fun() -> 7089 ?P("[owner] create (listen) socket(s)"), 7090 {ok, L1} = ?LISTEN(Config), 7091 {ok, L2} = ?LISTEN(Config), 7092 {ok, L3} = ?LISTEN(Config), 7093 {ok, L4} = ?LISTEN(Config), 7094 {ok, L5} = ?LISTEN(Config), 7095 ?P("[owner] send (listen) socket(s) to ctrl"), 7096 Self ! {socket, [L1, L2, L3, L4, L5]}, 7097 ?P("[owner] ready"), 7098 receive 7099 {Self, die} -> 7100 exit(normal) 7101 end 7102 end), 7103 ?P("await sockets (from owner)"), 7104 LSocks = receive 7105 {socket, Socks} -> 7106 ?P("received socket(s) from owner"), 7107 Socks; 7108 {'DOWN', OwnerMon, process, OwnerPid, OwnerReason} -> 7109 ?P("received unexpected owner termination: " 7110 "~n ~p", [OwnerReason]), 7111 ct:fail({unexpected_owner_termination, OwnerReason}) 7112 end, 7113 F = fun(S, Fun) -> spawn_monitor(fun() -> Fun(S, Self) end) end, 7114 F1 = fun(Sockets, Parent) when is_list(Sockets) andalso is_pid(Parent) -> 7115 ?P("[client] create monitor(s)"), 7116 Monitors = [{inet:monitor(Socket), Socket} || 7117 Socket <- Sockets], 7118 ?P("[client] announce ready"), 7119 Parent ! {self(), ready}, 7120 sm_await_socket_down2(Monitors, Type) 7121 end, 7122 ?P("spawn client"), 7123 {Pid1, Mon1} = F(LSocks, F1), 7124 ?P("await client ready"), 7125 sm_await_client_ready(Pid1), 7126 ?P("kill owner"), 7127 exit(OwnerPid, kill), 7128 ?P("await owner (~p) termination", [OwnerPid]), 7129 sm_await_down(OwnerPid, OwnerMon, killed), 7130 ?P("await client termination"), 7131 sm_await_down(Pid1, Mon1, ok), 7132 ?P("done"), 7133 ok. 7134 7135 7136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7137 7138%% This is the most basic of tests. 7139%% Spawn a process that creates a (listen) socket, then spawns (client) 7140%% processes that create monitors to it... 7141socket_monitor2_manyc(Config) when is_list(Config) -> 7142 ct:timetrap(?MINS(1)), 7143 ?TC_TRY(socket_monitor2_manyc, 7144 fun() -> do_socket_monitor2_manyc(Config) end). 7145 7146do_socket_monitor2_manyc(Config) -> 7147 ?P("begin"), 7148 Type = ?SOCKET_TYPE(Config), 7149 Self = self(), 7150 {OwnerPid, OwnerMon} = 7151 spawn_monitor(fun() -> 7152 {ok, L} = ?LISTEN(Config), 7153 Self ! {socket, L}, 7154 receive 7155 {Self, die} -> 7156 exit(normal) 7157 end 7158 end), 7159 LSock1 = receive 7160 {socket, L} -> 7161 ?P("received socket from owner"), 7162 L; 7163 {'DOWN', OwnerMon, process, OwnerPid, OwnerReason} -> 7164 ?P("received unexpected owner termination: " 7165 "~n ~p", [OwnerReason]), 7166 ct:fail({unexpected_owner_termination, OwnerReason}) 7167 end, 7168 F = fun(S, Fun, Name) -> 7169 spawn_monitor(fun() -> Fun(S, Name, Self) end) 7170 end, 7171 F1 = fun(Socket, Name, Parent) when is_list(Name) andalso is_pid(Parent) -> 7172 ?P("[~s] create monitor", [Name]), 7173 MRef = inet:monitor(Socket), 7174 Parent ! {self(), ready}, 7175 sm_await_socket_down(MRef, Socket, Type, Name) 7176 end, 7177 ?P("spawn client(s)"), 7178 {Pid1, Mon1} = F(LSock1, F1, "client1"), 7179 {Pid2, Mon2} = F(LSock1, F1, "client2"), 7180 {Pid3, Mon3} = F(LSock1, F1, "client3"), 7181 {Pid4, Mon4} = F(LSock1, F1, "client4"), 7182 {Pid5, Mon5} = F(LSock1, F1, "client5"), 7183 ?P("await client(s) ready"), 7184 sm_await_client_ready(Pid1, "client1"), 7185 sm_await_client_ready(Pid2, "client2"), 7186 sm_await_client_ready(Pid3, "client3"), 7187 sm_await_client_ready(Pid4, "client4"), 7188 sm_await_client_ready(Pid5, "client5"), 7189 ?P("kill owner"), 7190 exit(OwnerPid, kill), 7191 ?P("await owner termination"), 7192 sm_await_down(OwnerPid, OwnerMon, killed), 7193 ?P("await client(s) termination"), 7194 sm_await_down(Pid1, Mon1, ok), 7195 sm_await_down(Pid2, Mon2, ok), 7196 sm_await_down(Pid3, Mon3, ok), 7197 sm_await_down(Pid4, Mon4, ok), 7198 sm_await_down(Pid5, Mon5, ok), 7199 ?P("done"), 7200 ok. 7201 7202 7203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7204 7205%% This is the most basic of tests. 7206%% Spawn a process that creates a (listen) socket, then spawns (client) 7207%% processes that create monitors to it... 7208otp_17492(Config) when is_list(Config) -> 7209 ct:timetrap(?MINS(1)), 7210 ?TC_TRY(otp_17492, fun() -> do_otp_17492(Config) end). 7211 7212do_otp_17492(Config) -> 7213 ?P("begin"), 7214 7215 Self = self(), 7216 7217 ?P("try create listen socket"), 7218 {ok, L} = ?LISTEN(Config, 0, []), 7219 7220 ?P("try get (created) listen socket info"), 7221 try inet:info(L) of 7222 #{owner := Owner} = Info when is_pid(Owner) andalso (Owner =:= Self) -> 7223 ?P("(created) Listen socket info: ~p", [Info]); 7224 OBadInfo -> 7225 ?P("(created) listen socket info: ~p", [OBadInfo]), 7226 (catch gen_tcp:close(L)), 7227 ct:fail({invalid_created_info, OBadInfo}) 7228 catch 7229 OC:OE:OS -> 7230 ?P("Failed get (created) listen socket info: " 7231 "~n Class: ~p" 7232 "~n Error: ~p" 7233 "~n Stack: ~p", [OC, OE, OS]), 7234 (catch gen_tcp:close(L)), 7235 ct:fail({unexpected_created_info_result, {OC, OE, OS}}) 7236 end, 7237 7238 ?P("try close (listen) socket"), 7239 ok = gen_tcp:close(L), 7240 7241 ?P("try get (closed) listen socket info"), 7242 try inet:info(L) of 7243 #{states := [closed]} = CInfo when is_port(L) -> 7244 ?P("(closed) listen socket info: " 7245 "~n ~p", [CInfo]); 7246 #{rstates := [closed], wstates := [closed]} = CInfo -> 7247 ?P("(closed) listen socket info: " 7248 "~n ~p", [CInfo]); 7249 CBadInfo -> 7250 ?P("(closed) listen socket info: ~p", [CBadInfo]), 7251 ct:fail({invalid_closed_info, CBadInfo}) 7252 catch 7253 CC:CE:CS -> 7254 ?P("Failed get (closed) listen socket info: " 7255 "~n Class: ~p" 7256 "~n Error: ~p" 7257 "~n Stack: ~p", [CC, CE, CS]), 7258 (catch gen_tcp:close(L)), 7259 ct:fail({unexpected_closed_info_result, {CC, CE, CS}}) 7260 end, 7261 7262 ?P("done"), 7263 ok. 7264 7265 7266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7267 7268pi(Item) -> 7269 {Item, Val} = process_info(self(), Item), 7270 Val. 7271 7272 7273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7274 7275send_failed_str(Reason) -> 7276 ?F("Send failed: ~w", [Reason]). 7277 7278connect_failed_str(Reason) -> 7279 ?F("Connect failed: ~w", [Reason]). 7280 7281listen_failed_str(Reason) -> 7282 ?F("Listen failed: ~w", [Reason]). 7283 7284accept_failed_str(Reason) -> 7285 ?F("Accept failed: ~w", [Reason]). 7286 7287port_failed_str(Reason) -> 7288 ?F("Port failed: ~w", [Reason]). 7289