aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/socket_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/socket_SUITE.erl')
-rw-r--r--erts/emulator/test/socket_SUITE.erl7525
1 files changed, 7052 insertions, 473 deletions
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index e3545ccbf9..c82e2efad9 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -70,15 +70,40 @@
%% *** API Basic ***
api_b_open_and_close_udp4/1,
api_b_open_and_close_tcp4/1,
+ api_b_open_and_close_udpL/1,
+ api_b_open_and_close_tcpL/1,
api_b_sendto_and_recvfrom_udp4/1,
+ api_b_sendto_and_recvfrom_udpL/1,
api_b_sendmsg_and_recvmsg_udp4/1,
+ api_b_sendmsg_and_recvmsg_udpL/1,
api_b_send_and_recv_tcp4/1,
+ api_b_send_and_recv_tcpL/1,
api_b_sendmsg_and_recvmsg_tcp4/1,
+ api_b_sendmsg_and_recvmsg_tcpL/1,
+
+ %% *** API async ***
+ api_a_connect_tcp4/1,
+ api_a_sendto_and_recvfrom_udp4/1,
+ api_a_sendmsg_and_recvmsg_udp4/1,
+ api_a_send_and_recv_tcp4/1,
+ api_a_sendmsg_and_recvmsg_tcp4/1,
+ api_a_recvfrom_cancel_udp4/1,
+ api_a_recvmsg_cancel_udp4/1,
+ api_a_accept_cancel_tcp4/1,
+ api_a_recv_cancel_tcp4/1,
+ api_a_recvmsg_cancel_tcp4/1,
+ api_a_mrecvfrom_cancel_udp4/1,
+ api_a_mrecvmsg_cancel_udp4/1,
+ api_a_maccept_cancel_tcp4/1,
+ api_a_mrecv_cancel_tcp4/1,
+ api_a_mrecvmsg_cancel_tcp4/1,
+
%% *** API Options ***
api_opt_simple_otp_options/1,
api_opt_simple_otp_rcvbuf_option/1,
api_opt_simple_otp_controlling_process/1,
+ api_opt_ip_add_drop_membership/1,
%% *** API Operation Timeout ***
api_to_connect_tcp4/1,
@@ -107,57 +132,79 @@
%% *** Socket Closure ***
sc_cpe_socket_cleanup_tcp4/1,
sc_cpe_socket_cleanup_tcp6/1,
+ sc_cpe_socket_cleanup_tcpL/1,
sc_cpe_socket_cleanup_udp4/1,
sc_cpe_socket_cleanup_udp6/1,
+ sc_cpe_socket_cleanup_udpL/1,
sc_lc_recv_response_tcp4/1,
sc_lc_recv_response_tcp6/1,
+ sc_lc_recv_response_tcpL/1,
sc_lc_recvfrom_response_udp4/1,
sc_lc_recvfrom_response_udp6/1,
+ sc_lc_recvfrom_response_udpL/1,
sc_lc_recvmsg_response_tcp4/1,
sc_lc_recvmsg_response_tcp6/1,
+ sc_lc_recvmsg_response_tcpL/1,
sc_lc_recvmsg_response_udp4/1,
sc_lc_recvmsg_response_udp6/1,
+ sc_lc_recvmsg_response_udpL/1,
sc_lc_acceptor_response_tcp4/1,
sc_lc_acceptor_response_tcp6/1,
+ sc_lc_acceptor_response_tcpL/1,
sc_rc_recv_response_tcp4/1,
sc_rc_recv_response_tcp6/1,
+ sc_rc_recv_response_tcpL/1,
sc_rc_recvmsg_response_tcp4/1,
sc_rc_recvmsg_response_tcp6/1,
+ sc_rc_recvmsg_response_tcpL/1,
sc_rs_recv_send_shutdown_receive_tcp4/1,
sc_rs_recv_send_shutdown_receive_tcp6/1,
+ sc_rs_recv_send_shutdown_receive_tcpL/1,
sc_rs_recvmsg_send_shutdown_receive_tcp4/1,
sc_rs_recvmsg_send_shutdown_receive_tcp6/1,
+ sc_rs_recvmsg_send_shutdown_receive_tcpL/1,
%% *** Traffic ***
traffic_send_and_recv_chunks_tcp4/1,
traffic_send_and_recv_chunks_tcp6/1,
+ traffic_send_and_recv_chunks_tcpL/1,
traffic_ping_pong_small_send_and_recv_tcp4/1,
traffic_ping_pong_small_send_and_recv_tcp6/1,
+ traffic_ping_pong_small_send_and_recv_tcpL/1,
traffic_ping_pong_medium_send_and_recv_tcp4/1,
traffic_ping_pong_medium_send_and_recv_tcp6/1,
+ traffic_ping_pong_medium_send_and_recv_tcpL/1,
traffic_ping_pong_large_send_and_recv_tcp4/1,
traffic_ping_pong_large_send_and_recv_tcp6/1,
+ traffic_ping_pong_large_send_and_recv_tcpL/1,
traffic_ping_pong_small_sendto_and_recvfrom_udp4/1,
traffic_ping_pong_small_sendto_and_recvfrom_udp6/1,
+ traffic_ping_pong_small_sendto_and_recvfrom_udpL/1,
traffic_ping_pong_medium_sendto_and_recvfrom_udp4/1,
traffic_ping_pong_medium_sendto_and_recvfrom_udp6/1,
+ traffic_ping_pong_medium_sendto_and_recvfrom_udpL/1,
traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4/1,
traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6/1,
+ traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL/1,
traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4/1,
traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6/1,
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL/1,
traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4/1,
traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6/1,
+ traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL/1,
traffic_ping_pong_small_sendmsg_and_recvmsg_udp4/1,
traffic_ping_pong_small_sendmsg_and_recvmsg_udp6/1,
+ traffic_ping_pong_small_sendmsg_and_recvmsg_udpL/1,
traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4/1,
traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6/1,
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL/1,
%% *** Time Test ***
%% Server: transport = gen_tcp, active = false
@@ -325,24 +372,33 @@
%% Client: transport = socket(tcp)
ttest_ssockf_csockf_small_tcp4/1,
ttest_ssockf_csockf_small_tcp6/1,
+ ttest_ssockf_csockf_small_tcpL/1,
ttest_ssockf_csockf_medium_tcp4/1,
ttest_ssockf_csockf_medium_tcp6/1,
+ ttest_ssockf_csockf_medium_tcpL/1,
ttest_ssockf_csockf_large_tcp4/1,
ttest_ssockf_csockf_large_tcp6/1,
+ ttest_ssockf_csockf_large_tcpL/1,
ttest_ssockf_csocko_small_tcp4/1,
ttest_ssockf_csocko_small_tcp6/1,
+ ttest_ssockf_csocko_small_tcpL/1,
ttest_ssockf_csocko_medium_tcp4/1,
ttest_ssockf_csocko_medium_tcp6/1,
+ ttest_ssockf_csocko_medium_tcpL/1,
ttest_ssockf_csocko_large_tcp4/1,
ttest_ssockf_csocko_large_tcp6/1,
+ ttest_ssockf_csocko_large_tcpL/1,
ttest_ssockf_csockt_small_tcp4/1,
ttest_ssockf_csockt_small_tcp6/1,
+ ttest_ssockf_csockt_small_tcpL/1,
ttest_ssockf_csockt_medium_tcp4/1,
ttest_ssockf_csockt_medium_tcp6/1,
+ ttest_ssockf_csockt_medium_tcpL/1,
ttest_ssockf_csockt_large_tcp4/1,
ttest_ssockf_csockt_large_tcp6/1,
+ ttest_ssockf_csockt_large_tcpL/1,
%% Server: transport = socket(tcp), active = once
%% Client: transport = gen_tcp
@@ -371,24 +427,33 @@
%% Client: transport = socket(tcp)
ttest_ssocko_csockf_small_tcp4/1,
ttest_ssocko_csockf_small_tcp6/1,
+ ttest_ssocko_csockf_small_tcpL/1,
ttest_ssocko_csockf_medium_tcp4/1,
+ ttest_ssocko_csockf_medium_tcpL/1,
ttest_ssocko_csockf_medium_tcp6/1,
ttest_ssocko_csockf_large_tcp4/1,
ttest_ssocko_csockf_large_tcp6/1,
+ ttest_ssocko_csockf_large_tcpL/1,
ttest_ssocko_csocko_small_tcp4/1,
ttest_ssocko_csocko_small_tcp6/1,
+ ttest_ssocko_csocko_small_tcpL/1,
ttest_ssocko_csocko_medium_tcp4/1,
ttest_ssocko_csocko_medium_tcp6/1,
+ ttest_ssocko_csocko_medium_tcpL/1,
ttest_ssocko_csocko_large_tcp4/1,
ttest_ssocko_csocko_large_tcp6/1,
+ ttest_ssocko_csocko_large_tcpL/1,
ttest_ssocko_csockt_small_tcp4/1,
ttest_ssocko_csockt_small_tcp6/1,
+ ttest_ssocko_csockt_small_tcpL/1,
ttest_ssocko_csockt_medium_tcp4/1,
ttest_ssocko_csockt_medium_tcp6/1,
+ ttest_ssocko_csockt_medium_tcpL/1,
ttest_ssocko_csockt_large_tcp4/1,
ttest_ssocko_csockt_large_tcp6/1,
+ ttest_ssocko_csockt_large_tcpL/1,
%% Server: transport = socket(tcp), active = true
%% Client: transport = gen_tcp
@@ -417,24 +482,33 @@
%% Client: transport = socket(tcp)
ttest_ssockt_csockf_small_tcp4/1,
ttest_ssockt_csockf_small_tcp6/1,
+ ttest_ssockt_csockf_small_tcpL/1,
ttest_ssockt_csockf_medium_tcp4/1,
ttest_ssockt_csockf_medium_tcp6/1,
+ ttest_ssockt_csockf_medium_tcpL/1,
ttest_ssockt_csockf_large_tcp4/1,
ttest_ssockt_csockf_large_tcp6/1,
+ ttest_ssockt_csockf_large_tcpL/1,
ttest_ssockt_csocko_small_tcp4/1,
ttest_ssockt_csocko_small_tcp6/1,
+ ttest_ssockt_csocko_small_tcpL/1,
ttest_ssockt_csocko_medium_tcp4/1,
ttest_ssockt_csocko_medium_tcp6/1,
+ ttest_ssockt_csocko_medium_tcpL/1,
ttest_ssockt_csocko_large_tcp4/1,
ttest_ssockt_csocko_large_tcp6/1,
+ ttest_ssockt_csocko_large_tcpL/1,
ttest_ssockt_csockt_small_tcp4/1,
ttest_ssockt_csockt_small_tcp6/1,
+ ttest_ssockt_csockt_small_tcpL/1,
ttest_ssockt_csockt_medium_tcp4/1,
ttest_ssockt_csockt_medium_tcp6/1,
+ ttest_ssockt_csockt_medium_tcpL/1,
ttest_ssockt_csockt_large_tcp4/1,
- ttest_ssockt_csockt_large_tcp6/1
+ ttest_ssockt_csockt_large_tcp6/1,
+ ttest_ssockt_csockt_large_tcpL/1
%% Tickets
]).
@@ -508,71 +582,78 @@ use_group(Group, Env, Default) ->
groups() ->
- [{api, [], api_cases()},
- {api_basic, [], api_basic_cases()},
- {api_options, [], api_options_cases()},
- {api_op_with_timeout, [], api_op_with_timeout_cases()},
- {socket_closure, [], socket_closure_cases()},
- {sc_ctrl_proc_exit, [], sc_cp_exit_cases()},
- {sc_local_close, [], sc_lc_cases()},
- {sc_remote_close, [], sc_rc_cases()},
- {sc_remote_shutdown, [], sc_rs_cases()},
- {traffic, [], traffic_cases()},
- {ttest, [], ttest_cases()},
- {ttest_sgenf, [], ttest_sgenf_cases()},
- {ttest_sgenf_cgen, [], ttest_sgenf_cgen_cases()},
- {ttest_sgenf_cgenf, [], ttest_sgenf_cgenf_cases()},
- {ttest_sgenf_cgeno, [], ttest_sgenf_cgeno_cases()},
- {ttest_sgenf_cgent, [], ttest_sgenf_cgent_cases()},
- {ttest_sgenf_csock, [], ttest_sgenf_csock_cases()},
- {ttest_sgenf_csockf, [], ttest_sgenf_csockf_cases()},
- {ttest_sgenf_csocko, [], ttest_sgenf_csocko_cases()},
- {ttest_sgenf_csockt, [], ttest_sgenf_csockt_cases()},
- {ttest_sgeno, [], ttest_sgeno_cases()},
- {ttest_sgeno_cgen, [], ttest_sgeno_cgen_cases()},
- {ttest_sgeno_cgenf, [], ttest_sgeno_cgenf_cases()},
- {ttest_sgeno_cgeno, [], ttest_sgeno_cgeno_cases()},
- {ttest_sgeno_cgent, [], ttest_sgeno_cgent_cases()},
- {ttest_sgeno_csock, [], ttest_sgeno_csock_cases()},
- {ttest_sgeno_csockf, [], ttest_sgeno_csockf_cases()},
- {ttest_sgeno_csocko, [], ttest_sgeno_csocko_cases()},
- {ttest_sgeno_csockt, [], ttest_sgeno_csockt_cases()},
- {ttest_sgent, [], ttest_sgent_cases()},
- {ttest_sgent_cgen, [], ttest_sgent_cgen_cases()},
- {ttest_sgent_cgenf, [], ttest_sgent_cgenf_cases()},
- {ttest_sgent_cgeno, [], ttest_sgent_cgeno_cases()},
- {ttest_sgent_cgent, [], ttest_sgent_cgent_cases()},
- {ttest_sgent_csock, [], ttest_sgent_csock_cases()},
- {ttest_sgent_csockf, [], ttest_sgent_csockf_cases()},
- {ttest_sgent_csocko, [], ttest_sgent_csocko_cases()},
- {ttest_sgent_csockt, [], ttest_sgent_csockt_cases()},
- {ttest_ssockf, [], ttest_ssockf_cases()},
- {ttest_ssockf_cgen, [], ttest_ssockf_cgen_cases()},
- {ttest_ssockf_cgenf, [], ttest_ssockf_cgenf_cases()},
- {ttest_ssockf_cgeno, [], ttest_ssockf_cgeno_cases()},
- {ttest_ssockf_cgent, [], ttest_ssockf_cgent_cases()},
- {ttest_ssockf_csock, [], ttest_ssockf_csock_cases()},
- {ttest_ssockf_csockf, [], ttest_ssockf_csockf_cases()},
- {ttest_ssockf_csocko, [], ttest_ssockf_csocko_cases()},
- {ttest_ssockf_csockt, [], ttest_ssockf_csockt_cases()},
- {ttest_ssocko, [], ttest_ssocko_cases()},
- {ttest_ssocko_cgen, [], ttest_ssocko_cgen_cases()},
- {ttest_ssocko_cgenf, [], ttest_ssocko_cgenf_cases()},
- {ttest_ssocko_cgeno, [], ttest_ssocko_cgeno_cases()},
- {ttest_ssocko_cgent, [], ttest_ssocko_cgent_cases()},
- {ttest_ssocko_csock, [], ttest_ssocko_csock_cases()},
- {ttest_ssocko_csockf, [], ttest_ssocko_csockf_cases()},
- {ttest_ssocko_csocko, [], ttest_ssocko_csocko_cases()},
- {ttest_ssocko_csockt, [], ttest_ssocko_csockt_cases()},
- {ttest_ssockt, [], ttest_ssockt_cases()},
- {ttest_ssockt_cgen, [], ttest_ssockt_cgen_cases()},
- {ttest_ssockt_cgenf, [], ttest_ssockt_cgenf_cases()},
- {ttest_ssockt_cgeno, [], ttest_ssockt_cgeno_cases()},
- {ttest_ssockt_cgent, [], ttest_ssockt_cgent_cases()},
- {ttest_ssockt_csock, [], ttest_ssockt_csock_cases()},
- {ttest_ssockt_csockf, [], ttest_ssockt_csockf_cases()},
- {ttest_ssockt_csocko, [], ttest_ssockt_csocko_cases()},
- {ttest_ssockt_csockt, [], ttest_ssockt_csockt_cases()}
+ [{api, [], api_cases()},
+ {api_basic, [], api_basic_cases()},
+ {api_async, [], api_async_cases()},
+ {api_options, [], api_options_cases()},
+ {api_options_otp, [], api_options_otp_cases()},
+ {api_options_ip, [], api_options_ip_cases()},
+ {api_op_with_timeout, [], api_op_with_timeout_cases()},
+ {socket_closure, [], socket_closure_cases()},
+ {sc_ctrl_proc_exit, [], sc_cp_exit_cases()},
+ {sc_local_close, [], sc_lc_cases()},
+ {sc_remote_close, [], sc_rc_cases()},
+ {sc_remote_shutdown, [], sc_rs_cases()},
+ {traffic, [], traffic_cases()},
+ {traffic_chunks, [], traffic_chunks_cases()},
+ {traffic_pp_send_recv, [], traffic_pp_send_recv_cases()},
+ {traffic_pp_sendto_recvfrom, [], traffic_pp_sendto_recvfrom_cases()},
+ {traffic_pp_sendmsg_recvmsg, [], traffic_pp_sendmsg_recvmsg_cases()},
+ {ttest, [], ttest_cases()},
+ {ttest_sgenf, [], ttest_sgenf_cases()},
+ {ttest_sgenf_cgen, [], ttest_sgenf_cgen_cases()},
+ {ttest_sgenf_cgenf, [], ttest_sgenf_cgenf_cases()},
+ {ttest_sgenf_cgeno, [], ttest_sgenf_cgeno_cases()},
+ {ttest_sgenf_cgent, [], ttest_sgenf_cgent_cases()},
+ {ttest_sgenf_csock, [], ttest_sgenf_csock_cases()},
+ {ttest_sgenf_csockf, [], ttest_sgenf_csockf_cases()},
+ {ttest_sgenf_csocko, [], ttest_sgenf_csocko_cases()},
+ {ttest_sgenf_csockt, [], ttest_sgenf_csockt_cases()},
+ {ttest_sgeno, [], ttest_sgeno_cases()},
+ {ttest_sgeno_cgen, [], ttest_sgeno_cgen_cases()},
+ {ttest_sgeno_cgenf, [], ttest_sgeno_cgenf_cases()},
+ {ttest_sgeno_cgeno, [], ttest_sgeno_cgeno_cases()},
+ {ttest_sgeno_cgent, [], ttest_sgeno_cgent_cases()},
+ {ttest_sgeno_csock, [], ttest_sgeno_csock_cases()},
+ {ttest_sgeno_csockf, [], ttest_sgeno_csockf_cases()},
+ {ttest_sgeno_csocko, [], ttest_sgeno_csocko_cases()},
+ {ttest_sgeno_csockt, [], ttest_sgeno_csockt_cases()},
+ {ttest_sgent, [], ttest_sgent_cases()},
+ {ttest_sgent_cgen, [], ttest_sgent_cgen_cases()},
+ {ttest_sgent_cgenf, [], ttest_sgent_cgenf_cases()},
+ {ttest_sgent_cgeno, [], ttest_sgent_cgeno_cases()},
+ {ttest_sgent_cgent, [], ttest_sgent_cgent_cases()},
+ {ttest_sgent_csock, [], ttest_sgent_csock_cases()},
+ {ttest_sgent_csockf, [], ttest_sgent_csockf_cases()},
+ {ttest_sgent_csocko, [], ttest_sgent_csocko_cases()},
+ {ttest_sgent_csockt, [], ttest_sgent_csockt_cases()},
+ {ttest_ssockf, [], ttest_ssockf_cases()},
+ {ttest_ssockf_cgen, [], ttest_ssockf_cgen_cases()},
+ {ttest_ssockf_cgenf, [], ttest_ssockf_cgenf_cases()},
+ {ttest_ssockf_cgeno, [], ttest_ssockf_cgeno_cases()},
+ {ttest_ssockf_cgent, [], ttest_ssockf_cgent_cases()},
+ {ttest_ssockf_csock, [], ttest_ssockf_csock_cases()},
+ {ttest_ssockf_csockf, [], ttest_ssockf_csockf_cases()},
+ {ttest_ssockf_csocko, [], ttest_ssockf_csocko_cases()},
+ {ttest_ssockf_csockt, [], ttest_ssockf_csockt_cases()},
+ {ttest_ssocko, [], ttest_ssocko_cases()},
+ {ttest_ssocko_cgen, [], ttest_ssocko_cgen_cases()},
+ {ttest_ssocko_cgenf, [], ttest_ssocko_cgenf_cases()},
+ {ttest_ssocko_cgeno, [], ttest_ssocko_cgeno_cases()},
+ {ttest_ssocko_cgent, [], ttest_ssocko_cgent_cases()},
+ {ttest_ssocko_csock, [], ttest_ssocko_csock_cases()},
+ {ttest_ssocko_csockf, [], ttest_ssocko_csockf_cases()},
+ {ttest_ssocko_csocko, [], ttest_ssocko_csocko_cases()},
+ {ttest_ssocko_csockt, [], ttest_ssocko_csockt_cases()},
+ {ttest_ssockt, [], ttest_ssockt_cases()},
+ {ttest_ssockt_cgen, [], ttest_ssockt_cgen_cases()},
+ {ttest_ssockt_cgenf, [], ttest_ssockt_cgenf_cases()},
+ {ttest_ssockt_cgeno, [], ttest_ssockt_cgeno_cases()},
+ {ttest_ssockt_cgent, [], ttest_ssockt_cgent_cases()},
+ {ttest_ssockt_csock, [], ttest_ssockt_csock_cases()},
+ {ttest_ssockt_csockf, [], ttest_ssockt_csockf_cases()},
+ {ttest_ssockt_csocko, [], ttest_ssockt_csocko_cases()},
+ {ttest_ssockt_csockt, [], ttest_ssockt_csockt_cases()}
%% {tickets, [], ticket_cases()}
].
@@ -580,6 +661,7 @@ groups() ->
api_cases() ->
[
{group, api_basic},
+ {group, api_async},
{group, api_options},
{group, api_op_with_timeout}
].
@@ -588,19 +670,55 @@ api_basic_cases() ->
[
api_b_open_and_close_udp4,
api_b_open_and_close_tcp4,
+ api_b_open_and_close_udpL,
+ api_b_open_and_close_tcpL,
api_b_sendto_and_recvfrom_udp4,
+ api_b_sendto_and_recvfrom_udpL,
api_b_sendmsg_and_recvmsg_udp4,
+ api_b_sendmsg_and_recvmsg_udpL,
api_b_send_and_recv_tcp4,
- api_b_sendmsg_and_recvmsg_tcp4
+ api_b_send_and_recv_tcpL,
+ api_b_sendmsg_and_recvmsg_tcp4,
+ api_b_sendmsg_and_recvmsg_tcpL
+ ].
+
+api_async_cases() ->
+ [
+ api_a_connect_tcp4,
+ api_a_sendto_and_recvfrom_udp4,
+ api_a_sendmsg_and_recvmsg_udp4,
+ api_a_send_and_recv_tcp4,
+ api_a_sendmsg_and_recvmsg_tcp4,
+ api_a_recvfrom_cancel_udp4,
+ api_a_recvmsg_cancel_udp4,
+ api_a_accept_cancel_tcp4,
+ api_a_recv_cancel_tcp4,
+ api_a_recvmsg_cancel_tcp4,
+ api_a_mrecvfrom_cancel_udp4,
+ api_a_mrecvmsg_cancel_udp4,
+ api_a_maccept_cancel_tcp4,
+ api_a_mrecv_cancel_tcp4,
+ api_a_mrecvmsg_cancel_tcp4
].
api_options_cases() ->
[
+ {group, api_options_otp},
+ {group, api_options_ip}
+ ].
+
+api_options_otp_cases() ->
+ [
api_opt_simple_otp_options,
api_opt_simple_otp_rcvbuf_option,
api_opt_simple_otp_controlling_process
].
+api_options_ip_cases() ->
+ [
+ api_opt_ip_add_drop_membership
+ ].
+
api_op_with_timeout_cases() ->
[
api_to_connect_tcp4,
@@ -638,13 +756,15 @@ socket_closure_cases() ->
].
%% These cases are all about socket cleanup after the controlling process
-%% exits *without* calling socket:close/1.
+%% exits *without* explicitly calling socket:close/1.
sc_cp_exit_cases() ->
[
sc_cpe_socket_cleanup_tcp4,
sc_cpe_socket_cleanup_tcp6,
+ sc_cpe_socket_cleanup_tcpL,
sc_cpe_socket_cleanup_udp4,
- sc_cpe_socket_cleanup_udp6
+ sc_cpe_socket_cleanup_udp6,
+ sc_cpe_socket_cleanup_udpL
].
%% These cases tests what happens when the socket is closed locally.
@@ -652,17 +772,22 @@ sc_lc_cases() ->
[
sc_lc_recv_response_tcp4,
sc_lc_recv_response_tcp6,
+ sc_lc_recv_response_tcpL,
sc_lc_recvfrom_response_udp4,
sc_lc_recvfrom_response_udp6,
+ sc_lc_recvfrom_response_udpL,
sc_lc_recvmsg_response_tcp4,
sc_lc_recvmsg_response_tcp6,
+ sc_lc_recvmsg_response_tcpL,
sc_lc_recvmsg_response_udp4,
sc_lc_recvmsg_response_udp6,
+ sc_lc_recvmsg_response_udpL,
sc_lc_acceptor_response_tcp4,
- sc_lc_acceptor_response_tcp6
+ sc_lc_acceptor_response_tcp6,
+ sc_lc_acceptor_response_tcpL
].
%% These cases tests what happens when the socket is closed remotely.
@@ -670,9 +795,11 @@ sc_rc_cases() ->
[
sc_rc_recv_response_tcp4,
sc_rc_recv_response_tcp6,
+ sc_rc_recv_response_tcpL,
sc_rc_recvmsg_response_tcp4,
- sc_rc_recvmsg_response_tcp6
+ sc_rc_recvmsg_response_tcp6,
+ sc_rc_recvmsg_response_tcpL
].
%% These cases tests what happens when the socket is shutdown/closed remotely
@@ -681,43 +808,72 @@ sc_rs_cases() ->
[
sc_rs_recv_send_shutdown_receive_tcp4,
sc_rs_recv_send_shutdown_receive_tcp6,
+ sc_rs_recv_send_shutdown_receive_tcpL,
sc_rs_recvmsg_send_shutdown_receive_tcp4,
- sc_rs_recvmsg_send_shutdown_receive_tcp6
+ sc_rs_recvmsg_send_shutdown_receive_tcp6,
+ sc_rs_recvmsg_send_shutdown_receive_tcpL
].
traffic_cases() ->
[
+ {group, traffic_chunks},
+ {group, traffic_pp_send_recv},
+ {group, traffic_pp_sendto_recvfrom},
+ {group, traffic_pp_sendmsg_recvmsg}
+ ].
+
+traffic_chunks_cases() ->
+ [
traffic_send_and_recv_chunks_tcp4,
traffic_send_and_recv_chunks_tcp6,
+ traffic_send_and_recv_chunks_tcpL
+ ].
+traffic_pp_send_recv_cases() ->
+ [
traffic_ping_pong_small_send_and_recv_tcp4,
traffic_ping_pong_small_send_and_recv_tcp6,
+ traffic_ping_pong_small_send_and_recv_tcpL,
traffic_ping_pong_medium_send_and_recv_tcp4,
traffic_ping_pong_medium_send_and_recv_tcp6,
+ traffic_ping_pong_medium_send_and_recv_tcpL,
traffic_ping_pong_large_send_and_recv_tcp4,
traffic_ping_pong_large_send_and_recv_tcp6,
+ traffic_ping_pong_large_send_and_recv_tcpL
+ ].
+traffic_pp_sendto_recvfrom_cases() ->
+ [
traffic_ping_pong_small_sendto_and_recvfrom_udp4,
traffic_ping_pong_small_sendto_and_recvfrom_udp6,
+ traffic_ping_pong_small_sendto_and_recvfrom_udpL,
traffic_ping_pong_medium_sendto_and_recvfrom_udp4,
traffic_ping_pong_medium_sendto_and_recvfrom_udp6,
+ traffic_ping_pong_medium_sendto_and_recvfrom_udpL
+ ].
+traffic_pp_sendmsg_recvmsg_cases() ->
+ [
traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4,
traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6,
+ traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL,
traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4,
traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6,
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL,
traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4,
traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6,
+ traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL,
traffic_ping_pong_small_sendmsg_and_recvmsg_udp4,
traffic_ping_pong_small_sendmsg_and_recvmsg_udp6,
+ traffic_ping_pong_small_sendmsg_and_recvmsg_udpL,
traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4,
- traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6,
+ traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL
].
-
-
+
ttest_cases() ->
[
%% Server: transport = gen_tcp, active = false
@@ -1123,12 +1279,15 @@ ttest_ssockf_csockf_cases() ->
[
ttest_ssockf_csockf_small_tcp4,
ttest_ssockf_csockf_small_tcp6,
+ ttest_ssockf_csockf_small_tcpL,
ttest_ssockf_csockf_medium_tcp4,
ttest_ssockf_csockf_medium_tcp6,
+ ttest_ssockf_csockf_medium_tcpL,
ttest_ssockf_csockf_large_tcp4,
- ttest_ssockf_csockf_large_tcp6
+ ttest_ssockf_csockf_large_tcp6,
+ ttest_ssockf_csockf_large_tcpL
].
%% Server: transport = socket(tcp), active = false
@@ -1137,12 +1296,15 @@ ttest_ssockf_csocko_cases() ->
[
ttest_ssockf_csocko_small_tcp4,
ttest_ssockf_csocko_small_tcp6,
+ ttest_ssockf_csocko_small_tcpL,
ttest_ssockf_csocko_medium_tcp4,
ttest_ssockf_csocko_medium_tcp6,
+ ttest_ssockf_csocko_medium_tcpL,
ttest_ssockf_csocko_large_tcp4,
- ttest_ssockf_csocko_large_tcp6
+ ttest_ssockf_csocko_large_tcp6,
+ ttest_ssockf_csocko_large_tcpL
].
%% Server: transport = socket(tcp), active = false
@@ -1151,12 +1313,15 @@ ttest_ssockf_csockt_cases() ->
[
ttest_ssockf_csockt_small_tcp4,
ttest_ssockf_csockt_small_tcp6,
+ ttest_ssockf_csockt_small_tcpL,
ttest_ssockf_csockt_medium_tcp4,
ttest_ssockf_csockt_medium_tcp6,
+ ttest_ssockf_csockt_medium_tcpL,
ttest_ssockf_csockt_large_tcp4,
- ttest_ssockf_csockt_large_tcp6
+ ttest_ssockf_csockt_large_tcp6,
+ ttest_ssockf_csockt_large_tcpL
].
%% Server: transport = socket(tcp), active = once
@@ -1232,12 +1397,15 @@ ttest_ssocko_csockf_cases() ->
[
ttest_ssocko_csockf_small_tcp4,
ttest_ssocko_csockf_small_tcp6,
+ ttest_ssocko_csockf_small_tcpL,
ttest_ssocko_csockf_medium_tcp4,
ttest_ssocko_csockf_medium_tcp6,
+ ttest_ssocko_csockf_medium_tcpL,
ttest_ssocko_csockf_large_tcp4,
- ttest_ssocko_csockf_large_tcp6
+ ttest_ssocko_csockf_large_tcp6,
+ ttest_ssocko_csockf_large_tcpL
].
%% Server: transport = socket(tcp), active = once
@@ -1246,12 +1414,15 @@ ttest_ssocko_csocko_cases() ->
[
ttest_ssocko_csocko_small_tcp4,
ttest_ssocko_csocko_small_tcp6,
+ ttest_ssocko_csocko_small_tcpL,
ttest_ssocko_csocko_medium_tcp4,
ttest_ssocko_csocko_medium_tcp6,
+ ttest_ssocko_csocko_medium_tcpL,
ttest_ssocko_csocko_large_tcp4,
- ttest_ssocko_csocko_large_tcp6
+ ttest_ssocko_csocko_large_tcp6,
+ ttest_ssocko_csocko_large_tcpL
].
%% Server: transport = socket(tcp), active = once
@@ -1260,12 +1431,15 @@ ttest_ssocko_csockt_cases() ->
[
ttest_ssocko_csockt_small_tcp4,
ttest_ssocko_csockt_small_tcp6,
+ ttest_ssocko_csockt_small_tcpL,
ttest_ssocko_csockt_medium_tcp4,
ttest_ssocko_csockt_medium_tcp6,
+ ttest_ssocko_csockt_medium_tcpL,
ttest_ssocko_csockt_large_tcp4,
- ttest_ssocko_csockt_large_tcp6
+ ttest_ssocko_csockt_large_tcp6,
+ ttest_ssocko_csockt_large_tcpL
].
%% Server: transport = socket(tcp), active = true
@@ -1341,12 +1515,15 @@ ttest_ssockt_csockf_cases() ->
[
ttest_ssockt_csockf_small_tcp4,
ttest_ssockt_csockf_small_tcp6,
+ ttest_ssockt_csockf_small_tcpL,
ttest_ssockt_csockf_medium_tcp4,
ttest_ssockt_csockf_medium_tcp6,
+ ttest_ssockt_csockf_medium_tcpL,
ttest_ssockt_csockf_large_tcp4,
- ttest_ssockt_csockf_large_tcp6
+ ttest_ssockt_csockf_large_tcp6,
+ ttest_ssockt_csockf_large_tcpL
].
%% Server: transport = socket(tcp), active = true
@@ -1355,12 +1532,15 @@ ttest_ssockt_csocko_cases() ->
[
ttest_ssockt_csocko_small_tcp4,
ttest_ssockt_csocko_small_tcp6,
+ ttest_ssockt_csocko_small_tcpL,
ttest_ssockt_csocko_medium_tcp4,
ttest_ssockt_csocko_medium_tcp6,
+ ttest_ssockt_csocko_medium_tcpL,
ttest_ssockt_csocko_large_tcp4,
- ttest_ssockt_csocko_large_tcp6
+ ttest_ssockt_csocko_large_tcp6,
+ ttest_ssockt_csocko_large_tcpL
].
%% Server: transport = socket(tcp), active = true
@@ -1369,12 +1549,15 @@ ttest_ssockt_csockt_cases() ->
[
ttest_ssockt_csockt_small_tcp4,
ttest_ssockt_csockt_small_tcp6,
+ ttest_ssockt_csockt_small_tcpL,
ttest_ssockt_csockt_medium_tcp4,
ttest_ssockt_csockt_medium_tcp6,
+ ttest_ssockt_csockt_medium_tcpL,
ttest_ssockt_csockt_large_tcp4,
- ttest_ssockt_csockt_large_tcp6
+ ttest_ssockt_csockt_large_tcp6,
+ ttest_ssockt_csockt_large_tcpL
].
%% ticket_cases() ->
@@ -1413,11 +1596,12 @@ init_per_group(ttest = _GroupName, Config) ->
io:format("init_per_group(~w) -> entry with"
"~n Config: ~p"
"~n", [_GroupName, Config]),
+ ttest_manager_start(),
case lists:keysearch(esock_test_ttest_runtime, 1, Config) of
{value, _} ->
Config;
false ->
- [{esock_test_ttest_runtime, which_ttest_runtime_env()}|Config]
+ [{esock_test_ttest_runtime, which_ttest_runtime_env()} | Config]
end;
init_per_group(_GroupName, Config) ->
Config.
@@ -1426,6 +1610,7 @@ end_per_group(ttest = _GroupName, Config) ->
io:format("init_per_group(~w) -> entry with"
"~n Config: ~p"
"~n", [_GroupName, Config]),
+ ttest_manager_stop(),
lists:keydelete(esock_test_ttest_runtime, 1, Config);
end_per_group(_GroupName, Config) ->
Config.
@@ -1435,16 +1620,16 @@ init_per_testcase(_TC, Config) ->
io:format("init_per_testcase(~w) -> entry with"
"~n Config: ~p"
"~n", [_TC, Config]),
- case quiet_mode(Config) of
- default ->
- ?LOGGER:start();
- Quiet ->
- ?LOGGER:start(Quiet)
- end,
+ %% case quiet_mode(Config) of
+ %% default ->
+ %% ?LOGGER:start();
+ %% Quiet ->
+ %% ?LOGGER:start(Quiet)
+ %% end,
Config.
end_per_testcase(_TC, Config) ->
- ?LOGGER:stop(),
+ %% ?LOGGER:stop(),
Config.
@@ -1510,6 +1695,46 @@ api_b_open_and_close_tcp4(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Basically open (create) and close an Unix Domain dgram (UDP) socket.
+%% With some extra checks...
+api_b_open_and_close_udpL(suite) ->
+ [];
+api_b_open_and_close_udpL(doc) ->
+ [];
+api_b_open_and_close_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_open_and_close_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ type => dgram,
+ protocol => default},
+ ok = api_b_open_and_close(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically open (create) and close an Unix Domain stream (TCP) socket.
+%% With some extra checks...
+api_b_open_and_close_tcpL(suite) ->
+ [];
+api_b_open_and_close_tcpL(doc) ->
+ [];
+api_b_open_and_close_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_open_and_close_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ type => stream,
+ protocol => default},
+ ok = api_b_open_and_close(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
api_b_open_and_close(InitState) ->
Seq =
[
@@ -1633,6 +1858,37 @@ api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) ->
socket:recvfrom(Sock)
end,
InitState = #{domain => inet,
+ proto => udp,
+ send => Send,
+ recv => Recv},
+ ok = api_b_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv4 UDP (dgram) socket using
+%% sendto and recvfrom.
+api_b_sendto_and_recvfrom_udpL(suite) ->
+ [];
+api_b_sendto_and_recvfrom_udpL(doc) ->
+ [];
+api_b_sendto_and_recvfrom_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_sendto_and_recvfrom_udpL,
+ fun() ->
+ has_support_unix_domain_socket(),
+ unix_domain_socket_host_cond()
+ end,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ socket:sendto(Sock, Data, Dest)
+ end,
+ Recv = fun(Sock) ->
+ socket:recvfrom(Sock)
+ end,
+ InitState = #{domain => local,
+ proto => default,
send => Send,
recv => Recv},
ok = api_b_send_and_recv_udp(InitState)
@@ -1665,17 +1921,66 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) ->
end,
Recv = fun(Sock) ->
%% We have some issues on old darwing...
- socket:setopt(Sock, otp, debug, true),
+ %% socket:setopt(Sock, otp, debug, true),
case socket:recvmsg(Sock) of
{ok, #{addr := Source,
iov := [Data]}} ->
- socket:setopt(Sock, otp, debug, false),
+ %% socket:setopt(Sock, otp, debug, false),
{ok, {Source, Data}};
{error, _} = ERROR ->
ERROR
end
end,
InitState = #{domain => inet,
+ proto => udp,
+ send => Send,
+ recv => Recv},
+ ok = api_b_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv4 UDP (dgram) socket
+%% using sendmsg and recvmsg.
+api_b_sendmsg_and_recvmsg_udpL(suite) ->
+ [];
+api_b_sendmsg_and_recvmsg_udpL(doc) ->
+ [];
+api_b_sendmsg_and_recvmsg_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_b_sendmsg_and_recvmsg_udpL,
+ fun() ->
+ has_support_unix_domain_socket(),
+ unix_domain_socket_host_cond()
+ end,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ %% We need tests for this,
+ %% but this is not the place it.
+ %% CMsgHdr = #{level => ip,
+ %% type => tos,
+ %% data => reliability},
+ %% CMsgHdrs = [CMsgHdr],
+ MsgHdr = #{addr => Dest,
+ %% ctrl => CMsgHdrs,
+ iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ %% We have some issues on old darwing...
+ %% socket:setopt(Sock, otp, debug, true),
+ case socket:recvmsg(Sock) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ %% socket:setopt(Sock, otp, debug, false),
+ {ok, {Source, Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => local,
+ proto => default,
send => Send,
recv => Recv},
ok = api_b_send_and_recv_udp(InitState)
@@ -1688,42 +1993,64 @@ api_b_send_and_recv_udp(InitState) ->
Seq =
[
#{desc => "local address",
- cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
- {ok, State#{lsa => LSA}}
+ cmd => fun(#{domain := local = Domain} = State) ->
+ LSASrc = which_local_socket_addr(Domain),
+ LSADst = which_local_socket_addr(Domain),
+ {ok, State#{lsa_src => LSASrc,
+ lsa_dst => LSADst}};
+ (#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa_src => LSA,
+ lsa_dst => LSA}}
end},
+
#{desc => "open src socket",
- cmd => fun(#{domain := Domain} = State) ->
- Sock = sock_open(Domain, dgram, udp),
- SASrc = sock_sockname(Sock),
- {ok, State#{sock_src => Sock, sa_src => SASrc}}
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ Sock = sock_open(Domain, dgram, Proto),
+ {ok, State#{sock_src => Sock}}
end},
#{desc => "bind src",
- cmd => fun(#{sock_src := Sock, lsa := LSA}) ->
- sock_bind(Sock, LSA),
- ok
+ cmd => fun(#{sock_src := Sock, lsa_src := LSA}) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("src bound"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("src bind failed: ~p", [Reason]),
+ ERROR
+ end
end},
#{desc => "sockname src socket",
cmd => fun(#{sock_src := Sock} = State) ->
SASrc = sock_sockname(Sock),
- %% ei("src sockaddr: ~p", [SASrc]),
+ ?SEV_IPRINT("src sockaddr: "
+ "~n ~p", [SASrc]),
{ok, State#{sa_src => SASrc}}
end},
+
#{desc => "open dst socket",
- cmd => fun(#{domain := Domain} = State) ->
- Sock = sock_open(Domain, dgram, udp),
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ Sock = sock_open(Domain, dgram, Proto),
{ok, State#{sock_dst => Sock}}
end},
#{desc => "bind dst",
- cmd => fun(#{sock_dst := Sock, lsa := LSA}) ->
- sock_bind(Sock, LSA),
- ok
+ cmd => fun(#{sock_dst := Sock, lsa_dst := LSA}) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("src bound"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("src bind failed: ~p", [Reason]),
+ ERROR
+ end
end},
#{desc => "sockname dst socket",
cmd => fun(#{sock_dst := Sock} = State) ->
SADst = sock_sockname(Sock),
- %% ei("dst sockaddr: ~p", [SADst]),
+ ?SEV_IPRINT("dst sockaddr: "
+ "~n ~p", [SADst]),
{ok, State#{sa_dst => SADst}}
end},
#{desc => "send req (to dst)",
@@ -1761,12 +2088,32 @@ api_b_send_and_recv_udp(InitState) ->
end
end},
#{desc => "close src socket",
- cmd => fun(#{sock_src := Sock}) ->
- ok = socket:close(Sock)
+ cmd => fun(#{domain := local,
+ sock_src := Sock,
+ lsa_src := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() -> maps:remove(lsa_src, State) end,
+ fun() -> State end),
+ {ok, maps:remove(sock_src, State1)};
+ (#{sock_src := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock_src, State)}
end},
#{desc => "close dst socket",
- cmd => fun(#{sock_dst := Sock}) ->
- ok = socket:close(Sock)
+ cmd => fun(#{domain := local,
+ sock_dst := Sock,
+ lsa_dst := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() -> maps:remove(lsa_dst, State) end,
+ fun() -> State end),
+ {ok, maps:remove(sock_dst, State1)};
+ (#{sock_dst := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock_dst, State)}
end},
%% *** We are done ***
@@ -1796,6 +2143,34 @@ api_b_send_and_recv_tcp4(_Config) when is_list(_Config) ->
socket:recv(Sock)
end,
InitState = #{domain => inet,
+ proto => tcp,
+ send => Send,
+ recv => Recv},
+ ok = api_b_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the "common" functions (send and recv)
+%% on an Unix Domain (stream) socket (TCP).
+api_b_send_and_recv_tcpL(suite) ->
+ [];
+api_b_send_and_recv_tcpL(doc) ->
+ [];
+api_b_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_b_send_and_recv_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ Recv = fun(Sock) ->
+ socket:recv(Sock)
+ end,
+ InitState = #{domain => local,
+ proto => default,
send => Send,
recv => Recv},
ok = api_b_send_and_recv_tcp(InitState)
@@ -1828,6 +2203,56 @@ api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) ->
end
end,
InitState = #{domain => inet,
+ proto => tcp,
+ send => Send,
+ recv => Recv},
+ ok = api_b_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the msg functions (sendmsg and recvmsg)
+%% on an Unix Domain (stream) socket (TCP).
+api_b_sendmsg_and_recvmsg_tcpL(suite) ->
+ [];
+api_b_sendmsg_and_recvmsg_tcpL(doc) ->
+ [];
+api_b_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_b_sendmsg_and_recvmsg_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock) of
+ %% On some platforms, the address
+ %% is *not* provided (e.g. FreeBSD)
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ %% On some platforms, the address
+ %% *is* provided (e.g. linux)
+ {ok, #{addr := #{family := local},
+ iov := [Data]}} ->
+ socket:setopt(Sock,
+ otp,
+ debug,
+ false),
+ {ok, Data};
+ {error, _} = ERROR ->
+ socket:setopt(Sock,
+ otp,
+ debug,
+ false),
+ ERROR
+ end
+ end,
+ InitState = #{domain => local,
+ proto => default,
send => Send,
recv => Recv},
ok = api_b_send_and_recv_tcp(InitState)
@@ -1855,13 +2280,13 @@ api_b_send_and_recv_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -1869,9 +2294,19 @@ api_b_send_and_recv_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock, lsa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
+ ?SEV_IPRINT("bound to port: ~w", [Port]),
{ok, State#{lport => Port}};
{error, _} = ERROR ->
ERROR
@@ -1882,7 +2317,12 @@ api_b_send_and_recv_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester, lsa := #{path := Path}}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester, lport := Port}) ->
+ %% This is actually not used for unix domain socket
?SEV_ANNOUNCE_READY(Tester, init, Port),
ok
end},
@@ -1946,12 +2386,29 @@ api_b_send_and_recv_tcp(InitState) ->
end
end},
#{desc => "close connection socket",
- cmd => fun(#{csock := Sock}) ->
- socket:close(Sock)
+ cmd => fun(#{csock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(csock, State)}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := Sock}) ->
- socket:close(Sock)
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := LSock} = State) ->
+ case socket:close(LSock) of
+ ok ->
+ {ok, maps:remove(lsock, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
end},
%% *** We are done ***
@@ -1962,7 +2419,10 @@ api_b_send_and_recv_tcp(InitState) ->
[
%% *** Wait for start order ***
#{desc => "await start (from tester)",
- cmd => fun(State) ->
+ cmd => fun(#{domain := local} = State) ->
+ {Tester, Path} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_path => Path}};
+ (State) ->
{Tester, Port} = ?SEV_AWAIT_START(),
{ok, State#{tester => Tester, server_port => Port}}
end},
@@ -1974,16 +2434,20 @@ api_b_send_and_recv_tcp(InitState) ->
%% *** The init part ***
#{desc => "which server (local) address",
- cmd => fun(#{domain := Domain, server_port := Port} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
- SSA = LSA#{port => Port},
+ cmd => fun(#{domain := local = Domain,
+ server_path := Path} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = #{family => Domain, path => Path},
+ {ok, State#{local_sa => LSA, server_sa => SSA}};
+ (#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
{ok, State#{local_sa => LSA, server_sa => SSA}}
end},
#{desc => "create socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain,
+ proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{sock => Sock}};
{error, _} = ERROR ->
@@ -2054,8 +2518,20 @@ api_b_send_and_recv_tcp(InitState) ->
end
end},
#{desc => "close socket",
- cmd => fun(#{sock := Sock}) ->
- socket:close(Sock)
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(sock, State1)};
+ (#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock, State)}
end},
%% *** We are done ***
@@ -2105,11 +2581,7 @@ api_b_send_and_recv_tcp(InitState) ->
?SEV_ANNOUNCE_CONTINUE(Server, accept),
ok
end},
- #{desc => "sleep",
- cmd => fun(_) ->
- ?SLEEP(?SECS(1)),
- ok
- end},
+ ?SEV_SLEEP(?SECS(1)),
#{desc => "order client to continue (with connect)",
cmd => fun(#{client := Client} = _State) ->
?SEV_ANNOUNCE_CONTINUE(Client, connect),
@@ -2196,6 +2668,3852 @@ api_b_send_and_recv_tcp(InitState) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically establish a TCP connection via an async connect.
+
+api_a_connect_tcp4(suite) ->
+ [];
+api_a_connect_tcp4(doc) ->
+ [];
+api_a_connect_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_connect_tcp4,
+ fun() ->
+ Connect = fun(Sock, SockAddr) ->
+ socket:connect(Sock, SockAddr, nowait)
+ end,
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ Recv = fun(Sock) ->
+ socket:recv(Sock)
+ end,
+ InitState = #{domain => inet,
+ connect => Connect,
+ send => Send,
+ recv => Recv},
+ ok = api_a_connect_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_connect_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
+ {ok, Sock} ->
+ ?SEV_IPRINT("accepted: ~n ~p", [Sock]),
+ {ok, State#{csock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept),
+ ok
+ end},
+
+ #{desc => "await continue (recv_req)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_req)
+ end},
+ #{desc => "recv req",
+ cmd => fun(#{csock := Sock, recv := Recv}) ->
+ case Recv(Sock) of
+ {ok, ?BASIC_REQ} ->
+ ok;
+ {ok, UnexpData} ->
+ {error, {unexpected_data, UnexpData}};
+ {error, _} = ERROR ->
+ %% At the moment there is no way to get
+ %% status or state for the socket...
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_req)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_req),
+ ok
+ end},
+ #{desc => "await continue (send_rep)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_rep)
+ end},
+ #{desc => "send rep",
+ cmd => fun(#{csock := Sock, send := Send}) ->
+ Send(Sock, ?BASIC_REP)
+ end},
+ #{desc => "announce ready (send_rep)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_rep),
+ ok
+ end},
+
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket",
+ cmd => fun(#{csock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(csock, State)}
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(lsock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ ClientSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** The init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% *** The actual test ***
+ #{desc => "await continue (async connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, async_connect)
+ end},
+ #{desc => "connect (async) to server",
+ cmd => fun(#{sock := Sock,
+ server_sa := SSA,
+ connect := Connect} = State) ->
+ case Connect(Sock, SSA) of
+ ok ->
+ ?SEV_IPRINT("ok -> "
+ "unexpected success => SKIP",
+ []),
+ {skip, unexpected_success};
+ {select, {select_info, ST, SR}} ->
+ ?SEV_IPRINT("select ->"
+ "~n tag: ~p"
+ "~n ref: ~p", [ST, SR]),
+ {ok, State#{connect_stag => ST,
+ connect_sref => SR}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (connect select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{sock := Sock, connect_sref := Ref}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ ?SEV_IPRINT("select message ->"
+ "~n ref: ~p", [Ref]),
+ ok
+ after 5000 ->
+ ?SEV_EPRINT("timeout: "
+ "~n message queue: ~p",
+ [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "connect (async) to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA, connect := Connect}) ->
+ case Connect(Sock, SSA) of
+ ok ->
+ ok;
+ {select, SelectInfo} ->
+ {error, {unexpected_select, SelectInfo}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+ #{desc => "get peername",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case socket:peername(Sock) of
+ {ok, SockAddr} ->
+ ?SEV_IPRINT("Peer Name: ~p", [SockAddr]),
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "await continue (send_req)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_req)
+ end},
+ #{desc => "send req",
+ cmd => fun(#{sock := Sock, send := Send}) ->
+ Send(Sock, ?BASIC_REQ)
+ end},
+ #{desc => "announce ready (send_req)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_req),
+ ok
+ end},
+ #{desc => "await continue (recv_rep)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_rep)
+ end},
+ #{desc => "recv rep",
+ cmd => fun(#{sock := Sock, recv := Recv}) ->
+ case Recv(Sock) of
+ {ok, ?BASIC_REP} ->
+ ok;
+ {ok, UnexpData} ->
+ {error, {unexpected_data, UnexpData}};
+ {error, _} = ERROR ->
+ %% At the moment there is no way to get
+ %% status or state for the socket...
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_rep)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_rep),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ State2 = maps:remove(sock, State),
+ State3 = maps:remove(connect_stag, State2),
+ State4 = maps:remove(connect_sref, State3),
+ {ok, State4}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid, server_port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+
+ %% *** The actual test ***
+ #{desc => "order client to continue (async connect)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, async_connect),
+ ok
+ end},
+ #{desc => "await client ready (connect select)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, connect_select)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "await client ready (select)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, select)
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, connect)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, accept)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to recv test req (recv req)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_req),
+ ok
+ end},
+ #{desc => "order client to send test req (send req)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_req),
+ ok
+ end},
+ #{desc => "await client ready (send_req)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_req)
+ end},
+ #{desc => "await server ready (recv_req)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_req)
+ end},
+ #{desc => "order client to recv test rep (send rep)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_rep),
+ ok
+ end},
+ #{desc => "order server to send test rep (send rep)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_rep),
+ ok
+ end},
+ #{desc => "await server ready (send_rep)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_rep)
+ end},
+ #{desc => "await client ready (recv_rep)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_rep)
+ end},
+
+
+ %% *** Termination ***
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start client evaluator"),
+ Client = ?SEV_START("client", ClientSeq, InitState),
+ i("await evaluator(s)"),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv4 UDP (dgram) socket using
+%% sendto and recvfrom. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvfrom,
+%% since its much more difficult to "arrange" for sendto.
+%%
+api_a_sendto_and_recvfrom_udp4(suite) ->
+ [];
+api_a_sendto_and_recvfrom_udp4(doc) ->
+ [];
+api_a_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_a_sendto_and_recvfrom_udp4,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ socket:sendto(Sock, Data, Dest)
+ end,
+ Recv = fun(Sock) ->
+ socket:recvfrom(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv4 UDP (dgram) socket using
+%% sendto and recvfrom. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvmsg,
+%% since its much more difficult to "arrange" for sendmsg.
+%%
+api_a_sendmsg_and_recvmsg_udp4(suite) ->
+ [];
+api_a_sendmsg_and_recvmsg_udp4(doc) ->
+ [];
+api_a_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_a_sendmsg_and_recvmsg_udp4,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ %% ctrl => CMsgHdrs,
+ iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_send_and_recv_udp(InitState) ->
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind socket (to local address)",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ {ok, State#{port => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, local_sa := LSA, port := Port}) ->
+ ServerSA = LSA#{port => Port},
+ ?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, Tag, RecvRef}} ->
+ ?SEV_IPRINT("expected select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [Tag, RecvRef]),
+ {ok, State#{recv_stag => Tag,
+ recv_sref => RecvRef}};
+ {ok, X} ->
+ {error, {unexpected_succes, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{sock := Sock, recv_sref := RecvRef}) ->
+ receive
+ {'$socket', Sock, select, RecvRef} ->
+ ok
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "now read the data (request)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {ok, {Src, ?BASIC_REQ}} ->
+ {ok, State#{req_src => Src}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv request)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_req),
+ ok
+ end},
+
+ #{desc => "await continue (send reply)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_reply)
+ end},
+ #{desc => "send reply",
+ cmd => fun(#{sock := Sock, req_src := Src, send := Send}) ->
+ Send(Sock, ?BASIC_REP, Src)
+ end},
+ #{desc => "announce ready (send)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ State2 = maps:remove(tester, State),
+ State3 = maps:remove(recv_stag, State2),
+ State4 = maps:remove(recv_sref, State3),
+ State5 = maps:remove(req_src, State4),
+ {ok, State5};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ ClientSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, ServerSA} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester,
+ server_sa => ServerSA}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "open socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ Sock = sock_open(Domain, dgram, udp),
+ SA = sock_sockname(Sock),
+ {ok, State#{sock => Sock, sa => SA}}
+ end},
+ #{desc => "bind socket (to local address)",
+ cmd => fun(#{sock := Sock, lsa := LSA}) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (send request)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_req)
+ end},
+ #{desc => "send request",
+ cmd => fun(#{sock := Sock, server_sa := Server, send := Send}) ->
+ Send(Sock, ?BASIC_REQ, Server)
+ end},
+ #{desc => "announce ready (send request)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_req),
+ ok
+ end},
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv reply (with nowait)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, Tag, RecvRef}} ->
+ {ok, State#{recv_stag => Tag,
+ recv_sref => RecvRef}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{sock := Sock, recv_sref := RecvRef}) ->
+ receive
+ {'$socket', Sock, select, RecvRef} ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "now read the data (reply)",
+ cmd => fun(#{sock := Sock, recv := Recv}) ->
+ case Recv(Sock) of
+ {ok, {_Src, ?BASIC_REP}} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv reply)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_rep),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ State2 = maps:remove(tester, State),
+ State3 = maps:remove(recv_stag, State2),
+ State4 = maps:remove(recv_sref, State3),
+ {ok, State4};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, ServerSA} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_sa => ServerSA}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid,
+ server_sa := ServerSA} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, ServerSA),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ %% The actual test
+ #{desc => "order server continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv_select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+
+ #{desc => "order client continue (send request)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_req),
+ ok
+ end},
+ #{desc => "await client ready (send request)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, send_req)
+ end},
+ #{desc => "await server ready (select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, select)
+ end},
+ #{desc => "await server ready (recv request)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_req)
+ end},
+
+ #{desc => "order client continue (recv)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await client ready (recv_select)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, recv_select)
+ end},
+ #{desc => "order server continue (send reply)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_reply),
+ ok
+ end},
+ #{desc => "await server ready (send)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, send)
+ end},
+ #{desc => "await client ready (select)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, select)
+ end},
+ #{desc => "await client ready (recv reply)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, recv_rep)
+ end},
+
+ %% Terminations
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(client, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(server, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ ServerInitState = InitState,
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start client evaluator(s)"),
+ ClientInitState = InitState,
+ Client = ?SEV_START("client", ClientSeq, ClientInitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator"),
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the "common" functions (send and recv)
+%% on an IPv4 TCP (stream) socket. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recv,
+%% since its much more difficult to "arrange" for send.
+%% We *also* test async for accept.
+api_a_send_and_recv_tcp4(suite) ->
+ [];
+api_a_send_and_recv_tcp4(doc) ->
+ [];
+api_a_send_and_recv_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_send_and_recv_tcp4,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the msg functions (sendmsg and recvmsg)
+%% on an IPv4 TCP (stream) socket. But we try to be async. That is, we use
+%% the 'nowait' value for the Timeout argument (and await the eventual
+%% select message). Note that we only do this for the recvmsg,
+%% since its much more difficult to "arrange" for sendmsg.
+%% We *also* test async for accept.
+api_a_sendmsg_and_recvmsg_tcp4(suite) ->
+ [];
+api_a_sendmsg_and_recvmsg_tcp4(doc) ->
+ [];
+api_a_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_sendmsg_and_recvmsg_tcp4,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ send => Send,
+ recv => Recv},
+ ok = api_a_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_send_and_recv_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock, nowait) of
+ {select, {select_info, Tag, Ref}} ->
+ ?SEV_IPRINT("accept select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [Tag, Ref]),
+ {ok, State#{accept_stag => Tag,
+ accept_sref => Ref}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{lsock := Sock, accept_sref := Ref}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "await connection (again)",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock, nowait) of
+ {ok, Sock} ->
+ ?SEV_IPRINT("accepted: "
+ "~n Sock: ~p", [Sock]),
+ {ok, State#{csock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept),
+ ok
+ end},
+
+ #{desc => "await continue (recv request)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_req)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{csock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, Tag, Ref}} ->
+ ?SEV_IPRINT("recv select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [Tag, Ref]),
+ {ok, State#{recv_stag => Tag,
+ recv_sref => Ref}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{csock := Sock, recv_sref := RecvRef}) ->
+ receive
+ {'$socket', Sock, select, RecvRef} ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "now read the data (request)",
+ cmd => fun(#{csock := Sock, recv := Recv} = _State) ->
+ case Recv(Sock) of
+ {ok, ?BASIC_REQ} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv request)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_req),
+ ok
+ end},
+
+ #{desc => "await continue (send reply)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_rep)
+ end},
+ #{desc => "send reply",
+ cmd => fun(#{csock := Sock, send := Send}) ->
+ Send(Sock, ?BASIC_REP)
+ end},
+ #{desc => "announce ready (send reply)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_rep),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket",
+ cmd => fun(#{csock := Sock}) ->
+ socket:close(Sock)
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ ClientSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** The init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% *** The actual test ***
+ #{desc => "await continue (connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, connect)
+ end},
+ #{desc => "connect to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA}) ->
+ socket:connect(Sock, SSA)
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+
+ #{desc => "await continue (send request)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_req)
+ end},
+ #{desc => "send request (to server)",
+ cmd => fun(#{sock := Sock, send := Send}) ->
+ ok = Send(Sock, ?BASIC_REQ)
+ end},
+ #{desc => "announce ready (send request)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_req),
+ ok
+ end},
+
+ #{desc => "try recv reply (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, Tag, Ref}} ->
+ ?SEV_IPRINT("recv select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [Tag, Ref]),
+ {ok, State#{recv_stag => Tag,
+ recv_sref => Ref}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{sock := Sock, recv_sref := RecvRef}) ->
+ receive
+ {'$socket', Sock, select, RecvRef} ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, select),
+ ok
+ end},
+ #{desc => "now read the data (reply)",
+ cmd => fun(#{sock := Sock, recv := Recv}) ->
+ {ok, ?BASIC_REP} = Recv(Sock),
+ ok
+ end},
+ #{desc => "announce ready (recv reply)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_rep),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid, server_port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ %% *** The actual test ***
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "await server ready (accept select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, accept_select)
+ end},
+ #{desc => "order client to continue (with connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect),
+ ok
+ end},
+ #{desc => "await server ready (select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, select)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, accept)
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, connect)
+ end},
+
+ #{desc => "order server to continue (recv request)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv_req),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+ #{desc => "order client to continue (send request)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_req),
+ ok
+ end},
+ #{desc => "await client ready (send request)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_req)
+ end},
+ #{desc => "await server ready (select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, select)
+ end},
+ #{desc => "await server ready (recv request)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, recv_req)
+ end},
+
+ #{desc => "order client to continue (recv reply)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv_rep),
+ ok
+ end},
+ #{desc => "await client ready (recv select)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, recv_select)
+ end},
+ #{desc => "order server to continue (send reply)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_rep),
+ ok
+ end},
+ #{desc => "await server ready (send reply)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, send_rep)
+ end},
+ #{desc => "await client ready (select)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, select)
+ end},
+ #{desc => "await client ready (reply recv)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_rep)
+ end},
+
+
+ %% *** Termination ***
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start client evaluator"),
+ Client = ?SEV_START("client", ClientSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvfrom,
+%% wait some time and then cancel.
+%%
+api_a_recvfrom_cancel_udp4(suite) ->
+ [];
+api_a_recvfrom_cancel_udp4(doc) ->
+ [];
+api_a_recvfrom_cancel_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvfrom_cancel_udp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvfrom(Sock, 0, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_recv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvmsg,
+%% wait some time and then cancel.
+%%
+api_a_recvmsg_cancel_udp4(suite) ->
+ [];
+api_a_recvmsg_cancel_udp4(doc) ->
+ [];
+api_a_recvmsg_cancel_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvmsg_cancel_udp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_recv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_recv_cancel_udp(InitState) ->
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind socket (to local address)",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ {ok, State#{port => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, local_sa := LSA, port := Port}) ->
+ ServerSA = LSA#{port => Port},
+ ?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message (without success)",
+ cmd => fun(#{sock := Sock}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}}
+ after 5000 ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (no select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, no_select),
+ ok
+ end},
+ #{desc => "await continue (cancel)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, cancel)
+ end},
+ #{desc => "cancel",
+ cmd => fun(#{sock := Sock, recv_select_info := SelectInfo}) ->
+ ok = socket:cancel(Sock, SelectInfo)
+ end},
+ #{desc => "announce ready (cancel)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, cancel),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ State2 = maps:remove(tester, State),
+ State3 = maps:remove(recv_stag, State2),
+ State4 = maps:remove(recv_sref, State3),
+ State5 = maps:remove(req_src, State4),
+ {ok, State5};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ ok = socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, ServerSA} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_sa => ServerSA}}
+ end},
+
+ %% The actual test
+ #{desc => "order server continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+ #{desc => "await server ready (no select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, no_select)
+ end},
+ #{desc => "order server continue (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, cancel),
+ ok
+ end},
+ #{desc => "await server ready (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, cancel)
+ end},
+
+ %% Terminations
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(server, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ ServerInitState = InitState,
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{server => Server#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator"),
+ ok = ?SEV_AWAIT_FINISH([Server, Tester]).
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to accept,
+%% wait some time and then cancel.
+%%
+api_a_accept_cancel_tcp4(suite) ->
+ [];
+api_a_accept_cancel_tcp4(doc) ->
+ [];
+api_a_accept_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_accept_cancel_tcp4,
+ fun() ->
+ Accept = fun(Sock) ->
+ case socket:accept(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ accept => Accept},
+ ok = api_a_accept_cancel_tcp(InitState)
+ end).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_accept_cancel_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock, accept := Accept} = State) ->
+ case Accept(LSock) of
+ {select, {select_info, T, R} = SelectInfo} ->
+ ?SEV_IPRINT("accept select: "
+ "~n T: ~p"
+ "~n R: ~p", [T, R]),
+ {ok, State#{accept_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_select),
+ ok
+ end},
+ #{desc => "await select message (without success)",
+ cmd => fun(#{lsock := Sock}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}}
+ after 5000 ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (no select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, no_select),
+ ok
+ end},
+ #{desc => "await continue (cancel)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, cancel)
+ end},
+ #{desc => "cancel",
+ cmd => fun(#{lsock := Sock, accept_select_info := SelectInfo}) ->
+ ok = socket:cancel(Sock, SelectInfo)
+ end},
+ #{desc => "announce ready (cancel)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, cancel),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% *** The actual test ***
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "await server ready (accept select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, accept_select)
+ end},
+ #{desc => "await server ready (no select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, no_select)
+ end},
+ #{desc => "order server to continue (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, cancel),
+ ok
+ end},
+ #{desc => "await server ready (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, cancel)
+ end},
+
+ %% *** Termination ***
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recv,
+%% wait some time and then cancel.
+%%
+api_a_recv_cancel_tcp4(suite) ->
+ [];
+api_a_recv_cancel_tcp4(doc) ->
+ [];
+api_a_recv_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recv_cancel_tcp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_recv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvmsg,
+%% wait some time and then cancel.
+%%
+api_a_recvmsg_cancel_tcp4(suite) ->
+ [];
+api_a_recvmsg_cancel_tcp4(doc) ->
+ [];
+api_a_recvmsg_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvmsg_cancel_tcp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recvmsg(Sock, nowait)
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_recv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_recv_cancel_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
+ {ok, CSock} ->
+ {ok, State#{csock => CSock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept),
+ ok
+ end},
+
+ #{desc => "await continue (nowait recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{csock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, T, R} = SelectInfo} ->
+ ?SEV_IPRINT("recv select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [T, R]),
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{csock := Sock}) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}}
+ after 5000 ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (no select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, no_select),
+ ok
+ end},
+ #{desc => "await continue (cancel)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, cancel)
+ end},
+ #{desc => "cancel",
+ cmd => fun(#{csock := Sock, recv_select_info := SelectInfo}) ->
+ ok = socket:cancel(Sock, SelectInfo)
+ end},
+ #{desc => "announce ready (cancel)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, cancel),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close connection socket",
+ cmd => fun(#{csock := Sock}) ->
+ socket:close(Sock)
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ ClientSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** The init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% *** The actual test ***
+ #{desc => "await continue (connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, connect)
+ end},
+ #{desc => "connect to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA}) ->
+ socket:connect(Sock, SSA)
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid, server_port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ %% *** The actual test ***
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "order client to continue (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect),
+ ok
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, connect)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, accept)
+ end},
+
+ #{desc => "order server to continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+ #{desc => "await server ready (no select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, no_select)
+ end},
+ #{desc => "order server to continue (send request)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, cancel),
+ ok
+ end},
+ #{desc => "await server ready (cancel)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, server, cancel)
+ end},
+
+ %% *** Termination ***
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start client evaluator"),
+ Client = ?SEV_START("client", ClientSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvfrom
+%% (from *several* processes), wait some time and then cancel.
+%% This should result in abort messages to the 'other' processes.
+%%
+api_a_mrecvfrom_cancel_udp4(suite) ->
+ [];
+api_a_mrecvfrom_cancel_udp4(doc) ->
+ [];
+api_a_mrecvfrom_cancel_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvfrom_cancel_udp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvfrom(Sock, 0, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvmsg
+%% (from *several* processes), wait some time and then cancel.
+%% This should result in abort messages to the 'other' processes.
+%%
+api_a_mrecvmsg_cancel_udp4(suite) ->
+ [];
+api_a_mrecvmsg_cancel_udp4(doc) ->
+ [];
+api_a_mrecvmsg_cancel_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvmsg_cancel_udp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_mrecv_cancel_udp(InitState) ->
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind socket (to local address)",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ {ok, State#{port => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, sock := Sock}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Sock),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await abort message",
+ cmd => fun(#{sock := Sock,
+ recv_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ State2 = maps:remove(tester, State),
+ State3 = maps:remove(recv_stag, State2),
+ State4 = maps:remove(recv_sref, State3),
+ State5 = maps:remove(req_src, State4),
+ {ok, State5};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ AltServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, Sock} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, sock => Sock}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await abort message",
+ cmd => fun(#{sock := Sock,
+ recv_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ ?SEV_IPRINT("terminating"),
+ State1 = maps:remove(recv_select_info, State),
+ State2 = maps:remove(tester, State1),
+ State3 = maps:remove(sock, State2),
+ {ok, State3};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 1",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 2",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Sock} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{sock => Sock}}
+ end},
+
+ %% Start the alt-server 1
+ #{desc => "order alt-server 1 start",
+ cmd => fun(#{alt_server1 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (init)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, alt_server1, init)
+ end},
+
+ %% Start the alt-server 2
+ #{desc => "order alt-server 2 start",
+ cmd => fun(#{alt_server2 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (init)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, alt_server2, init)
+ end},
+
+
+ %% The actual test
+ #{desc => "order server continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+
+ #{desc => "order alt-server 1 continue (recv)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (recv select)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, recv_select)
+ end},
+
+ #{desc => "order alt-server 2 continue (recv)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (recv select)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, recv_select)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "close the socket",
+ cmd => fun(#{sock := Sock} = _State) ->
+ socket:close(Sock)
+ end},
+
+ #{desc => "await server ready (abort)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, abort)
+ end},
+ #{desc => "await alt-server 1 ready (abort)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, abort)
+ end},
+ #{desc => "await alt-server 2 ready (abort)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, abort)
+ end},
+
+ %% Terminations
+ #{desc => "order alt-server 2 to terminate",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 2 termination",
+ cmd => fun(#{alt_server2 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server2, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order alt-server 1 to terminate",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 1 termination",
+ cmd => fun(#{alt_server1 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server1, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(server, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start alt-server 1 evaluator"),
+ AltServer1 = ?SEV_START("alt_server1", AltServerSeq, InitState),
+
+ i("start alt-server 2 evaluator"),
+ AltServer2 = ?SEV_START("alt_server2", AltServerSeq, InitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ alt_server1 => AltServer1#ev.pid,
+ alt_server2 => AltServer2#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, AltServer1, AltServer2, Tester]).
+
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to accept
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes.
+%%
+api_a_maccept_cancel_tcp4(suite) ->
+ [];
+api_a_maccept_cancel_tcp4(doc) ->
+ [];
+api_a_maccept_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_maccept_cancel_tcp4,
+ fun() ->
+ Accept = fun(Sock) ->
+ case socket:accept(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet,
+ accept => Accept},
+ ok = api_a_maccept_cancel_tcp(InitState)
+ end).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_maccept_cancel_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lsock := Sock}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Sock),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock, accept := Accept} = State) ->
+ case Accept(LSock) of
+ {select, {select_info, T, R} = SelectInfo} ->
+ ?SEV_IPRINT("accept select: "
+ "~n T: ~p"
+ "~n R: ~p", [T, R]),
+ {ok, State#{accept_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_select),
+ ok
+ end},
+ #{desc => "await select message (without success)",
+ cmd => fun(#{lsock := Sock,
+ accept_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(lsock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ AltServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, Sock} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, lsock => Sock}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "try accept request (with nowait, expect select)",
+ cmd => fun(#{lsock := Sock, accept := Accept} = State) ->
+ case Accept(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{accept_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_select),
+ ok
+ end},
+ #{desc => "await abort message",
+ cmd => fun(#{lsock := Sock,
+ accept_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ ?SEV_IPRINT("terminating"),
+ State1 = maps:remove(tester, State),
+ State2 = maps:remove(accept_select_info, State1),
+ State3 = maps:remove(lsock, State2),
+ {ok, State3};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 1",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 2",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Sock} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{sock => Sock}}
+ end},
+
+ %% Start the alt-server 1
+ #{desc => "order alt-server 1 start",
+ cmd => fun(#{alt_server1 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (init)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, alt_server1, init)
+ end},
+
+ %% Start the alt-server 2
+ #{desc => "order alt-server 2 start",
+ cmd => fun(#{alt_server2 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (init)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, alt_server2, init)
+ end},
+
+
+ %% *** The actual test ***
+ #{desc => "order server continue (accept)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ #{desc => "await server ready (accept select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, accept_select)
+ end},
+
+ #{desc => "order alt-server 1 continue (accept)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (accept select)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, accept_select)
+ end},
+
+ #{desc => "order alt-server 2 continue (accept)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (accept select)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, accept_select)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "close the socket",
+ cmd => fun(#{sock := Sock} = _State) ->
+ socket:close(Sock)
+ end},
+
+ #{desc => "await server ready (abort)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, abort)
+ end},
+ #{desc => "await alt-server 1 ready (abort)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, abort)
+ end},
+ #{desc => "await alt-server 2 ready (abort)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, abort)
+ end},
+
+
+ %% *** Termination ***
+ #{desc => "order alt-server 2 to terminate",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 2 termination",
+ cmd => fun(#{alt_server2 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server2, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order alt-server 1 to terminate",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 1 termination",
+ cmd => fun(#{alt_server1 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server1, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ State1 = maps:remove(server, State),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start alt-server 1 evaluator"),
+ AltServer1 = ?SEV_START("alt_server1", AltServerSeq, InitState),
+
+ i("start alt-server 2 evaluator"),
+ AltServer2 = ?SEV_START("alt_server2", AltServerSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ alt_server1 => AltServer1#ev.pid,
+ alt_server2 => AltServer2#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, AltServer1, AltServer2, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recv
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes.
+%%
+api_a_mrecv_cancel_tcp4(suite) ->
+ [];
+api_a_mrecv_cancel_tcp4(doc) ->
+ [];
+api_a_mrecv_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecv_cancel_tcp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make multiple async (Timeout = nowait) call(s) to recvmsg
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes.
+%%
+api_a_mrecvmsg_cancel_tcp4(suite) ->
+ [];
+api_a_mrecvmsg_cancel_tcp4(doc) ->
+ [];
+api_a_mrecvmsg_cancel_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvmsg_cancel_tcp4,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recvmsg(Sock, nowait)
+ end,
+ InitState = #{domain => inet,
+ recv => Recv},
+ ok = api_a_mrecv_cancel_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_mrecv_cancel_tcp(InitState) ->
+ process_flag(trap_exit, true),
+ ServerSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ Tester = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
+ end},
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{lsock := LSock, lsa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "await connection (nowait)",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
+ {ok, CSock} ->
+ {ok, State#{csock => CSock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester, csock := Sock}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept, Sock),
+ ok
+ end},
+
+ #{desc => "await continue (nowait recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{csock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, {select_info, T, R} = SelectInfo} ->
+ ?SEV_IPRINT("recv select: "
+ "~n Tag: ~p"
+ "~n Ref: ~p", [T, R]),
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await select message",
+ cmd => fun(#{csock := Sock,
+ recv_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ok
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ AltServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, Sock} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, sock => Sock}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv)
+ end},
+ #{desc => "try recv request (with nowait, expect select)",
+ cmd => fun(#{sock := Sock, recv := Recv} = State) ->
+ case Recv(Sock) of
+ {select, SelectInfo} ->
+ {ok, State#{recv_select_info => SelectInfo}};
+ {ok, X} ->
+ {error, {unexpected_select_info, X}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv_select)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_select),
+ ok
+ end},
+ #{desc => "await abort message",
+ cmd => fun(#{sock := Sock,
+ recv_select_info := {select_info, _, Ref}} = State) ->
+ receive
+ {'$socket', Sock, select, Ref} ->
+ {error, {unexpected_select, Ref}};
+ {'$socket', Sock, abort, {Ref, closed}} ->
+ {ok, maps:remove(sock, State)}
+ after 5000 ->
+ ?SEV_EPRINT("message queue: ~p", [mq()]),
+ {error, timeout}
+ end
+ end},
+ #{desc => "announce ready (abort)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, abort),
+ ok
+ end},
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ ?SEV_IPRINT("terminating"),
+ State1 = maps:remove(recv_select_info, State),
+ State2 = maps:remove(tester, State1),
+ State3 = maps:remove(sock, State2),
+ {ok, State3};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ ClientSeq =
+ [
+ %% *** Wait for start order ***
+ #{desc => "await start (from tester)",
+ cmd => fun(State) ->
+ {Tester, Port} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, server_port => Port}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester}) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** The init part ***
+ #{desc => "which server (local) address",
+ cmd => fun(#{domain := Domain, server_port := Port} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
+ {ok, State#{local_sa => LSA, server_sa => SSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% *** The actual test ***
+ #{desc => "await continue (connect)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, connect)
+ end},
+ #{desc => "connect to server",
+ cmd => fun(#{sock := Sock, server_sa := SSA}) ->
+ socket:connect(Sock, SSA)
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+
+ %% *** Termination ***
+ #{desc => "await terminate",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 1",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor alt-server 2",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid, server_port := Port} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Port),
+ ok
+ end},
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
+ end},
+
+ #{desc => "order server to continue (with accept)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, accept),
+ ok
+ end},
+ #{desc => "order client to continue (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect),
+ ok
+ end},
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_AWAIT_READY(Pid, client, connect)
+ end},
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Pid} = State) ->
+ {ok, Sock} = ?SEV_AWAIT_READY(Pid, server, accept),
+ {ok, State#{sock => Sock}}
+ end},
+
+ %% Start the alt server 1
+ #{desc => "order alt-server 1 start",
+ cmd => fun(#{alt_server1 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (init)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, init)
+ end},
+
+ %% Start the alt server 2
+ #{desc => "order alt-server 2 start",
+ cmd => fun(#{alt_server2 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (init)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, init)
+ end},
+
+
+ %% *** The actual test ***
+ #{desc => "order server continue (recv)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await server ready (recv select)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, recv_select)
+ end},
+
+ #{desc => "order alt-server 1 continue (recv)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await alt-server 1 ready (recv select)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, recv_select)
+ end},
+
+ #{desc => "order alt-server 2 continue (recv)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv),
+ ok
+ end},
+ #{desc => "await alt-server 2 ready (recv select)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, recv_select)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "close the socket",
+ cmd => fun(#{sock := Sock} = _State) ->
+ socket:close(Sock)
+ end},
+
+ #{desc => "await server ready (abort)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, server, abort)
+ end},
+ #{desc => "await alt-server 1 ready (abort)",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server1, abort)
+ end},
+ #{desc => "await alt-server 2 ready (abort)",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, alt_server2, abort)
+ end},
+
+ %% Terminations
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await client termination",
+ cmd => fun(#{client := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(client, State),
+ {ok, State1}
+ end},
+
+ #{desc => "order alt-server 2 to terminate",
+ cmd => fun(#{alt_server2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 2 termination",
+ cmd => fun(#{alt_server2 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server2, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order alt-server 1 to terminate",
+ cmd => fun(#{alt_server1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await alt-server 1 termination",
+ cmd => fun(#{alt_server1 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(alt_server1, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ State1 = maps:remove(server, State),
+ {ok, State1};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ i("start server evaluator"),
+ Server = ?SEV_START("server", ServerSeq, InitState),
+
+ i("start alt-server 1 evaluator"),
+ AltServer1 = ?SEV_START("alt_server1", AltServerSeq, InitState),
+
+ i("start alt-server 2 evaluator"),
+ AltServer2 = ?SEV_START("alt_server2", AltServerSeq, InitState),
+
+ i("start client evaluator"),
+ Client = ?SEV_START("client", ClientSeq, InitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{server => Server#ev.pid,
+ alt_server1 => AltServer1#ev.pid,
+ alt_server2 => AltServer2#ev.pid,
+ client => Client#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Server, AltServer1, AltServer2, Client, Tester]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
%% API OPTIONS %%
@@ -2530,8 +6848,7 @@ api_opt_simple_otp_rcvbuf_option() ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
@@ -2776,8 +7093,7 @@ api_opt_simple_otp_rcvbuf_option() ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create socket",
@@ -3173,7 +7489,7 @@ api_opt_simple_otp_controlling_process(suite) ->
api_opt_simple_otp_controlling_process(doc) ->
[];
api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) ->
- ?TT(?SECS(5)),
+ ?TT(?SECS(30)),
tc_try(api_opt_simple_otp_controlling_process,
fun() -> api_opt_simple_otp_controlling_process() end).
@@ -3418,6 +7734,320 @@ api_opt_simple_otp_controlling_process() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests that the add_mambership and drop_membership ip options work.
+%% We create one server and two clients. The server only send messages,
+%% the clients only receives messages.
+%% An UDP datagram is forbidden (RFC 1122) from having a source address
+%% that is a multicast address (or a broadcast address).
+%% So, the server create a socket "for sending" and the clients sockets
+%% "for receiving".
+%% Sending socket: Bound to the local address (and any port).
+%% When sending, the dest will be the multicast address
+%% and port of the receiving socket.
+%% Receiving socket: Bound to the multicast address and port.
+api_opt_ip_add_drop_membership(suite) ->
+ [];
+api_opt_ip_add_drop_membership(doc) ->
+ ["OTP-15908 (ERL-980)"];
+api_opt_ip_add_drop_membership(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_ip_add_drop_membership,
+ fun() ->
+ has_ip_add_membership_support(),
+ has_ip_drop_membership_support(),
+ has_ip_multicast_support()
+ end,
+ fun() -> api_opt_ip_add_drop_membership() end).
+
+
+api_opt_ip_add_drop_membership() ->
+ Set = fun(S, Key, Val) ->
+ socket:setopt(S, ip, Key, Val)
+ end,
+ AddMembership = fun(S, Val) -> Set(S, add_membership, Val) end,
+ DropMembership = fun(S, Val) -> Set(S, drop_membership, Val) end,
+
+ ServerSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start",
+ cmd => fun(State) ->
+ {Tester, MSA} = ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester, msa => MSA}}
+ end},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{local_sa => LSA}}
+ end},
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make recv socket reuse addr",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case socket:setopt(Sock, socket, reuseaddr, true) of
+ ok ->
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Failed set reuseaddr: "
+ "~n ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "bind recv socket to multicast address",
+ cmd => fun(#{sock := Sock, msa := MSA} = State) ->
+ case socket:bind(Sock, MSA) of
+ {ok, Port} ->
+ ?SEV_IPRINT("bound to:"
+ "~n ~p", [Port]),
+ {ok, State#{msa => MSA#{port => Port}}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (add_membership)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, add_membership)
+ end},
+ #{desc => "add membership",
+ cmd => fun(#{sock := Sock,
+ msa := #{addr := MAddr},
+ local_sa := #{addr := Addr}} = State) ->
+ MReq = #{multiaddr => MAddr,
+ interface => Addr},
+ ?SEV_IPRINT("try add membership to:"
+ "~n ~p", [MReq]),
+ case AddMembership(Sock, MReq) of
+ ok ->
+ ?SEV_IPRINT("membership added"),
+ {ok, State#{mreq => MReq}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Failed adding membership to: "
+ "~n ~p"
+ "~n Reason: ~p",
+ [MReq, Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (add-membership)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, add_membership),
+ ok
+ end},
+
+ #{desc => "await continue (drop_membership)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, drop_membership)
+ end},
+ #{desc => "drop membership",
+ cmd => fun(#{sock := Sock,
+ mreq := MReq} = State) ->
+ ?SEV_IPRINT("try drop membership from:"
+ "~n ~p", [MReq]),
+ case DropMembership(Sock, MReq) of
+ ok ->
+ ?SEV_IPRINT("membership dropped"),
+ {ok, maps:remove(mreq, State)};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Failed drop membership from: "
+ "~n ~p"
+ "~n Reason: ~p",
+ [MReq, Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (drop-membership)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, drop_membership),
+ ok
+ end},
+
+
+ %% Termination
+ #{desc => "await terminate (from tester)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ ok ->
+ {ok, maps:remove(tester, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor server",
+ cmd => fun(#{server := Server} = _State) ->
+ _MRef = erlang:monitor(process, Server),
+ ok
+ end},
+
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid, msa := MSA} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, MSA),
+ ok
+ end},
+ #{desc => "await server ready (init)",
+ cmd => fun(#{server := Pid} = _State) ->
+ case ?SEV_AWAIT_READY(Pid, server, init) of
+ ok ->
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Start of server failed: "
+ "~n ~p", [Reason]),
+ ERROR
+ end
+ end},
+
+
+ %% *** The actual test ***
+ #{desc => "order server to continue (add-membership)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, add_membership),
+ ok
+ end},
+ #{desc => "await server ready (add-membership)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, add_membership)
+ end},
+
+ #{desc => "order server to continue (drop-membership)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, drop_membership),
+ ok
+ end},
+ #{desc => "await server ready (drop-membership)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, drop_membership)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ %% *** Termination ***
+ #{desc => "order server terminate",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Server),
+ ok
+ end},
+ #{desc => "await server termination",
+ cmd => fun(#{server := Server} = State) ->
+ ?SEV_AWAIT_TERMINATION(Server),
+ {ok, maps:remove(server, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ i("get multicast address"),
+ Domain = inet,
+ MAddr = which_ip_multicast_address(),
+ MSA = #{family => Domain, addr => MAddr},
+
+ i("start server evaluator"),
+ ServerInitState = #{domain => Domain},
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start tester evaluator"),
+ TesterInitState = #{domain => Domain,
+ msa => MSA,
+ server => Server#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester, Server]).
+
+
+
+which_ip_multicast_address() ->
+ which_multicast_address(inet).
+
+which_multicast_address(Domain) ->
+ case os:type() of
+ {unix, linux} ->
+ WhichMAddr = fun([_, _, MAddr]) -> MAddr end,
+ which_multicast_address2(Domain, WhichMAddr);
+
+ {unix, sunos} ->
+ WhichMAddr = fun([_, MAddr, _]) -> MAddr end,
+ which_multicast_address2(Domain, WhichMAddr);
+
+ Type ->
+ not_supported({multicast, Type})
+ end.
+
+%% Note that the 'netstat -g' table looks different on linux and SunOS
+%% Linux: IfName - RefCnt - Group
+%% SunOS: IfName - Group - RefCnt
+
+which_multicast_address2(Domain, WhichMAddr) ->
+ IfName = which_local_host_ifname(Domain),
+ NetstatGroupsStr = os:cmd("netstat -g | grep " ++ IfName),
+ NetstatGroups0 = string:tokens(NetstatGroupsStr, [$\n]),
+ NetstatGroups = [string:tokens(G, [$ ]) || G <- NetstatGroups0],
+ MAddrs = [WhichMAddr(NetstatGroup) || NetstatGroup <-
+ NetstatGroups],
+ which_multicast_address3(Domain, MAddrs).
+
+which_multicast_address3(_Domain, []) ->
+ not_supported({multicast, no_valid_addrs});
+which_multicast_address3(Domain, [MAddrStr|MAddrs]) ->
+ %% Even on linux some of these are not actually addresses, but
+ %% "host names", such as all-systems.mcast.net. But both
+ %% address strings, such as "224.0.0.251" and host name strings
+ %% gets translated into an address by the inet:inet:getaddr/2.
+ case inet:getaddr(MAddrStr, Domain) of
+ {ok, MAddr} ->
+ MAddr;
+ {error, _} ->
+ which_multicast_address3(Domain, MAddrs)
+ end.
+
+which_local_host_ifname(Domain) ->
+ case which_local_host_info(Domain) of
+ {ok, {Name, _Addr, _Flags}} ->
+ Name;
+ {error, Reason} ->
+ not_supported({multicast, Reason})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
%% API OPERATIONS WITH TIMEOUT %%
@@ -3434,11 +8064,11 @@ api_to_connect_tcp4(suite) ->
api_to_connect_tcp4(doc) ->
[];
api_to_connect_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
Cond = fun() -> api_to_connect_cond() end,
tc_try(api_to_connect_tcp4,
Cond,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet,
backlog => 1,
timeout => 5000,
@@ -3454,7 +8084,9 @@ api_to_connect_cond() ->
%% So, just to simplify, we require atleast 4.15
api_to_connect_cond({unix, linux}, {Maj, Min, _Rev}) ->
if
- ((Maj >= 4) andalso (Min >= 15)) ->
+ (Maj > 4) ->
+ ok;
+ ((Maj =:= 4) andalso (Min >= 15)) ->
ok;
true ->
skip("TC does not work")
@@ -3491,10 +8123,10 @@ api_to_connect_tcp6(suite) ->
api_to_connect_tcp6(doc) ->
[];
api_to_connect_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_connect_tcp6,
fun() -> has_support_ipv6(), api_to_connect_cond() end,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet6,
backlog => 1,
timeout => 5000,
@@ -3531,8 +8163,7 @@ api_to_connect_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
@@ -3603,8 +8234,7 @@ api_to_connect_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create node",
@@ -3754,8 +8384,7 @@ api_to_connect_tcp(InitState) ->
end},
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "order server start",
@@ -3906,9 +8535,7 @@ api_toc_tcp_client_await_terminate(Parent) ->
end.
api_to_connect_tcp_await_timeout(To, ServerSA, Domain, ConLimit) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
NewSock = fun() ->
S = case socket:open(Domain, stream, tcp) of
{ok, Sock} ->
@@ -3986,9 +8613,9 @@ api_to_accept_tcp4(suite) ->
api_to_accept_tcp4(doc) ->
[];
api_to_accept_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_accept_tcp4,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet, timeout => 5000},
ok = api_to_accept_tcp(InitState)
end).
@@ -4003,10 +8630,10 @@ api_to_accept_tcp6(suite) ->
api_to_accept_tcp6(doc) ->
[];
api_to_accept_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_accept_tcp4,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet6, timeout => 5000},
ok = api_to_accept_tcp(InitState)
end).
@@ -4020,8 +8647,7 @@ api_to_accept_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create (listen) socket",
@@ -4145,8 +8771,7 @@ api_to_maccept_tcp(InitState) ->
end},
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create (listen) socket",
@@ -4602,9 +9227,9 @@ api_to_recv_tcp4(suite) ->
api_to_recv_tcp4(doc) ->
[];
api_to_recv_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recv_tcp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recv(Sock, 0, To) end,
InitState = #{domain => inet,
recv => Recv,
@@ -4622,12 +9247,12 @@ api_to_recv_tcp6(suite) ->
api_to_recv_tcp6(doc) ->
[];
api_to_recv_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recv_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
case socket:supports(ipv6) of
true ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) ->
socket:recv(Sock, 0, To)
end,
@@ -4663,8 +9288,7 @@ api_to_receive_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
@@ -4782,10 +9406,8 @@ api_to_receive_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain, server_port := Port} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
- SSA = LSA#{port => Port},
+ LSA = which_local_socket_addr(Domain),
+ SSA = LSA#{port => Port},
{ok, State#{local_sa => LSA, server_sa => SSA}}
end},
#{desc => "create socket",
@@ -4961,9 +9583,9 @@ api_to_recvfrom_udp4(suite) ->
api_to_recvfrom_udp4(doc) ->
[];
api_to_recvfrom_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvfrom_udp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end,
InitState = #{domain => inet,
recv => Recv,
@@ -4981,10 +9603,10 @@ api_to_recvfrom_udp6(suite) ->
api_to_recvfrom_udp6(doc) ->
[];
api_to_recvfrom_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvfrom_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end,
InitState = #{domain => inet6,
recv => Recv,
@@ -5001,8 +9623,7 @@ api_to_receive_udp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create socket",
@@ -5078,9 +9699,9 @@ api_to_recvmsg_udp4(suite) ->
api_to_recvmsg_udp4(doc) ->
[];
api_to_recvmsg_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvmsg_udp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet,
recv => Recv,
@@ -5098,10 +9719,10 @@ api_to_recvmsg_udp6(suite) ->
api_to_recvmsg_udp6(doc) ->
[];
api_to_recvmsg_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvmsg_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
recv => Recv,
@@ -5119,9 +9740,9 @@ api_to_recvmsg_tcp4(suite) ->
api_to_recvmsg_tcp4(doc) ->
[];
api_to_recvmsg_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvmsg_tcp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet,
recv => Recv,
@@ -5139,10 +9760,10 @@ api_to_recvmsg_tcp6(suite) ->
api_to_recvmsg_tcp6(doc) ->
[];
api_to_recvmsg_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(api_to_recvmsg_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
recv => Recv,
@@ -5170,9 +9791,9 @@ sc_cpe_socket_cleanup_tcp4(suite) ->
sc_cpe_socket_cleanup_tcp4(doc) ->
[];
sc_cpe_socket_cleanup_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
tc_try(sc_cpe_socket_cleanup_tcp4,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet,
type => stream,
protocol => tcp},
@@ -5190,10 +9811,10 @@ sc_cpe_socket_cleanup_tcp6(suite) ->
sc_cpe_socket_cleanup_tcp6(doc) ->
[];
sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
tc_try(sc_cpe_socket_cleanup_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet6,
type => stream,
protocol => tcp},
@@ -5204,6 +9825,27 @@ sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test that the sockets are cleaned up
%% ("removed") when the controlling process terminates (without explicitly
+%% calling the close function). For a Unix Domain (stream) socket (TCP).
+
+sc_cpe_socket_cleanup_tcpL(suite) ->
+ [];
+sc_cpe_socket_cleanup_tcpL(doc) ->
+ [];
+sc_cpe_socket_cleanup_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(sc_cpe_socket_cleanup_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ type => stream,
+ protocol => default},
+ ok = sc_cpe_socket_cleanup(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sockets are cleaned up
+%% ("removed") when the controlling process terminates (without explicitly
%% calling the close function). For a IPv4 UDP (dgram) socket.
sc_cpe_socket_cleanup_udp4(suite) ->
@@ -5211,9 +9853,9 @@ sc_cpe_socket_cleanup_udp4(suite) ->
sc_cpe_socket_cleanup_udp4(doc) ->
[];
sc_cpe_socket_cleanup_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
tc_try(sc_cpe_socket_cleanup_udp4,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet,
type => dgram,
protocol => udp},
@@ -5232,10 +9874,10 @@ sc_cpe_socket_cleanup_udp6(suite) ->
sc_cpe_socket_cleanup_udp6(doc) ->
[];
sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
tc_try(sc_cpe_socket_cleanup_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet6,
type => dgram,
protocol => udp},
@@ -5244,6 +9886,28 @@ sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sockets are cleaned up
+%% ("removed") when the controlling process terminates (without explicitly
+%% calling the close function). For a Unix Domain (dgram) socket (UDP).
+
+sc_cpe_socket_cleanup_udpL(suite) ->
+ [];
+sc_cpe_socket_cleanup_udpL(doc) ->
+ [];
+sc_cpe_socket_cleanup_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(sc_cpe_socket_cleanup_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ type => dgram,
+ protocol => default},
+ ok = sc_cpe_socket_cleanup(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sc_cpe_socket_cleanup(InitState) ->
OwnerSeq =
@@ -5386,12 +10050,11 @@ sc_lc_recv_response_tcp4(suite) ->
sc_lc_recv_response_tcp4(doc) ->
[];
sc_lc_recv_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_recv_response_tcp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_lc_receive_response_tcp(InitState)
@@ -5408,13 +10071,12 @@ sc_lc_recv_response_tcp6(suite) ->
sc_lc_recv_response_tcp6(doc) ->
[];
sc_lc_recv_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_recv_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet6,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_lc_receive_response_tcp(InitState)
@@ -5422,6 +10084,28 @@ sc_lc_recv_response_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the recv function.
+%% Socket is Unix Domain (stream) socket.
+
+sc_lc_recv_response_tcpL(suite) ->
+ [];
+sc_lc_recv_response_tcpL(doc) ->
+ [];
+sc_lc_recv_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_lc_recv_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock) -> socket:recv(Sock) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
+ ok = sc_lc_receive_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sc_lc_receive_response_tcp(InitState) ->
%% This (acceptor) is the server that accepts connections.
@@ -5444,15 +10128,13 @@ sc_lc_receive_response_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
- {ok, State#{local_sa => LSA}}
+ LSA = which_local_socket_addr(Domain),
+ {ok, State#{lsa => LSA}}
end},
#{desc => "create (listen) socket",
cmd => fun(#{domain := Domain,
- type := Type,
protocol := Proto} = State) ->
- case socket:open(Domain, Type, Proto) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -5460,9 +10142,22 @@ sc_lc_receive_response_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := LSA} = _State) ->
+ ?SEV_IPRINT("bind to LSA: "
+ "~n ~p", [LSA]),
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock,
+ lsa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
+ ?SEV_IPRINT("bound to port: ~w", [Port]),
{ok, State#{lport => Port}};
{error, _} = ERROR ->
ERROR
@@ -5473,7 +10168,12 @@ sc_lc_receive_response_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ lsa := #{path := Path}}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester, lport := Port}) ->
?SEV_ANNOUNCE_READY(Tester, init, Port),
ok
end},
@@ -5494,7 +10194,8 @@ sc_lc_receive_response_tcp(InitState) ->
cmd => fun(#{lsock := LSock} = State) ->
case socket:accept(LSock) of
{ok, Sock} ->
- ?SEV_IPRINT("connection accepted"),
+ ?SEV_IPRINT("connection accepted: "
+ "~n ~p", [socket:sockname(Sock)]),
{ok, State#{csock => Sock}};
{error, _} = ERROR ->
ERROR
@@ -5525,9 +10226,8 @@ sc_lc_receive_response_tcp(InitState) ->
?SEV_AWAIT_CONTINUE(Tester, tester, close),
ok
end},
- #{desc => "close the connection socket",
+ #{desc => "close connection socket",
cmd => fun(#{csock := Sock} = State) ->
- %% ok = socket:setopt(Sock, otp, debug, true),
case socket:close(Sock) of
ok ->
{ok, maps:remove(csock, State)};
@@ -5551,8 +10251,19 @@ sc_lc_receive_response_tcp(InitState) ->
ERROR
end
end},
- #{desc => "close socket",
- cmd => fun(#{lsock := Sock} = State) ->
+ #{desc => "close listen socket",
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ lsa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->maps:remove(lsa, State) end,
+ fun() -> State end),
+ State2 = maps:remove(lsock, State1),
+ State3 = maps:remove(lport, State2),
+ {ok, State3};
+ (#{lsock := Sock} = State) ->
case socket:close(Sock) of
ok ->
State1 = maps:remove(lsock, State),
@@ -5667,15 +10378,13 @@ sc_lc_receive_response_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create socket",
cmd => fun(#{domain := Domain,
- type := Type,
protocol := Proto} = State) ->
- case socket:open(Domain, Type, Proto) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{sock => Sock}};
{error, _} = ERROR ->
@@ -5684,6 +10393,8 @@ sc_lc_receive_response_tcp(InitState) ->
end},
#{desc => "bind socket to local address",
cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ ?SEV_IPRINT("bind to LSA: "
+ "~n ~p", [LSA]),
case socket:bind(Sock, LSA) of
{ok, _} ->
ok;
@@ -5699,7 +10410,19 @@ sc_lc_receive_response_tcp(InitState) ->
%% The actual test
#{desc => "await continue (connect)",
- cmd => fun(#{tester := Tester, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local = Domain,
+ tester := Tester} = State) ->
+ case ?SEV_AWAIT_CONTINUE(Tester, tester, connect) of
+ {ok, ServerPath} ->
+ ?SEV_IPRINT("Server Path: "
+ "~n ~s", [ServerPath]),
+ ServerSA = #{family => Domain,
+ path => ServerPath},
+ {ok, State#{server_sa => ServerSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{tester := Tester, local_sa := LSA} = State) ->
case ?SEV_AWAIT_CONTINUE(Tester, tester, connect) of
{ok, Port} ->
ServerSA = LSA#{port => Port},
@@ -5729,7 +10452,18 @@ sc_lc_receive_response_tcp(InitState) ->
end
end},
#{desc => "close socket",
- cmd => fun(#{sock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ sock_close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(sock, State1)};
+ (#{sock := Sock} = State) ->
sock_close(Sock),
{ok, maps:remove(sock, State)}
end},
@@ -5776,8 +10510,8 @@ sc_lc_receive_response_tcp(InitState) ->
#{desc => "await acceptor ready (init)",
cmd => fun(#{acceptor := Pid} = State) ->
case ?SEV_AWAIT_READY(Pid, acceptor, init) of
- {ok, Port} ->
- {ok, State#{lport => Port}};
+ {ok, PortOrPath} ->
+ {ok, State#{server_info => PortOrPath}};
{error, _} = ERROR ->
ERROR
end
@@ -5834,8 +10568,8 @@ sc_lc_receive_response_tcp(InitState) ->
end},
?SEV_SLEEP(?SECS(1)),
#{desc => "order client to continue (connect)",
- cmd => fun(#{client := Pid, lport := Port} = _State) ->
- ?SEV_ANNOUNCE_CONTINUE(Pid, connect, Port),
+ cmd => fun(#{client := Pid, server_info := Info} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect, Info),
ok
end},
#{desc => "await acceptor ready (accept)",
@@ -6002,12 +10736,11 @@ sc_lc_recvfrom_response_udp4(suite) ->
sc_lc_recvfrom_response_udp4(doc) ->
[];
sc_lc_recvfrom_response_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_lc_recvfrom_response_udp4,
fun() ->
- ?TT(?SECS(30)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end,
InitState = #{domain => inet,
- type => dgram,
protocol => udp,
recv => Recv},
ok = sc_lc_receive_response_udp(InitState)
@@ -6024,13 +10757,36 @@ sc_lc_recvfrom_response_udp6(suite) ->
sc_lc_recvfrom_response_udp6(doc) ->
[];
sc_lc_recvfrom_response_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_lc_recvfrom_response_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(30)),
Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end,
- InitState = #{domain => inet6,
- recv => Recv},
+ InitState = #{domain => inet6,
+ protocol => udp,
+ recv => Recv},
+ ok = sc_lc_receive_response_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the recv function.
+%% Socket is Unix Domainm (dgram) socket.
+
+sc_lc_recvfrom_response_udpL(suite) ->
+ [];
+sc_lc_recvfrom_response_udpL(doc) ->
+ [];
+sc_lc_recvfrom_response_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(sc_lc_recvfrom_response_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
ok = sc_lc_receive_response_udp(InitState)
end).
@@ -6055,20 +10811,25 @@ sc_lc_receive_response_udp(InitState) ->
%% *** Init part ***
#{desc => "local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "open socket",
- cmd => fun(#{domain := Domain} = State) ->
- Sock = sock_open(Domain, dgram, udp),
+ cmd => fun(#{domain := Domain, protocol := Proto} = State) ->
+ Sock = sock_open(Domain, dgram, Proto),
SA = sock_sockname(Sock),
{ok, State#{sock => Sock, sa => SA}}
end},
#{desc => "bind socket",
cmd => fun(#{sock := Sock, local_sa := LSA}) ->
- sock_bind(Sock, LSA),
- ok
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("src bound"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("src bind failed: ~p", [Reason]),
+ ERROR
+ end
end},
#{desc => "announce ready (init)",
cmd => fun(#{tester := Tester, sock := Sock}) ->
@@ -6107,7 +10868,18 @@ sc_lc_receive_response_udp(InitState) ->
ok = ?SEV_AWAIT_CONTINUE(Tester, tester, close)
end},
#{desc => "close socket",
- cmd => fun(#{sock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(sock, State1)};
+ (#{sock := Sock} = State) ->
case socket:close(Sock) of
ok ->
{ok, maps:remove(sock, State)};
@@ -6400,9 +11172,9 @@ sc_lc_receive_response_udp(InitState) ->
i("start 'tester' evaluator"),
TesterInitState = #{prim_server => PrimServer#ev.pid,
- sec_server1 => SecServer1#ev.pid,
- sec_server2 => SecServer2#ev.pid,
- sec_server3 => SecServer3#ev.pid},
+ sec_server1 => SecServer1#ev.pid,
+ sec_server2 => SecServer2#ev.pid,
+ sec_server3 => SecServer3#ev.pid},
Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
i("await evaluator"),
@@ -6422,12 +11194,11 @@ sc_lc_recvmsg_response_tcp4(suite) ->
sc_lc_recvmsg_response_tcp4(doc) ->
[];
sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_recvmsg_response_tcp4,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_lc_receive_response_tcp(InitState)
@@ -6444,13 +11215,12 @@ sc_lc_recvmsg_response_tcp6(suite) ->
sc_lc_recvmsg_response_tcp6(doc) ->
[];
sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_recvmsg_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet6,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_lc_receive_response_tcp(InitState)
@@ -6460,6 +11230,28 @@ sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test what happens when a socket is
%% locally closed while the process is calling the recvmsg function.
+%% Socket is Unix Domain (stream) socket.
+
+sc_lc_recvmsg_response_tcpL(suite) ->
+ [];
+sc_lc_recvmsg_response_tcpL(doc) ->
+ [];
+sc_lc_recvmsg_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_recvmsg_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock) -> socket:recvmsg(Sock) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
+ ok = sc_lc_receive_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the recvmsg function.
%% Socket is IPv4.
sc_lc_recvmsg_response_udp4(suite) ->
@@ -6471,8 +11263,9 @@ sc_lc_recvmsg_response_udp4(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
- InitState = #{domain => inet,
- recv => Recv},
+ InitState = #{domain => inet,
+ protocol => udp,
+ recv => Recv},
ok = sc_lc_receive_response_udp(InitState)
end).
@@ -6492,8 +11285,32 @@ sc_lc_recvmsg_response_udp6(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(10)),
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
- InitState = #{domain => inet6,
- recv => Recv},
+ InitState = #{domain => inet6,
+ protocol => udp,
+ recv => Recv},
+ ok = sc_lc_receive_response_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the recvmsg function.
+%% Socket is Unix Domain (dgram) socket.
+
+sc_lc_recvmsg_response_udpL(suite) ->
+ [];
+sc_lc_recvmsg_response_udpL(doc) ->
+ [];
+sc_lc_recvmsg_response_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_recvmsg_response_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
ok = sc_lc_receive_response_udp(InitState)
end).
@@ -6511,11 +11328,10 @@ sc_lc_acceptor_response_tcp4(suite) ->
sc_lc_acceptor_response_tcp4(doc) ->
[];
sc_lc_acceptor_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_acceptor_response_tcp4,
fun() ->
- ?TT(?SECS(10)),
InitState = #{domain => inet,
- type => stream,
protocol => tcp},
ok = sc_lc_acceptor_response_tcp(InitState)
end).
@@ -6533,18 +11349,39 @@ sc_lc_acceptor_response_tcp6(suite) ->
sc_lc_acceptor_response_tcp6(doc) ->
[];
sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
tc_try(sc_lc_acceptor_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
- InitState = #{domain => inet,
- type => stream,
+ InitState = #{domain => inet6,
protocol => tcp},
ok = sc_lc_acceptor_response_tcp(InitState)
end).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% locally closed while the process is calling the accept function.
+%% We test what happens with a non-controlling_process also, since we
+%% git the setup anyway.
+%% Socket is Unix Domain (stream) socket.
+
+sc_lc_acceptor_response_tcpL(suite) ->
+ [];
+sc_lc_acceptor_response_tcpL(doc) ->
+ [];
+sc_lc_acceptor_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_lc_acceptor_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ protocol => default},
+ ok = sc_lc_acceptor_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sc_lc_acceptor_response_tcp(InitState) ->
PrimAcceptorSeq =
@@ -6564,15 +11401,13 @@ sc_lc_acceptor_response_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{lsa => LSA}}
end},
#{desc => "create (listen) socket",
cmd => fun(#{domain := Domain,
- type := Type,
protocol := Proto} = State) ->
- case socket:open(Domain, Type, Proto) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{sock => Sock}};
{error, _} = ERROR ->
@@ -6609,8 +11444,8 @@ sc_lc_acceptor_response_tcp(InitState) ->
end
end},
#{desc => "await connection",
- cmd => fun(#{sock := Sock, timeout := Timeout} = _State) ->
- case socket:accept(Sock, Timeout) of
+ cmd => fun(#{sock := LSock, timeout := Timeout} = _State) ->
+ case socket:accept(LSock, Timeout) of
{error, timeout} ->
ok;
{ok, Sock} ->
@@ -6631,7 +11466,25 @@ sc_lc_acceptor_response_tcp(InitState) ->
ok = ?SEV_AWAIT_CONTINUE(Tester, tester, close)
end},
#{desc => "close socket",
- cmd => fun(#{sock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ lsa := #{path := Path}} = State) ->
+ case socket:close(Sock) of
+ ok ->
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(lsa, State)
+ end,
+ fun() ->
+ State
+ end),
+ {ok, maps:remove(sock, State1)};
+ {error, _} = ERROR ->
+ unlink_path(Path),
+ ERROR
+ end;
+ (#{sock := Sock} = State) ->
case socket:close(Sock) of
ok ->
{ok, maps:remove(sock, State)};
@@ -6946,12 +11799,11 @@ sc_rc_recv_response_tcp4(suite) ->
sc_rc_recv_response_tcp4(doc) ->
[];
sc_rc_recv_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rc_recv_response_tcp4,
fun() ->
- ?TT(?SECS(30)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_rc_receive_response_tcp(InitState)
@@ -6968,13 +11820,12 @@ sc_rc_recv_response_tcp6(suite) ->
sc_rc_recv_response_tcp6(doc) ->
[];
sc_rc_recv_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rc_recv_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recv(Sock) end,
InitState = #{domain => inet6,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_rc_receive_response_tcp(InitState)
@@ -6982,6 +11833,28 @@ sc_rc_recv_response_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% remotely closed while the process is calling the recv function.
+%% Socket is Unix Domain (stream) socket.
+
+sc_rc_recv_response_tcpL(suite) ->
+ [];
+sc_rc_recv_response_tcpL(doc) ->
+ [];
+sc_rc_recv_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(sc_rc_recv_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock) -> socket:recv(Sock) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
+ ok = sc_rc_receive_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sc_rc_receive_response_tcp(InitState) ->
%% Each connection are handled by handler processes.
@@ -7004,13 +11877,12 @@ sc_rc_receive_response_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain, protocol := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -7018,7 +11890,17 @@ sc_rc_receive_response_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock,
+ local_sa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
{ok, State#{lport => Port}};
@@ -7031,7 +11913,15 @@ sc_rc_receive_response_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ local_sa := LSA}) ->
+ %% Actually we only need to send the path,
+ %% but to keep it simple, we send the "same"
+ %% as for non-local.
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester, local_sa := LSA, lport := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -7213,7 +12103,25 @@ sc_rc_receive_response_tcp(InitState) ->
{ok, State2}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := LSock} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := #{path := Path}} = State) ->
+ case socket:close(LSock) of
+ ok ->
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(lsa, State)
+ end,
+ fun() ->
+ State
+ end),
+ {ok, maps:remove(lsock, State1)};
+ {error, _} = ERROR ->
+ unlink_path(Path),
+ ERROR
+ end;
+ (#{lsock := LSock} = State) ->
case socket:close(LSock) of
ok ->
{ok, maps:remove(lsock, State)};
@@ -7270,8 +12178,10 @@ sc_rc_receive_response_tcp(InitState) ->
ok
end},
#{desc => "order remote client to start",
- cmd => fun(#{rclient := Client, server_sa := ServerSA}) ->
- ?SEV_ANNOUNCE_START(Client, ServerSA),
+ cmd => fun(#{rclient := Client,
+ server_sa := ServerSA,
+ protocol := Proto}) ->
+ ?SEV_ANNOUNCE_START(Client, {ServerSA, Proto}),
ok
end},
#{desc => "await remote client ready",
@@ -7672,16 +12582,16 @@ sc_rc_tcp_client_start(Node) ->
sc_rc_tcp_client(Parent) ->
sc_rc_tcp_client_init(Parent),
- ServerSA = sc_rc_tcp_client_await_start(Parent),
+ {ServerSA, Proto} = sc_rc_tcp_client_await_start(Parent),
Domain = maps:get(family, ServerSA),
- Sock = sc_rc_tcp_client_create(Domain),
- sc_rc_tcp_client_bind(Sock, Domain),
+ Sock = sc_rc_tcp_client_create(Domain, Proto),
+ Path = sc_rc_tcp_client_bind(Sock, Domain),
sc_rc_tcp_client_announce_ready(Parent, init),
sc_rc_tcp_client_await_continue(Parent, connect),
sc_rc_tcp_client_connect(Sock, ServerSA),
sc_rc_tcp_client_announce_ready(Parent, connect),
sc_rc_tcp_client_await_continue(Parent, close),
- sc_rc_tcp_client_close(Sock),
+ sc_rc_tcp_client_close(Sock, Path),
sc_rc_tcp_client_announce_ready(Parent, close),
Reason = sc_rc_tcp_client_await_terminate(Parent),
?SEV_IPRINT("terminate"),
@@ -7697,9 +12607,9 @@ sc_rc_tcp_client_await_start(Parent) ->
i("sc_rc_tcp_client_await_start -> entry"),
?SEV_AWAIT_START(Parent).
-sc_rc_tcp_client_create(Domain) ->
+sc_rc_tcp_client_create(Domain, Proto) ->
i("sc_rc_tcp_client_create -> entry"),
- case socket:open(Domain, stream, tcp) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
case socket:getopt(Sock, otp, fd) of
{ok, FD} ->
@@ -7714,12 +12624,17 @@ sc_rc_tcp_client_create(Domain) ->
sc_rc_tcp_client_bind(Sock, Domain) ->
i("sc_rc_tcp_client_bind -> entry"),
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
- ok;
+ case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ Path;
+ {ok, _} ->
+ undefined;
+ {error, Reason1} ->
+ exit({sockname, Reason1})
+ end;
{error, Reason} ->
exit({bind, Reason})
end.
@@ -7741,13 +12656,17 @@ sc_rc_tcp_client_connect(Sock, ServerSA) ->
exit({connect, Reason})
end.
-sc_rc_tcp_client_close(Sock) ->
+sc_rc_tcp_client_close(Sock, Path) ->
i("sc_rc_tcp_client_close -> entry"),
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("failed closing: "
+ "~n Reason: ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
sc_rc_tcp_client_await_terminate(Parent) ->
@@ -7827,12 +12746,11 @@ sc_rc_recvmsg_response_tcp4(suite) ->
sc_rc_recvmsg_response_tcp4(doc) ->
[];
sc_rc_recvmsg_response_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rc_recvmsg_response_tcp4,
fun() ->
- ?TT(?SECS(30)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_rc_receive_response_tcp(InitState)
@@ -7849,13 +12767,12 @@ sc_rc_recvmsg_response_tcp6(suite) ->
sc_rc_recvmsg_response_tcp6(doc) ->
[];
sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rc_recvmsg_response_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(10)),
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet6,
- type => stream,
protocol => tcp,
recv => Recv},
ok = sc_rc_receive_response_tcp(InitState)
@@ -7863,6 +12780,28 @@ sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% remotely closed while the process is calling the recvmsg function.
+%% Socket is Unix Domain (stream) socket.
+
+sc_rc_recvmsg_response_tcpL(suite) ->
+ [];
+sc_rc_recvmsg_response_tcpL(doc) ->
+ [];
+sc_rc_recvmsg_response_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(sc_rc_recvmsg_response_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ Recv = fun(Sock) -> socket:recvmsg(Sock) end,
+ InitState = #{domain => local,
+ protocol => default,
+ recv => Recv},
+ ok = sc_rc_receive_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test what happens when a socket is
%% remotely closed while the process is calling the recv function.
%% The remote client sends data, then shutdown(write) and then the
@@ -7872,6 +12811,7 @@ sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
%% To minimize the chance of "weirdness", we should really have test cases
%% where the two sides of the connection is on different machines. But for
%% now, we will make do with different VMs on the same host.
+%% This would of course not work for Unix Domain sockets.
%%
sc_rs_recv_send_shutdown_receive_tcp4(suite) ->
@@ -7879,9 +12819,9 @@ sc_rs_recv_send_shutdown_receive_tcp4(suite) ->
sc_rs_recv_send_shutdown_receive_tcp4(doc) ->
[];
sc_rs_recv_send_shutdown_receive_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(sc_rs_recv_send_shutdown_receive_tcp4,
fun() ->
- ?TT(?SECS(30)),
MsgData = ?DATA,
Recv = fun(Sock) ->
socket:recv(Sock)
@@ -7890,6 +12830,7 @@ sc_rs_recv_send_shutdown_receive_tcp4(_Config) when is_list(_Config) ->
socket:send(Sock, Data)
end,
InitState = #{domain => inet,
+ proto => tcp,
recv => Recv,
send => Send,
data => MsgData},
@@ -7921,6 +12862,39 @@ sc_rs_recv_send_shutdown_receive_tcp6(_Config) when is_list(_Config) ->
socket:send(Sock, Data)
end,
InitState = #{domain => inet6,
+ proto => tcp,
+ recv => Recv,
+ send => Send,
+ data => MsgData},
+ ok = sc_rs_send_shutdown_receive_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% remotely closed while the process is calling the recv function.
+%% The remote client sends data, then shutdown(write) and then the
+%% reader attempts a recv.
+%% Socket is Unix Domain (stream) socket.
+
+sc_rs_recv_send_shutdown_receive_tcpL(suite) ->
+ [];
+sc_rs_recv_send_shutdown_receive_tcpL(doc) ->
+ [];
+sc_rs_recv_send_shutdown_receive_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_rs_recv_send_shutdown_receive_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ MsgData = ?DATA,
+ Recv = fun(Sock) ->
+ socket:recv(Sock)
+ end,
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ InitState = #{domain => local,
+ proto => default,
recv => Recv,
send => Send,
data => MsgData},
@@ -7952,13 +12926,12 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
i("get local address for ~p", [Domain]),
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -7966,9 +12939,19 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ local_sa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock, local_sa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
+ ?SEV_IPRINT("bound to port: ~w", [Port]),
{ok, State#{lport => Port}};
{error, _} = ERROR ->
ERROR
@@ -7979,7 +12962,11 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester, local_sa := LSA}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester, local_sa := LSA, lport := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -8090,7 +13077,18 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
{ok, State2}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := LSock} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := LSock} = State) ->
case socket:close(LSock) of
ok ->
{ok, maps:remove(lsock, State)};
@@ -8148,8 +13146,10 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
ok
end},
#{desc => "order remote client to start",
- cmd => fun(#{rclient := Client, server_sa := ServerSA}) ->
- ?SEV_ANNOUNCE_START(Client, ServerSA),
+ cmd => fun(#{rclient := Client,
+ proto := Proto,
+ server_sa := ServerSA}) ->
+ ?SEV_ANNOUNCE_START(Client, {ServerSA, Proto}),
ok
end},
#{desc => "await remote client ready",
@@ -8479,12 +13479,14 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
i("start server evaluator"),
ServerInitState = #{domain => maps:get(domain, InitState),
+ proto => maps:get(proto, InitState),
recv => maps:get(recv, InitState)},
Server = ?SEV_START("server", ServerSeq, ServerInitState),
i("start client evaluator"),
ClientInitState = #{host => local_host(),
domain => maps:get(domain, InitState),
+ proto => maps:get(proto, InitState),
send => maps:get(send, InitState)},
Client = ?SEV_START("client", ClientSeq, ClientInitState),
@@ -8506,10 +13508,10 @@ sc_rs_tcp_client_start(Node, Send) ->
sc_rs_tcp_client(Parent, Send) ->
sc_rs_tcp_client_init(Parent),
- ServerSA = sc_rs_tcp_client_await_start(Parent),
+ {ServerSA, Proto} = sc_rs_tcp_client_await_start(Parent),
Domain = maps:get(family, ServerSA),
- Sock = sc_rs_tcp_client_create(Domain),
- sc_rs_tcp_client_bind(Sock, Domain),
+ Sock = sc_rs_tcp_client_create(Domain, Proto),
+ Path = sc_rs_tcp_client_bind(Sock, Domain),
sc_rs_tcp_client_announce_ready(Parent, init),
sc_rs_tcp_client_await_continue(Parent, connect),
sc_rs_tcp_client_connect(Sock, ServerSA),
@@ -8521,7 +13523,7 @@ sc_rs_tcp_client(Parent, Send) ->
sc_rs_tcp_client_shutdown(Sock),
sc_rs_tcp_client_announce_ready(Parent, shutdown),
sc_rs_tcp_client_await_continue(Parent, close),
- sc_rs_tcp_client_close(Sock),
+ sc_rs_tcp_client_close(Sock, Path),
sc_rs_tcp_client_announce_ready(Parent, close),
Reason = sc_rs_tcp_client_await_terminate(Parent),
?SEV_IPRINT("terminate"),
@@ -8537,9 +13539,9 @@ sc_rs_tcp_client_await_start(Parent) ->
i("sc_rs_tcp_client_await_start -> entry"),
?SEV_AWAIT_START(Parent).
-sc_rs_tcp_client_create(Domain) ->
+sc_rs_tcp_client_create(Domain, Proto) ->
i("sc_rs_tcp_client_create -> entry"),
- case socket:open(Domain, stream, tcp) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
Sock;
{error, Reason} ->
@@ -8548,12 +13550,17 @@ sc_rs_tcp_client_create(Domain) ->
sc_rs_tcp_client_bind(Sock, Domain) ->
i("sc_rs_tcp_client_bind -> entry"),
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
- ok;
+ case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ Path;
+ {ok, _} ->
+ undefined;
+ {error, Reason1} ->
+ exit({sockname, Reason1})
+ end;
{error, Reason} ->
exit({bind, Reason})
end.
@@ -8600,13 +13607,17 @@ sc_rs_tcp_client_shutdown(Sock) ->
exit({shutdown, Reason})
end.
-sc_rs_tcp_client_close(Sock) ->
+sc_rs_tcp_client_close(Sock, Path) ->
i("sc_rs_tcp_client_close -> entry"),
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("failed closing: "
+ "~n Reason: ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
sc_rs_tcp_client_await_terminate(Parent) ->
@@ -8711,12 +13722,11 @@ sc_rs_recvmsg_send_shutdown_receive_tcp4(_Config) when is_list(_Config) ->
MsgHdr = #{iov => [Data]},
socket:sendmsg(Sock, MsgHdr)
end,
- InitState = #{domain => inet,
- type => stream,
- protocol => tcp,
- recv => Recv,
- send => Send,
- data => MsgData},
+ InitState = #{domain => inet,
+ proto => tcp,
+ recv => Recv,
+ send => Send,
+ data => MsgData},
ok = sc_rs_send_shutdown_receive_tcp(InitState)
end).
@@ -8748,15 +13758,62 @@ sc_rs_recvmsg_send_shutdown_receive_tcp6(_Config) when is_list(_Config) ->
end
end,
Send = fun(Sock, Data) when is_binary(Data) ->
- MsgHdr = #{iov => [Data]},
- socket:sendmsg(Sock, MsgHdr)
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
end,
- InitState = #{domain => inet6,
- type => stream,
- protocol => tcp,
- recv => Recv,
- send => Send,
- data => MsgData},
+ InitState = #{domain => inet6,
+ proto => tcp,
+ recv => Recv,
+ send => Send,
+ data => MsgData},
+ ok = sc_rs_send_shutdown_receive_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test what happens when a socket is
+%% remotely closed while the process is calling the recvmsg function.
+%% The remote client sends data, then shutdown(write) and then the
+%% reader attempts a recv.
+%% Socket is UNix Domain (stream) socket.
+
+sc_rs_recvmsg_send_shutdown_receive_tcpL(suite) ->
+ [];
+sc_rs_recvmsg_send_shutdown_receive_tcpL(doc) ->
+ [];
+sc_rs_recvmsg_send_shutdown_receive_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(sc_rs_recvmsg_send_shutdown_receive_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ {ok, CWD} = file:get_cwd(),
+ ?SEV_IPRINT("CWD: ~s", [CWD]),
+ MsgData = ?DATA,
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock) of
+ %% On some platforms, the address
+ %% is *not* provided (e.g. FreeBSD)
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ %% On some platforms, the address
+ %% *is* provided (e.g. linux)
+ {ok, #{addr := #{family := local},
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ Send = fun(Sock, Data) when is_binary(Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ InitState = #{domain => local,
+ proto => default,
+ recv => Recv,
+ send => Send,
+ data => MsgData},
ok = sc_rs_send_shutdown_receive_tcp(InitState)
end).
@@ -8773,10 +13830,11 @@ traffic_send_and_recv_chunks_tcp4(suite) ->
traffic_send_and_recv_chunks_tcp4(doc) ->
[];
traffic_send_and_recv_chunks_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(traffic_send_and_recv_chunks_tcp4,
fun() ->
- ?TT(?SECS(30)),
- InitState = #{domain => inet},
+ InitState = #{domain => inet,
+ proto => tcp},
ok = traffic_send_and_recv_chunks_tcp(InitState)
end).
@@ -8794,11 +13852,34 @@ traffic_send_and_recv_chunks_tcp6(suite) ->
traffic_send_and_recv_chunks_tcp6(doc) ->
[];
traffic_send_and_recv_chunks_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
tc_try(traffic_send_and_recv_chunks_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(30)),
- InitState = #{domain => inet6},
+ InitState = #{domain => inet6,
+ proto => tcp},
+ ok = traffic_send_and_recv_chunks_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the send and recv functions
+%% behave as expected when sending and/or reading chunks.
+%% First send data in one "big" chunk, and read it in "small" chunks.
+%% Second, send in a bunch of "small" chunks, and read in one "big" chunk.
+%% Socket is UNix Domain (Stream) socket.
+
+traffic_send_and_recv_chunks_tcpL(suite) ->
+ [];
+traffic_send_and_recv_chunks_tcpL(doc) ->
+ [];
+traffic_send_and_recv_chunks_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(traffic_send_and_recv_chunks_tcp6,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default},
ok = traffic_send_and_recv_chunks_tcp(InitState)
end).
@@ -8823,13 +13904,12 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -8837,7 +13917,17 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ local_sa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock,
+ local_sa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
{ok, State#{lport => Port}};
@@ -8850,7 +13940,14 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ local_sa := LSA}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester,
+ local_sa := LSA,
+ lport := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -9045,9 +14142,20 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
{ok, maps:remove(csock, State)}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
+ ok = socket:close(Sock),
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := Sock} = State) ->
(catch socket:close(Sock)),
- {ok, maps:remove(lsock, State)}
+ {ok, maps:remove(lsock, State)}
end},
%% *** We are done ***
@@ -9098,8 +14206,10 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
ok
end},
#{desc => "order remote client to start",
- cmd => fun(#{rclient := Client, server_sa := ServerSA}) ->
- ?SEV_ANNOUNCE_START(Client, ServerSA),
+ cmd => fun(#{rclient := Client,
+ server_sa := ServerSA,
+ proto := Proto}) ->
+ ?SEV_ANNOUNCE_START(Client, {ServerSA, Proto}),
ok
end},
#{desc => "await remote client ready",
@@ -9654,14 +14764,14 @@ traffic_snr_tcp_client_start(Node) ->
erlang:spawn(Node, Fun).
traffic_snr_tcp_client(Parent) ->
- {Sock, ServerSA} = traffic_snr_tcp_client_init(Parent),
+ {Sock, ServerSA, Path} = traffic_snr_tcp_client_init(Parent),
traffic_snr_tcp_client_announce_ready(Parent, init),
traffic_snr_tcp_client_await_continue(Parent, connect),
traffic_snr_tcp_client_connect(Sock, ServerSA),
traffic_snr_tcp_client_announce_ready(Parent, connect),
traffic_snr_tcp_client_send_loop(Parent, Sock),
Reason = traffic_snr_tcp_client_await_terminate(Parent),
- traffic_snr_tcp_client_close(Sock),
+ traffic_snr_tcp_client_close(Sock, Path),
exit(Reason).
@@ -9687,19 +14797,19 @@ traffic_snr_tcp_client_init(Parent) ->
put(sname, "rclient"),
?SEV_IPRINT("init"),
_MRef = erlang:monitor(process, Parent),
- ServerSA = traffic_snr_tcp_client_await_start(Parent),
+ {ServerSA, Proto} = traffic_snr_tcp_client_await_start(Parent),
Domain = maps:get(family, ServerSA),
- Sock = traffic_snr_tcp_client_create(Domain),
- traffic_snr_tcp_client_bind(Sock, Domain),
- {Sock, ServerSA}.
+ Sock = traffic_snr_tcp_client_create(Domain, Proto),
+ Path = traffic_snr_tcp_client_bind(Sock, Domain),
+ {Sock, ServerSA, Path}.
traffic_snr_tcp_client_await_start(Parent) ->
i("traffic_snr_tcp_client_await_start -> entry"),
?SEV_AWAIT_START(Parent).
-traffic_snr_tcp_client_create(Domain) ->
+traffic_snr_tcp_client_create(Domain, Proto) ->
i("traffic_snr_tcp_client_create -> entry"),
- case socket:open(Domain, stream, tcp) of
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
Sock;
{error, Reason} ->
@@ -9708,12 +14818,17 @@ traffic_snr_tcp_client_create(Domain) ->
traffic_snr_tcp_client_bind(Sock, Domain) ->
i("traffic_snr_tcp_client_bind -> entry"),
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
- ok;
+ case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ Path;
+ {ok, _} ->
+ undefined;
+ {error, Reason1} ->
+ exit({sockname, Reason1})
+ end;
{error, Reason} ->
exit({bind, Reason})
end.
@@ -9734,13 +14849,17 @@ traffic_snr_tcp_client_connect(Sock, ServerSA) ->
exit({connect, Reason})
end.
-traffic_snr_tcp_client_close(Sock) ->
+traffic_snr_tcp_client_close(Sock, Path) ->
i("traffic_snr_tcp_client_close -> entry"),
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("failed closing: "
+ "~n Reason: ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
traffic_snr_tcp_client_await_terminate(Parent) ->
@@ -9768,12 +14887,13 @@ traffic_ping_pong_small_send_and_recv_tcp4(suite) ->
traffic_ping_pong_small_send_and_recv_tcp4(doc) ->
[];
traffic_ping_pong_small_send_and_recv_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_send_and_recv_tcp4,
fun() ->
- ?TT(?SECS(15)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9795,13 +14915,42 @@ traffic_ping_pong_small_send_and_recv_tcp6(suite) ->
traffic_ping_pong_small_send_and_recv_tcp6(doc) ->
[];
traffic_ping_pong_small_send_and_recv_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_send_and_recv_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(15)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the send and recv functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'small' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_small_send_and_recv_tcpL(suite) ->
+ [];
+traffic_ping_pong_small_send_and_recv_tcpL(doc) ->
+ [];
+traffic_ping_pong_small_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ Msg = l2b(?TPP_SMALL),
+ Num = ?TPP_SMALL_NUM,
+ tc_try(traffic_ping_pong_small_send_and_recv_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9828,6 +14977,7 @@ traffic_ping_pong_medium_send_and_recv_tcp4(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9855,6 +15005,36 @@ traffic_ping_pong_medium_send_and_recv_tcp6(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_send_and_recv_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the send and recv functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'medium' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_medium_send_and_recv_tcpL(suite) ->
+ [];
+traffic_ping_pong_medium_send_and_recv_tcpL(doc) ->
+ [];
+traffic_ping_pong_medium_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ Msg = l2b(?TPP_MEDIUM),
+ Num = ?TPP_MEDIUM_NUM,
+ tc_try(traffic_ping_pong_medium_send_and_recv_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9876,12 +15056,13 @@ traffic_ping_pong_large_send_and_recv_tcp4(suite) ->
traffic_ping_pong_large_send_and_recv_tcp4(doc) ->
[];
traffic_ping_pong_large_send_and_recv_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(45)),
Msg = l2b(?TPP_LARGE),
Num = ?TPP_LARGE_NUM,
tc_try(traffic_ping_pong_large_send_and_recv_tcp4,
fun() ->
- ?TT(?SECS(45)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
@@ -9909,11 +15090,53 @@ traffic_ping_pong_large_send_and_recv_tcp6(_Config) when is_list(_Config) ->
fun() ->
?TT(?SECS(45)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_send_and_recv_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the send and recv functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'large' message test case, for UNix Domain (stream) socket.
+
+traffic_ping_pong_large_send_and_recv_tcpL(suite) ->
+ [];
+traffic_ping_pong_large_send_and_recv_tcpL(doc) ->
+ [];
+traffic_ping_pong_large_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(45)),
+ Msg = l2b(?TPP_LARGE),
+ Num = ?TPP_LARGE_NUM,
+ tc_try(traffic_ping_pong_large_send_and_recv_tcpL,
+ fun() ->
+ has_support_unix_domain_socket(),
+ traffic_ping_pong_large_host_cond()
+ end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_send_and_recv_tcp(InitState)
end).
+%% This test case is a bit extreme and fails on some hosts
+%% (e.g. OpenIndiana Hipster), so exclude them.
+traffic_ping_pong_large_host_cond() ->
+ traffic_ping_pong_large_host_cond(os:type(), os:version()).
+
+traffic_ping_pong_large_host_cond({unix, sunos}, _) ->
+ skip("TC does not work on platform");
+traffic_ping_pong_large_host_cond(_, _) ->
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -9936,6 +15159,7 @@ traffic_ping_pong_small_sendto_and_recvfrom_udp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(45)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -9956,12 +15180,43 @@ traffic_ping_pong_small_sendto_and_recvfrom_udp6(suite) ->
traffic_ping_pong_small_sendto_and_recvfrom_udp6(doc) ->
[];
traffic_ping_pong_small_sendto_and_recvfrom_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(45)),
Msg = l2b(?TPP_SMALL),
Num = ?TPP_SMALL_NUM,
tc_try(traffic_ping_pong_small_sendto_and_recvfrom_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(45)),
- InitState = #{domain => inet,
+ InitState = #{domain => inet6,
+ proto => udp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendto and recvfrom
+%% functions by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for two different message sizes;
+%% small (8 bytes) and medium (8K).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'small' message test case, for Unix Domain (dgram) socket.
+
+traffic_ping_pong_small_sendto_and_recvfrom_udpL(suite) ->
+ [];
+traffic_ping_pong_small_sendto_and_recvfrom_udpL(doc) ->
+ [];
+traffic_ping_pong_small_sendto_and_recvfrom_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(45)),
+ Msg = l2b(?TPP_SMALL),
+ Num = ?TPP_SMALL_NUM,
+ tc_try(traffic_ping_pong_small_sendto_and_recvfrom_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -9989,6 +15244,7 @@ traffic_ping_pong_medium_sendto_and_recvfrom_udp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(45)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -10016,6 +15272,36 @@ traffic_ping_pong_medium_sendto_and_recvfrom_udp6(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(45)),
InitState = #{domain => inet6,
+ proto => udp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendto and recvfrom
+%% functions by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for two different message sizes;
+%% small (8 bytes) and medium (8K).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'medium' message test case, for Unix Domain (dgram) socket.
+
+traffic_ping_pong_medium_sendto_and_recvfrom_udpL(suite) ->
+ [];
+traffic_ping_pong_medium_sendto_and_recvfrom_udpL(doc) ->
+ [];
+traffic_ping_pong_medium_sendto_and_recvfrom_udpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_MEDIUM),
+ Num = ?TPP_MEDIUM_NUM,
+ tc_try(traffic_ping_pong_medium_sendto_and_recvfrom_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(45)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -10043,6 +15329,7 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(20)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10070,6 +15357,35 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(20)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'small' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(suite) ->
+ [];
+traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(doc) ->
+ [];
+traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_SMALL),
+ Num = ?TPP_SMALL_NUM,
+ tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(20)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10096,6 +15412,7 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10122,7 +15439,36 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
fun() -> has_support_ipv6() end,
fun() ->
?TT(?SECS(20)),
- InitState = #{domain => ine6,
+ InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'medium' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(suite) ->
+ [];
+traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(doc) ->
+ [];
+traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_MEDIUM),
+ Num = ?TPP_MEDIUM_NUM,
+ tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(20)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10146,15 +15492,27 @@ traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config)
Msg = l2b(?TPP_LARGE),
Num = ?TPP_LARGE_NUM,
tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcp4,
+ fun() -> traffic_ping_pong_large_sendmsg_and_recvmsg_cond() end,
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet,
+ proto => tcp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
end).
+traffic_ping_pong_large_sendmsg_and_recvmsg_cond() ->
+ traffic_ping_pong_large_sendmsg_and_recvmsg_cond(os:type(), os:version()).
+
+traffic_ping_pong_large_sendmsg_and_recvmsg_cond({unix, linux}, {M, _, _})
+ when (M < 3) ->
+ skip("TC may not work on this version");
+traffic_ping_pong_large_sendmsg_and_recvmsg_cond(_, _) ->
+ ok.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test that the sendmsg and recvmsg functions
%% by repeatedly sending a meassage between two entities.
@@ -10172,10 +15530,43 @@ traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
Msg = l2b(?TPP_LARGE),
Num = ?TPP_LARGE_NUM,
tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcp6,
- fun() -> has_support_ipv6() end,
+ fun() ->
+ has_support_ipv6(),
+ traffic_ping_pong_large_sendmsg_and_recvmsg_cond()
+ end,
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet6,
+ proto => tcp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes), medium (8K) and large (8M).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'large' message test case, for Unix Domain (stream) socket.
+
+traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(suite) ->
+ [];
+traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(doc) ->
+ [];
+traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_LARGE),
+ Num = ?TPP_LARGE_NUM,
+ tc_try(traffic_ping_pong_large_sendmsg_and_recvmsg_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(30)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10203,6 +15594,7 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(60)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10229,7 +15621,36 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
fun() -> has_support_ipv6() end,
fun() ->
?TT(?SECS(30)),
- InitState = #{domain => inet,
+ InitState = #{domain => inet6,
+ proto => udp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg functions
+%% by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes) and medium (8K).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'small' message test case, for Unix Domain (dgram) socket.
+
+traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(suite) ->
+ [];
+traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(doc) ->
+ [];
+traffic_ping_pong_small_sendmsg_and_recvmsg_udpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_SMALL),
+ Num = ?TPP_SMALL_NUM,
+ tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(30)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10256,6 +15677,7 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config)
fun() ->
?TT(?SECS(30)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10282,7 +15704,37 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
fun() -> has_support_ipv6() end,
fun() ->
?TT(?SECS(20)),
- InitState = #{domain => ine6,
+ InitState = #{domain => inet6,
+ proto => udp,
+ msg => Msg,
+ num => Num},
+ ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
+ end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to test that the sendmsg and recvmsg
+%% functions by repeatedly sending a meassage between two entities.
+%% The same basic test case is used for three different message sizes;
+%% small (8 bytes) and medium (8K).
+%% The message is sent from A to B and then back again. This is
+%% repeated a set number of times (more times the small the message).
+%% This is the 'medium' message test case, for Unix Domain (dgram) socket.
+
+traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(suite) ->
+ [];
+traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(doc) ->
+ [];
+traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL(_Config) when is_list(_Config) ->
+ Msg = l2b(?TPP_MEDIUM),
+ Num = ?TPP_MEDIUM_NUM,
+ tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ ?TT(?SECS(20)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10302,14 +15754,26 @@ traffic_ping_pong_send_and_recv_tcp(InitState) ->
},
traffic_ping_pong_send_and_receive_tcp(InitState2).
-traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState) ->
- Send = fun(Sock, Data) when is_binary(Data) ->
- MsgHdr = #{iov => [Data]},
- socket:sendmsg(Sock, MsgHdr);
- (Sock, Data) when is_list(Data) -> %% We assume iovec...
- MsgHdr = #{iov => Data},
- socket:sendmsg(Sock, MsgHdr)
+traffic_ping_pong_sendmsg_and_recvmsg_tcp(#{domain := local} = InitState) ->
+ Recv = fun(Sock, Sz) ->
+ case socket:recvmsg(Sock, Sz, 0) of
+ %% On some platforms, the address
+ %% is *not* provided (e.g. FreeBSD)
+ {ok, #{addr := undefined,
+ iov := [Data]}} ->
+ {ok, Data};
+ %% On some platforms, the address
+ %% *is* provided (e.g. linux)
+ {ok, #{addr := #{family := local},
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
end,
+ InitState2 = InitState#{recv => Recv}, % Receive function
+ traffic_ping_pong_sendmsg_and_recvmsg_tcp2(InitState2);
+traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState) ->
Recv = fun(Sock, Sz) ->
case socket:recvmsg(Sock, Sz, 0) of
{ok, #{addr := undefined,
@@ -10319,9 +15783,18 @@ traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState) ->
ERROR
end
end,
- InitState2 = InitState#{send => Send, % Send function
- recv => Recv % Receive function
- },
+ InitState2 = InitState#{recv => Recv}, % Receive function
+ traffic_ping_pong_sendmsg_and_recvmsg_tcp2(InitState2).
+
+traffic_ping_pong_sendmsg_and_recvmsg_tcp2(InitState) ->
+ Send = fun(Sock, Data) when is_binary(Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(Sock, MsgHdr);
+ (Sock, Data) when is_list(Data) -> %% We assume iovec...
+ MsgHdr = #{iov => Data},
+ socket:sendmsg(Sock, MsgHdr)
+ end,
+ InitState2 = InitState#{send => Send}, % Send function
traffic_ping_pong_send_and_receive_tcp(InitState2).
@@ -10381,13 +15854,12 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
#{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, stream, tcp) of
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
{ok, State#{lsock => Sock}};
{error, _} = ERROR ->
@@ -10395,9 +15867,19 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{lsock := LSock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := LSock,
+ lsa := LSA} = _State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{lsock := LSock, local_sa := LSA} = State) ->
case socket:bind(LSock, LSA) of
{ok, Port} ->
+ ?SEV_IPRINT("bound to port: ~w", [Port]),
{ok, State#{lport => Port}};
{error, _} = ERROR ->
ERROR
@@ -10412,7 +15894,11 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester, local_sa := LSA}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester, local_sa := LSA, lport := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -10523,9 +16009,20 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
{ok, State1}
end},
#{desc => "close listen socket",
- cmd => fun(#{lsock := Sock} = State) ->
+ cmd => fun(#{domain := local,
+ lsock := Sock,
+ local_sa := #{path := Path}} = State) ->
(catch socket:close(Sock)),
- {ok, maps:remove(lsock, State)}
+ State1 =
+ unlink_path(Path,
+ fun() ->
+ maps:remove(local_sa, State)
+ end,
+ fun() -> State end),
+ {ok, maps:remove(lsock, State1)};
+ (#{lsock := Sock} = State) ->
+ (catch socket:close(Sock)),
+ {ok, maps:remove(lsock, State)}
end},
%% *** We are done ***
@@ -10577,12 +16074,14 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
end},
#{desc => "order remote client to start",
cmd => fun(#{rclient := RClient,
+ proto := Proto,
server_sa := ServerSA,
buf_init := BufInit,
send := Send,
recv := Recv}) ->
?SEV_ANNOUNCE_START(RClient,
- {ServerSA, BufInit, Send, Recv}),
+ {ServerSA, Proto, BufInit,
+ Send, Recv}),
ok
end},
#{desc => "await remote client ready",
@@ -10883,6 +16382,7 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
i("start server evaluator"),
ServerInitState = #{domain => maps:get(domain, InitState),
+ proto => maps:get(proto, InitState),
recv => maps:get(recv, InitState),
send => maps:get(send, InitState),
buf_init => maps:get(buf_init, InitState)},
@@ -10976,14 +16476,6 @@ tpp_tcp_handler_msg_exchange_loop(Sock, Send, Recv, N, Sent, Received, Start) ->
?SEV_EPRINT("send (~w): ~p", [N, SReason]),
exit({send, SReason, N})
end;
- %% {error, timeout} ->
- %% ?SEV_IPRINT("timeout(~w) - try again", [N]),
- %% case Send(Sock, list_to_binary("ping")) of
- %% ok ->
- %% exit({'ping-send', ok, N});
- %% {error, Reason} ->
- %% exit({'ping-send', Reason, N})
- %% end;
{error, closed} ->
?SEV_IPRINT("closed - we are done: ~w, ~w, ~w", [N, Sent, Received]),
Stop = ?LIB:timestamp(),
@@ -11002,10 +16494,10 @@ tpp_tcp_client_create(Node) ->
tpp_tcp_client(Parent) ->
tpp_tcp_client_init(Parent),
- {ServerSA, BufInit, Send, Recv} = tpp_tcp_client_await_start(Parent),
+ {ServerSA, Proto, BufInit, Send, Recv} = tpp_tcp_client_await_start(Parent),
Domain = maps:get(family, ServerSA),
- Sock = tpp_tcp_client_sock_open(Domain, BufInit),
- tpp_tcp_client_sock_bind(Sock, Domain),
+ Sock = tpp_tcp_client_sock_open(Domain, Proto, BufInit),
+ Path = tpp_tcp_client_sock_bind(Sock, Domain),
tpp_tcp_client_announce_ready(Parent, init),
tpp_tcp_client_await_continue(Parent, connect),
tpp_tcp_client_sock_connect(Sock, ServerSA),
@@ -11014,7 +16506,7 @@ tpp_tcp_client(Parent) ->
Result = tpp_tcp_client_msg_exchange(Sock, Send, Recv, InitMsg, Num),
tpp_tcp_client_announce_ready(Parent, send, Result),
Reason = tpp_tcp_client_await_terminate(Parent),
- tpp_tcp_client_sock_close(Sock),
+ tpp_tcp_client_sock_close(Sock, Path),
?SEV_IPRINT("terminating"),
exit(Reason).
@@ -11054,8 +16546,10 @@ tpp_tcp_client_await_terminate(Parent) ->
?SEV_IPRINT("await terminate"),
case ?SEV_AWAIT_TERMINATE(Parent, parent) of
ok ->
- ok;
+ ?SEV_IPRINT("termination received: normal"),
+ normal;
{error, Reason} ->
+ ?SEV_IPRINT("termination received: ~w", [Reason]),
Reason
end.
@@ -11099,8 +16593,8 @@ tpp_tcp_client_msg_exchange_loop(Sock, Send, Recv, Data,
exit({send, SReason, N})
end.
-tpp_tcp_client_sock_open(Domain, BufInit) ->
- case socket:open(Domain, stream, tcp) of
+tpp_tcp_client_sock_open(Domain, Proto, BufInit) ->
+ case socket:open(Domain, stream, Proto) of
{ok, Sock} ->
ok = BufInit(Sock),
Sock;
@@ -11109,14 +16603,19 @@ tpp_tcp_client_sock_open(Domain, BufInit) ->
end.
tpp_tcp_client_sock_bind(Sock, Domain) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
- ok;
- {error, Reason} ->
- exit({bind, Reason})
+ case socket:sockname(Sock) of
+ {ok, #{family := local, path := Path}} ->
+ Path;
+ {ok, _} ->
+ undefined;
+ {error, Reason1} ->
+ exit({sockname, Reason1})
+ end;
+ {error, Reason2} ->
+ exit({bind, Reason2})
end.
tpp_tcp_client_sock_connect(Sock, ServerSA) ->
@@ -11127,14 +16626,20 @@ tpp_tcp_client_sock_connect(Sock, ServerSA) ->
exit({connect, Reason})
end.
-tpp_tcp_client_sock_close(Sock) ->
+tpp_tcp_client_sock_close(Sock, Path) ->
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("failed closing: "
+ "~n Reason: ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
+
+
-define(TPP_REQUEST, 1).
-define(TPP_REPLY, 2).
@@ -11300,13 +16805,12 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
%% *** Init part ***
#{desc => "which local address",
cmd => fun(#{domain := Domain} = State) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
{ok, State#{local_sa => LSA}}
end},
- #{desc => "create listen socket",
- cmd => fun(#{domain := Domain} = State) ->
- case socket:open(Domain, dgram, udp) of
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, dgram, Proto) of
{ok, Sock} ->
{ok, State#{sock => Sock}};
{error, _} = ERROR ->
@@ -11314,7 +16818,15 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
end
end},
#{desc => "bind to local address",
- cmd => fun(#{sock := Sock, local_sa := LSA} = State) ->
+ cmd => fun(#{domain := local,
+ sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{sock := Sock, local_sa := LSA} = State) ->
case socket:bind(Sock, LSA) of
{ok, Port} ->
{ok, State#{port => Port}};
@@ -11357,7 +16869,11 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
end
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, local_sa := LSA, port := Port}) ->
+ cmd => fun(#{domain := local,
+ tester := Tester, local_sa := LSA}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, LSA),
+ ok;
+ (#{tester := Tester, local_sa := LSA, port := Port}) ->
ServerSA = LSA#{port => Port},
?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
@@ -11396,6 +16912,19 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
ERROR
end
end},
+ #{desc => "(maybe) unlink socket",
+ cmd => fun(#{domain := local,
+ local_sa := #{path := Path}} = State) ->
+ unlink_path(Path,
+ fun() ->
+ {ok, maps:remove(local_sa, State)}
+ end,
+ fun() ->
+ ok
+ end);
+ (_) ->
+ ok
+ end},
#{desc => "announce ready (close)",
cmd => fun(#{tester := Tester} = _State) ->
?SEV_ANNOUNCE_READY(Tester, close),
@@ -11492,11 +17021,13 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
#{desc => "order remote handler to start",
cmd => fun(#{handler := Handler,
server_sa := ServerSA,
+ proto := Proto,
buf_init := BufInit,
send := Send,
recv := Recv}) ->
?SEV_ANNOUNCE_START(Handler,
- {ServerSA, BufInit, Send, Recv}),
+ {ServerSA, Proto, BufInit,
+ Send, Recv}),
ok
end},
#{desc => "await (remote) handler ready",
@@ -11741,6 +17272,7 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
i("start server evaluator"),
ServerInitState = #{domain => maps:get(domain, InitState),
+ proto => maps:get(proto, InitState),
recv => maps:get(recv, InitState),
send => maps:get(send, InitState),
buf_init => maps:get(buf_init, InitState)},
@@ -11841,12 +17373,12 @@ tpp_udp_client_handler_create(Node) ->
tpp_udp_client_handler(Parent) ->
tpp_udp_client_handler_init(Parent),
?SEV_IPRINT("await start command"),
- {ServerSA, BufInit, Send, Recv} = tpp_udp_handler_await_start(Parent),
+ {ServerSA, Proto, BufInit, Send, Recv} = tpp_udp_handler_await_start(Parent),
?SEV_IPRINT("start command with"
"~n ServerSA: ~p", [ServerSA]),
Domain = maps:get(family, ServerSA),
- Sock = tpp_udp_sock_open(Domain, BufInit),
- tpp_udp_sock_bind(Sock, Domain),
+ Sock = tpp_udp_sock_open(Domain, Proto, BufInit),
+ Path = tpp_udp_sock_bind(Sock, Domain),
?SEV_IPRINT("announce ready", []),
tpp_udp_handler_announce_ready(Parent, init),
{InitMsg, Num} = tpp_udp_handler_await_continue(Parent, send),
@@ -11859,7 +17391,7 @@ tpp_udp_client_handler(Parent) ->
?SEV_IPRINT("await terminate"),
Reason = tpp_udp_handler_await_terminate(Parent),
?SEV_IPRINT("terminate with ~p", [Reason]),
- tpp_udp_sock_close(Sock),
+ tpp_udp_sock_close(Sock, Path),
?SEV_IPRINT("terminating"),
exit(Reason).
@@ -11997,8 +17529,8 @@ tpp_udp_handler_await_terminate(Parent) ->
end.
-tpp_udp_sock_open(Domain, BufInit) ->
- case socket:open(Domain, dgram, udp) of
+tpp_udp_sock_open(Domain, Proto, BufInit) ->
+ case socket:open(Domain, dgram, Proto) of
{ok, Sock} ->
ok = BufInit(Sock),
Sock;
@@ -12007,9 +17539,7 @@ tpp_udp_sock_open(Domain, BufInit) ->
end.
tpp_udp_sock_bind(Sock, Domain) ->
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain,
- addr => LAddr},
+ LSA = which_local_socket_addr(Domain),
case socket:bind(Sock, LSA) of
{ok, _} ->
ok;
@@ -12017,12 +17547,16 @@ tpp_udp_sock_bind(Sock, Domain) ->
exit({bind, Reason})
end.
-tpp_udp_sock_close(Sock) ->
+tpp_udp_sock_close(Sock, Path) ->
case socket:close(Sock) of
ok ->
+ unlink_path(Path),
ok;
{error, Reason} ->
- exit({close, Reason})
+ ?SEV_EPRINT("Failed closing socket: "
+ "~n ~p", [Reason]),
+ unlink_path(Path),
+ {error, {close, Reason}}
end.
@@ -15104,6 +20638,30 @@ ttest_ssockf_csockf_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockf_csockf_small_tcpL(suite) ->
+ [];
+ttest_ssockf_csockf_small_tcpL(doc) ->
+ [];
+ttest_ssockf_csockf_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockf_small_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, false,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -15152,6 +20710,30 @@ ttest_ssockf_csockf_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockf_csockf_medium_tcpL(suite) ->
+ [];
+ttest_ssockf_csockf_medium_tcpL(doc) ->
+ [];
+ttest_ssockf_csockf_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockf_medium_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, false,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -15199,6 +20781,30 @@ ttest_ssockf_csockf_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = false
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockf_csockf_large_tcpL(suite) ->
+ [];
+ttest_ssockf_csockf_large_tcpL(doc) ->
+ [];
+ttest_ssockf_csockf_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockf_large_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, false,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = once
%% Message Size: small (=1)
%% Domain: inet
@@ -15248,6 +20854,30 @@ ttest_ssockf_csocko_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockf_csocko_small_tcpL(suite) ->
+ [];
+ttest_ssockf_csocko_small_tcpL(doc) ->
+ [];
+ttest_ssockf_csocko_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, once,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -15296,6 +20926,30 @@ ttest_ssockf_csocko_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockf_csocko_medium_tcpL(suite) ->
+ [];
+ttest_ssockf_csocko_medium_tcpL(doc) ->
+ [];
+ttest_ssockf_csocko_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csocko_medium_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, once,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -15343,6 +20997,30 @@ ttest_ssockf_csocko_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = once
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockf_csocko_large_tcpL(suite) ->
+ [];
+ttest_ssockf_csocko_large_tcpL(doc) ->
+ [];
+ttest_ssockf_csocko_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csocko_large_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, once,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = true
%% Message Size: small (=1)
%% Domain: inet
@@ -15390,6 +21068,30 @@ ttest_ssockf_csockt_small_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockf_csockt_small_tcpL(suite) ->
+ [];
+ttest_ssockf_csockt_small_tcpL(doc) ->
+ [];
+ttest_ssockf_csockt_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, true,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = true
%% Message Size: medium (=2)
@@ -15440,6 +21142,30 @@ ttest_ssockf_csockt_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = false
%% Client: Transport = socket(tcp), Active = true
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockf_csockt_medium_tcpL(suite) ->
+ [];
+ttest_ssockf_csockt_medium_tcpL(doc) ->
+ [];
+ttest_ssockf_csockt_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockt_medium_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, true,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = true
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -15486,6 +21212,30 @@ ttest_ssockf_csockt_large_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = false
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockf_csockt_large_tcpL(suite) ->
+ [];
+ttest_ssockf_csockt_large_tcpL(doc) ->
+ [];
+ttest_ssockf_csockt_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockf_csockt_large_tcpL,
+ Runtime,
+ local,
+ sock, false,
+ sock, true,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = gen_tcp, Active = false
%% Message Size: small (=1)
@@ -15968,6 +21718,30 @@ ttest_ssocko_csockf_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssocko_csockf_small_tcpL(suite) ->
+ [];
+ttest_ssocko_csockf_small_tcpL(doc) ->
+ [];
+ttest_ssocko_csockf_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockf_small_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, false,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -16016,6 +21790,30 @@ ttest_ssocko_csockf_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssocko_csockf_medium_tcpL(suite) ->
+ [];
+ttest_ssocko_csockf_medium_tcpL(doc) ->
+ [];
+ttest_ssocko_csockf_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockf_medium_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, false,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -16063,6 +21861,30 @@ ttest_ssocko_csockf_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = false
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssocko_csockf_large_tcpL(suite) ->
+ [];
+ttest_ssocko_csockf_large_tcpL(doc) ->
+ [];
+ttest_ssocko_csockf_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockf_large_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, false,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = once
%% Message Size: small (=1)
%% Domain: inet
@@ -16112,6 +21934,30 @@ ttest_ssocko_csocko_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssocko_csocko_small_tcpL(suite) ->
+ [];
+ttest_ssocko_csocko_small_tcpL(doc) ->
+ [];
+ttest_ssocko_csocko_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, once,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -16160,6 +22006,30 @@ ttest_ssocko_csocko_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssocko_csocko_medium_tcpL(suite) ->
+ [];
+ttest_ssocko_csocko_medium_tcpL(doc) ->
+ [];
+ttest_ssocko_csocko_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csocko_medium_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, once,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -16207,6 +22077,30 @@ ttest_ssocko_csocko_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = once
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssocko_csocko_large_tcpL(suite) ->
+ [];
+ttest_ssocko_csocko_large_tcpL(doc) ->
+ [];
+ttest_ssocko_csocko_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csocko_large_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, once,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = true
%% Message Size: small (=1)
%% Domain: inet
@@ -16254,6 +22148,30 @@ ttest_ssocko_csockt_small_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssocko_csockt_small_tcpL(suite) ->
+ [];
+ttest_ssocko_csockt_small_tcpL(doc) ->
+ [];
+ttest_ssocko_csockt_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, true,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = true
%% Message Size: medium (=2)
@@ -16304,6 +22222,30 @@ ttest_ssocko_csockt_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = once
%% Client: Transport = socket(tcp), Active = true
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssocko_csockt_medium_tcpL(suite) ->
+ [];
+ttest_ssocko_csockt_medium_tcpL(doc) ->
+ [];
+ttest_ssocko_csockt_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockt_medium_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, true,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = true
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -16350,6 +22292,30 @@ ttest_ssocko_csockt_large_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = once
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssocko_csockt_large_tcpL(suite) ->
+ [];
+ttest_ssocko_csockt_large_tcpL(doc) ->
+ [];
+ttest_ssocko_csockt_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssocko_csockt_large_tcpL,
+ Runtime,
+ local,
+ sock, once,
+ sock, true,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = gen_tcp, Active = false
%% Message Size: small (=1)
@@ -16832,6 +22798,30 @@ ttest_ssockt_csockf_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockt_csockf_small_tcpL(suite) ->
+ [];
+ttest_ssockt_csockf_small_tcpL(doc) ->
+ [];
+ttest_ssockt_csockf_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockf_small_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, false,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -16880,6 +22870,30 @@ ttest_ssockt_csockf_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = false
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockt_csockf_medium_tcpL(suite) ->
+ [];
+ttest_ssockt_csockf_medium_tcpL(doc) ->
+ [];
+ttest_ssockt_csockf_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockf_medium_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, false,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = false
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -16927,6 +22941,30 @@ ttest_ssockt_csockf_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = false
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockt_csockf_large_tcpL(suite) ->
+ [];
+ttest_ssockt_csockf_large_tcpL(doc) ->
+ [];
+ttest_ssockt_csockf_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockf_large_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, false,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = once
%% Message Size: small (=1)
%% Domain: inet
@@ -16976,6 +23014,30 @@ ttest_ssockt_csocko_small_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockt_csocko_small_tcpL(suite) ->
+ [];
+ttest_ssockt_csocko_small_tcpL(doc) ->
+ [];
+ttest_ssockt_csocko_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, once,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: medium (=2)
%% Domain: inet
%%
@@ -17024,6 +23086,30 @@ ttest_ssockt_csocko_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = once
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockt_csocko_medium_tcpL(suite) ->
+ [];
+ttest_ssockt_csocko_medium_tcpL(doc) ->
+ [];
+ttest_ssockt_csocko_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csocko_medium_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, once,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = once
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -17071,6 +23157,30 @@ ttest_ssockt_csocko_large_tcp6(Config) when is_list(Config) ->
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = once
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockt_csocko_large_tcpL(suite) ->
+ [];
+ttest_ssockt_csocko_large_tcpL(doc) ->
+ [];
+ttest_ssockt_csocko_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csocko_large_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, once,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = true
%% Message Size: small (=1)
%% Domain: inet
@@ -17118,6 +23228,30 @@ ttest_ssockt_csockt_small_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case uses the time test (ttest) utility to implement a
%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: small (=1)
+%% Domain: local
+%%
+
+ttest_ssockt_csockt_small_tcpL(suite) ->
+ [];
+ttest_ssockt_csockt_small_tcpL(doc) ->
+ [];
+ttest_ssockt_csockt_small_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csocko_small_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, true,
+ 1, 200).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = true
%% Message Size: medium (=2)
@@ -17168,6 +23302,30 @@ ttest_ssockt_csockt_medium_tcp6(Config) when is_list(Config) ->
%% ping-pong like test case.
%% Server: Transport = socket(tcp), Active = true
%% Client: Transport = socket(tcp), Active = true
+%% Message Size: medium (=2)
+%% Domain: local
+%%
+
+ttest_ssockt_csockt_medium_tcpL(suite) ->
+ [];
+ttest_ssockt_csockt_medium_tcpL(doc) ->
+ [];
+ttest_ssockt_csockt_medium_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockt_medium_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, true,
+ 2, 20).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = true
%% Message Size: large (=3)
%% Domain: inet
%%
@@ -17212,6 +23370,30 @@ ttest_ssockt_csockt_large_tcp6(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case uses the time test (ttest) utility to implement a
+%% ping-pong like test case.
+%% Server: Transport = socket(tcp), Active = true
+%% Client: Transport = socket(tcp), Active = true
+%% Message Size: large (=3)
+%% Domain: local
+%%
+
+ttest_ssockt_csockt_large_tcpL(suite) ->
+ [];
+ttest_ssockt_csockt_large_tcpL(doc) ->
+ [];
+ttest_ssockt_csockt_large_tcpL(Config) when is_list(Config) ->
+ Runtime = which_ttest_runtime(Config),
+ ttest_tcp(ttest_ssockt_csockt_large_tcpL,
+ Runtime,
+ local,
+ sock, true,
+ sock, true,
+ 3, 2).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
which_ttest_runtime(Config) when is_list(Config) ->
case lists:keysearch(esock_test_ttest_runtime, 1, Config) of
@@ -17235,7 +23417,7 @@ which_ttest_runtime_env(false) ->
%% ms: milliseconds
%% s: seconds (default)
%% m: minutes
-which_ttest_runtime_env2([$m, $s | MS]) when (length(MS) > 0) ->
+which_ttest_runtime_env2([$s, $m | MS]) when (length(MS) > 0) ->
convert_time(MS, fun(X) -> X end);
which_ttest_runtime_env2([$m | M]) when (length(M) > 0) ->
convert_time(M, fun(X) -> ?MINS(X) end);
@@ -17272,7 +23454,8 @@ ttest_tcp(TC,
tc_try(TC,
fun() ->
if
- (Domain =/= inet) -> has_support_ipv6();
+ (Domain =:= local) -> has_support_unix_domain_socket();
+ (Domain =:= inet6) -> has_support_ipv6();
true -> ok
end
end,
@@ -17326,11 +23509,25 @@ ttest_tcp(InitState) ->
ok
end},
#{desc => "start ttest (remote) server",
- cmd => fun(#{mod := Mod,
+ cmd => fun(#{domain := local = Domain,
+ mod := Mod,
+ active := Active,
+ node := Node} = State) ->
+ case ttest_tcp_server_start(Node,
+ Domain, Mod, Active) of
+ {ok, {{Pid, _}, Path}} ->
+ {ok, State#{rserver => Pid,
+ path => Path}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{domain := Domain,
+ mod := Mod,
active := Active,
node := Node} = State) ->
- case ttest_tcp_server_start(Node, Mod, Active) of
- {ok, {{Pid, _MRef}, {Addr, Port}}} ->
+ case ttest_tcp_server_start(Node,
+ Domain, Mod, Active) of
+ {ok, {{Pid, _}, {Addr, Port}}} ->
{ok, State#{rserver => Pid,
addr => Addr,
port => Port}};
@@ -17339,7 +23536,12 @@ ttest_tcp(InitState) ->
end
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester,
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ path := Path}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester,
addr := Addr,
port := Port}) ->
?SEV_ANNOUNCE_READY(Tester, init, {Addr, Port}),
@@ -17394,8 +23596,14 @@ ttest_tcp(InitState) ->
[
%% *** Wait for start order part ***
#{desc => "await start",
- cmd => fun(State) ->
- {Tester, {ServerAddr, ServerPort}} = ?SEV_AWAIT_START(),
+ cmd => fun(#{domain := local} = State) ->
+ {Tester, ServerPath} =
+ ?SEV_AWAIT_START(),
+ {ok, State#{tester => Tester,
+ server_path => ServerPath}};
+ (State) ->
+ {Tester, {ServerAddr, ServerPort}} =
+ ?SEV_AWAIT_START(),
{ok, State#{tester => Tester,
server_addr => ServerAddr,
server_port => ServerPort}}
@@ -17436,7 +23644,32 @@ ttest_tcp(InitState) ->
ok
end},
#{desc => "start ttest (remote) client",
- cmd => fun(#{node := Node,
+ cmd => fun(#{domain := local = Domain,
+ node := Node,
+ mod := Mod,
+ active := Active,
+ msg_id := MsgID,
+ max_outstanding := MaxOutstanding,
+ runtime := RunTime,
+ server_path := Path} = State) ->
+ Self = self(),
+ Notify =
+ fun(Result) ->
+ ?SEV_ANNOUNCE_READY(Self, ttest, Result)
+ end,
+ case ttest_tcp_client_start(Node, Notify,
+ Domain, Mod,
+ Path,
+ Active,
+ MsgID, MaxOutstanding,
+ RunTime) of
+ {ok, {Pid, _MRef}} ->
+ {ok, State#{rclient => Pid}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{domain := Domain,
+ node := Node,
mod := Mod,
active := Active,
msg_id := MsgID,
@@ -17450,8 +23683,9 @@ ttest_tcp(InitState) ->
?SEV_ANNOUNCE_READY(Self, ttest, Result)
end,
case ttest_tcp_client_start(Node, Notify,
- Mod, Active,
- Addr, Port,
+ Domain, Mod,
+ {Addr, Port},
+ Active,
MsgID, MaxOutstanding,
RunTime) of
{ok, {Pid, _MRef}} ->
@@ -17463,8 +23697,6 @@ ttest_tcp(InitState) ->
#{desc => "await ttest ready",
cmd => fun(#{tester := Tester,
rclient := RClient} = State) ->
- %% TTestResult = ?SEV_AWAIT_READY(RClient, rclient, ttest,
- %% [{tester, Tester}]),
case ?SEV_AWAIT_READY(RClient, rclient, ttest,
[{tester, Tester}]) of
{ok, Result} ->
@@ -17535,8 +23767,13 @@ ttest_tcp(InitState) ->
ok
end},
#{desc => "await server ready (init)",
- cmd => fun(#{server := Pid} = State) ->
- {ok, {Addr, Port}} = ?SEV_AWAIT_READY(Pid, server, init),
+ cmd => fun(#{domain := local,
+ server := Pid} = State) ->
+ {ok, Path} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{server_path => Path}};
+ (#{server := Pid} = State) ->
+ {ok, {Addr, Port}} =
+ ?SEV_AWAIT_READY(Pid, server, init),
{ok, State#{server_addr => Addr,
server_port => Port}}
end},
@@ -17544,7 +23781,12 @@ ttest_tcp(InitState) ->
%% Start the client
#{desc => "order client start",
- cmd => fun(#{client := Pid,
+ cmd => fun(#{domain := local,
+ client := Pid,
+ server_path := Path} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Path),
+ ok;
+ (#{client := Pid,
server_addr := Addr,
server_port := Port} = _State) ->
?SEV_ANNOUNCE_START(Pid, {Addr, Port}),
@@ -17600,12 +23842,23 @@ ttest_tcp(InitState) ->
%% Present the results
#{desc => "present the results",
- cmd => fun(#{result := Result} = State) ->
+ cmd => fun(#{result := Result,
+ domain := Domain,
+ server_mod := ServerTrans,
+ server_active := ServerActive,
+ client_mod := ClientTrans,
+ client_active := ClientActive,
+ msg_id := MsgID} = State) ->
case Result of
#{status := ok,
runtime := RunTime,
cnt := Cnt,
bcnt := BCnt} ->
+ ttest_report(Domain,
+ ServerTrans, ServerActive,
+ ClientTrans, ClientActive,
+ MsgID,
+ RunTime, BCnt, Cnt),
?SEV_IPRINT(
"TTest results: "
"~n Run Time: ~s"
@@ -17683,7 +23936,8 @@ ttest_tcp(InitState) ->
Client = ?SEV_START("client", ClientSeq, ClientInitState),
i("start 'tester' evaluator"),
- TesterInitState = #{server => Server#ev.pid,
+ TesterInitState = #{domain => maps:get(domain, InitState),
+ server => Server#ev.pid,
client => Client#ev.pid},
Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
@@ -17692,12 +23946,14 @@ ttest_tcp(InitState) ->
-ttest_tcp_server_start(Node, gen, Active) ->
+ttest_tcp_server_start(Node, _Domain, gen, Active) ->
Transport = socket_test_ttest_tcp_gen,
socket_test_ttest_tcp_server:start_monitor(Node, Transport, Active);
-ttest_tcp_server_start(Node, sock, Active) ->
+ttest_tcp_server_start(Node, Domain, sock, Active) ->
TransportMod = socket_test_ttest_tcp_socket,
- Transport = {TransportMod, #{method => plain}},
+ Transport = {TransportMod, #{domain => Domain,
+ async => true,
+ method => plain}},
socket_test_ttest_tcp_server:start_monitor(Node, Transport, Active).
ttest_tcp_server_stop(Pid) ->
@@ -17705,31 +23961,210 @@ ttest_tcp_server_stop(Pid) ->
ttest_tcp_client_start(Node,
Notify,
- gen,
- Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+ _Domain, gen,
+ ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
Transport = socket_test_ttest_tcp_gen,
socket_test_ttest_tcp_client:start_monitor(Node,
Notify,
Transport,
+ ServerInfo,
Active,
- Addr, Port,
MsgID, MaxOutstanding, RunTime);
ttest_tcp_client_start(Node,
Notify,
- sock,
- Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
+ Domain, sock,
+ ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
TransportMod = socket_test_ttest_tcp_socket,
- Transport = {TransportMod, #{method => plain}},
+ Transport = {TransportMod, #{domain => Domain,
+ async => true,
+ method => plain}},
socket_test_ttest_tcp_client:start_monitor(Node,
Notify,
Transport,
+ ServerInfo,
Active,
- Addr, Port,
MsgID, MaxOutstanding, RunTime).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(TTEST_MANAGER, esock_ttest_manager).
+
+-record(ttest_report_id,
+ {domain :: socket:domain(),
+ serv_trans :: gen | sock,
+ serv_active :: once | boolean(),
+ client_trans :: gen | sock,
+ client_active :: once | boolean(),
+ msg_id :: small | medium | large}).
+
+-record(ttest_report, {id :: #ttest_report_id{},
+ time :: non_neg_integer(),
+ bytes :: non_neg_integer(),
+ msgs :: non_neg_integer()}).
+
+-spec ttest_report(Domain :: socket:domain(),
+ ServTrans :: gen | sock, ServActive :: once | boolean(),
+ ClientTrans :: gen | sock, ClientActive :: once | boolean(),
+ MsgID :: 1 | 2 | 3,
+ RunTime :: non_neg_integer(),
+ NumBytes :: non_neg_integer(),
+ NumMsgs :: non_neg_integer()) -> ok.
+
+ttest_report(Domain,
+ ServTrans, ServActive,
+ ClientTrans, ClientActive,
+ MsgID,
+ RunTime,
+ NumBytes,
+ NumMsgs) ->
+ ID = #ttest_report_id{domain = Domain,
+ serv_trans = ServTrans,
+ serv_active = ServActive,
+ client_trans = ClientTrans,
+ client_active = ClientActive,
+ msg_id = ttest_msg_id_num_to_name(MsgID)},
+ Report = #ttest_report{id = ID,
+ time = RunTime,
+ bytes = NumBytes,
+ msgs = NumMsgs},
+ %% If we run just one test case, the group init has never been run
+ %% and therefor the ttest manager is not running (we also don't actually
+ %% care about collecting reports in that case).
+ (catch global:send(?TTEST_MANAGER, Report)),
+ ok.
+
+ttest_msg_id_num_to_name(1) ->
+ small;
+ttest_msg_id_num_to_name(2) ->
+ medium;
+ttest_msg_id_num_to_name(3) ->
+ large.
+
+ttest_manager_start() ->
+ Self = self(),
+ {Pid, MRef} = spawn_monitor(fun() -> ttest_manager_init(Self) end),
+ receive
+ {ttest_manager_started, Pid} ->
+ erlang:demonitor(MRef, [flush]),
+ ok;
+ {'DOWN', MRef, process, Pid, Reason} ->
+ exit({failed_starting, ttest_manager, Reason})
+ after 5000 ->
+ exit(Pid, kill),
+ exit({failed_starting, ttest_manager, timeout})
+ end.
+
+ttest_manager_stop() ->
+ case global:whereis_name(?TTEST_MANAGER) of
+ Pid when is_pid(Pid) ->
+ erlang:monitor(process, Pid),
+ global:send(?TTEST_MANAGER, stop),
+ receive
+ {'DOWN', _MRef, process, Pid, _} ->
+ ok
+ after 10000 ->
+ exit(Pid, kill),
+ ok
+ end;
+ _ ->
+ ok
+ end.
+
+ttest_manager_init(Parent) ->
+ yes = global:register_name(?TTEST_MANAGER, self()),
+ ets:new(?TTEST_MANAGER,
+ [{keypos, #ttest_report.id}, named_table, protected, ordered_set]),
+ Parent ! {ttest_manager_started, self()},
+ ttest_manager_loop().
+
+ttest_manager_loop() ->
+ receive
+ stop ->
+ ?LOGGER:format("manager stopping~n", []),
+ ttest_manager_done();
+
+ #ttest_report{id = _ID,
+ time = _RunTime,
+ bytes = _NumBytes,
+ msgs = _NumMsgs} = Report ->
+ true = ets:insert_new(?TTEST_MANAGER, Report),
+ ttest_manager_loop()
+ end.
+
+%% We are supposed to pretty print the result here...
+ttest_manager_done() ->
+ format_reports(inet),
+ %% format_reports(inet6),
+ ets:delete(?TTEST_MANAGER),
+ exit(normal).
+
+format_reports(Domain) ->
+ ?LOGGER:format("Domain ~w reports:~n~n", [Domain]),
+ format_reports(Domain, small),
+ format_reports(Domain, medium),
+ format_reports(Domain, large).
+
+format_reports(Domain, MsgID) when is_atom(MsgID) ->
+ case which_ttest_reports(Domain, MsgID) of
+ [] ->
+ ?LOGGER:format(" No ~w reports~n~n", [MsgID]);
+ Reports ->
+ ?LOGGER:format(" ~w reports: ~n", [MsgID]),
+ lists:foreach(fun(R) -> format_report(R) end, Reports)
+ end.
+
+%% This should really be a table like this:
+%%
+%% client
+%% server gen(false) gen(once) gen(true) sock(false) sock(once) sock(true)
+%% gen(false) nnn
+%% gen(once) nnn
+%% gen(true) nnn
+%% sock(false) nnn
+%% sock(once) nnn
+%% sock(true) nnn
+%%
+format_report(#ttest_report{id = #ttest_report_id{serv_trans = STrans,
+ serv_active = SActive,
+ client_trans = CTrans,
+ client_active = CActive},
+ time = RunTime,
+ bytes = BCnt,
+ msgs = MCnt}) ->
+ ?LOGGER:format(" server ~w[~w] - client ~w[~w] => "
+ "~n Run Time: ~s"
+ "~n Bytes: ~s"
+ "~n Messages: ~s"
+ "~n", [STrans, SActive, CTrans, CActive,
+ ?TTEST_LIB:format_time(RunTime),
+ if ((BCnt =:= 0) orelse (RunTime =:= 0)) ->
+ ?TTEST_LIB:format("~w, ~w",
+ [BCnt, RunTime]);
+ true ->
+ ?TTEST_LIB:format("~p => ~p byte / ms",
+ [BCnt, BCnt div RunTime])
+ end,
+ if (RunTime =:= 0) ->
+ "-";
+ true ->
+ ?TTEST_LIB:format("~p => ~p iterations / ms",
+ [MCnt, MCnt div RunTime])
+ end]),
+ ok.
+
+
+which_ttest_reports(Domain, all) ->
+ [R || R = #ttest_report{id = #ttest_report_id{domain = D}} <-
+ ets:tab2list(?TTEST_MANAGER), Domain =:= D];
+which_ttest_reports(Domain, MsgID) ->
+ [R || R = #ttest_report{id = #ttest_report_id{domain = D, msg_id = MID}} <-
+ ets:tab2list(?TTEST_MANAGER), (Domain =:= D) andalso (MsgID =:= MID)].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
%% This mechanism has only one purpose: So that we are able to kill
%% the node-starter process if it takes to long. The node-starter
%% runs on the local node.
@@ -17801,19 +24236,6 @@ sock_open(Domain, Type, Proto) ->
end.
-sock_bind(Sock, SockAddr) ->
- try socket:bind(Sock, SockAddr) of
- {ok, Port} ->
- Port;
- {error, Reason} ->
- i("sock_bind -> error: ~p", [Reason]),
- ?FAIL({bind, Reason})
- catch
- C:E:S ->
- i("sock_bind -> failed: ~p, ~p, ~p", [C, E, S]),
- ?FAIL({bind, C, E, S})
- end.
-
sock_connect(Sock, SockAddr) ->
try socket:connect(Sock, SockAddr) of
ok ->
@@ -17899,47 +24321,176 @@ local_host() ->
end.
+%% The point of this is to "ensure" that paths from different test runs
+%% don't clash.
+mk_unique_path() ->
+ [NodeName | _] = string:tokens(atom_to_list(node()), [$@]),
+ Path = ?LIB:f("/tmp/esock_~s_~w", [NodeName, erlang:system_time(nanosecond)]),
+ ensure_unique_path(Path).
+
+ensure_unique_path(Path) ->
+ case file:read_file_info(Path) of
+ {ok, _} -> % Ouch, append a unique ID and try again
+ ensure_unique_path(Path, 1);
+ {error, _} ->
+ %% We assume this means it does not exist yet...
+ %% If we have several process in paralell trying to create
+ %% (unique) path's, then we are in trouble. To *really* be
+ %% on the safe side we should have a (central) path registry...
+ Path
+ end.
+
+ensure_unique_path(Path, ID) when (ID < 100) -> % If this is not enough...
+ NewPath = ?LIB:f("~s_~w", [Path, ID]),
+ case file:read_file_info(NewPath) of
+ {ok, _} -> % Ouch, this also existed, increment and try again
+ ensure_unique_path(Path, ID + 1);
+ {error, _} -> % We assume this means it does not exist yet...
+ NewPath
+ end;
+ensure_unique_path(_, _) ->
+ skip("Could not create unique path").
+
+
+which_local_socket_addr(local = Domain) ->
+ #{family => Domain,
+ path => mk_unique_path()};
+
%% This gets the local address (not 127.0...)
%% We should really implement this using the (new) net module,
%% but until that gets the necessary functionality...
-which_local_addr(Domain) ->
+which_local_socket_addr(Domain) ->
+ case which_local_host_info(Domain) of
+ {ok, {_Name, _Flags, Addr}} ->
+ #{family => Domain,
+ addr => Addr};
+ {error, Reason} ->
+ ?FAIL(Reason)
+ end.
+
+
+%% Returns the interface (name), flags and address (not 127...)
+%% of the local host.
+which_local_host_info(Domain) ->
case inet:getifaddrs() of
{ok, IFL} ->
- which_addr(Domain, IFL);
- {error, Reason} ->
- ?FAIL({inet, getifaddrs, Reason})
+ which_local_host_info(Domain, IFL);
+ {error, _} = ERROR ->
+ ERROR
end.
-which_addr(_Domain, []) ->
+which_local_host_info(_Domain, []) ->
?FAIL(no_address);
-which_addr(Domain, [{"lo" ++ _, _}|IFL]) ->
- which_addr(Domain, IFL);
-which_addr(Domain, [{_Name, IFO}|IFL]) ->
- case which_addr2(Domain, IFO) of
- {ok, Addr} ->
- Addr;
- {error, no_address} ->
- which_addr(Domain, IFL)
+which_local_host_info(Domain, [{"lo" ++ _, _}|IFL]) ->
+ which_local_host_info(Domain, IFL);
+which_local_host_info(Domain, [{"docker" ++ _, _}|IFL]) ->
+ which_local_host_info(Domain, IFL);
+which_local_host_info(Domain, [{"br-" ++ _, _}|IFL]) ->
+ which_local_host_info(Domain, IFL);
+which_local_host_info(Domain, [{Name, IFO}|IFL]) ->
+ case which_local_host_info2(Domain, IFO) of
+ {ok, {Flags, Addr}} ->
+ {ok, {Name, Flags, Addr}};
+ {error, _} ->
+ which_local_host_info(Domain, IFL)
end;
-which_addr(Domain, [_|IFL]) ->
- which_addr(Domain, IFL).
+which_local_host_info(Domain, [_|IFL]) ->
+ which_local_host_info(Domain, IFL).
+
+which_local_host_info2(Domain, IFO) ->
+ case lists:keysearch(flags, 1, IFO) of
+ {value, {flags, Flags}} ->
+ which_local_host_info2(Domain, IFO, Flags);
+ false ->
+ {error, no_flags}
+ end.
-which_addr2(_Domain, []) ->
+which_local_host_info2(_Domain, [], _Flags) ->
{error, no_address};
-which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
- {ok, Addr};
-which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
- {ok, Addr};
-which_addr2(Domain, [_|IFO]) ->
- which_addr2(Domain, IFO).
+which_local_host_info2(inet = _Domain, [{addr, Addr}|_IFO], Flags)
+ when (size(Addr) =:= 4) andalso (element(1, Addr) =/= 127) ->
+ {ok, {Flags, Addr}};
+which_local_host_info2(inet6 = _Domain, [{addr, Addr}|_IFO], Flags)
+ when (size(Addr) =:= 8) andalso
+ (element(1, Addr) =/= 0) andalso
+ (element(1, Addr) =/= 16#fe80) ->
+ {ok, {Flags, Addr}};
+which_local_host_info2(Domain, [_|IFO], Flags) ->
+ which_local_host_info2(Domain, IFO, Flags).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Here are all the *general* test case condition functions.
+
+%% We also need (be able) to figure out the the multicast address,
+%% which we only support for some platforms (linux and sunos).
+%% We don't do that here, but since we can only do that (find a
+%% multicast address) for specific platforms, we check that we are
+%% on of those platforms here.
+has_ip_multicast_support() ->
+ case os:type() of
+ {unix, OsName} when (OsName =:= linux) orelse
+ (OsName =:= sunos) ->
+ case which_local_host_info(inet) of
+ {ok, {_Name, Flags, _Addr}} ->
+ case lists:member(multicast, Flags) of
+ true ->
+ ok;
+ false ->
+ not_supported(multicast)
+ end;
+ {error, Reason} ->
+ not_supported({multicast, Reason})
+ end;
+ Type ->
+ not_supported({multicast, Type})
+ end.
+has_ip_add_membership_support() ->
+ has_socket_option_ip_support(add_membership).
+has_ip_drop_membership_support() ->
+ has_socket_option_ip_support(drop_membership).
+has_socket_option_ip_support(Opt) ->
+ has_socket_option_support(ip, Opt).
+
+has_socket_option_support(Level, Option) ->
+ case socket:supports(options, Level, Option) of
+ true ->
+ ok;
+ false ->
+ not_supported({options, Level, Option})
+ end.
+
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Here are all the *general* test vase condition functions.
+
+unix_domain_socket_host_cond() ->
+ unix_domain_socket_host_cond(os:type(), os:version()).
+
+unix_domain_socket_host_cond({unix, linux}, {M, _, _}) when (M < 3) ->
+ skip("TC may not work on this version");
+unix_domain_socket_host_cond(_, _) ->
+ ok.
+
+has_support_unix_domain_socket() ->
+ case os:type() of
+ {win32, _} ->
+ skip("Not supported");
+ _ ->
+ case socket:supports(local) of
+ true ->
+ ok;
+ false ->
+ skip("Not supported")
+ end
+ end.
+
%% The idea is that this function shall test if the test host has
%% support for IPv6. If not, there is no point in running IPv6 tests.
@@ -17957,6 +24508,34 @@ has_support_ipv6() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+unlink_path(Path) ->
+ unlink_path(Path, fun() -> ok end, fun() -> ok end).
+
+unlink_path(Path, Success, Failure) when is_list(Path) andalso
+ is_function(Success, 0) andalso
+ is_function(Failure, 0) ->
+ ?SEV_IPRINT("try unlink path: "
+ "~n ~s", [Path]),
+ case os:cmd("unlink " ++ Path) of
+ "" ->
+ ?SEV_IPRINT("path unlinked: "
+ "~n Path: ~s", [Path]),
+ Success();
+ Result ->
+ ?SEV_EPRINT("unlink maybe failed: "
+ "~n Path: ~s"
+ "~n Res: ~s", [Path, Result]),
+ Failure()
+ end;
+unlink_path(_, _, _) ->
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+not_supported(What) ->
+ skip({not_supported, What}).
+
not_yet_implemented() ->
skip("not yet implemented").