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.erl12095
1 files changed, 11542 insertions, 553 deletions
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index e3545ccbf9..4980ea2a82 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -58,6 +58,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("common_test/include/ct_event.hrl").
+-include("socket_test_evaluator.hrl").
%% Suite exports
-export([suite/0, all/0, groups/0]).
@@ -67,18 +68,72 @@
%% Test cases
-export([
+ %% *** API Misc ***
+ api_m_debug/1,
+
%% *** 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_connect_tcp6/1,
+ api_a_sendto_and_recvfrom_udp4/1,
+ api_a_sendto_and_recvfrom_udp6/1,
+ api_a_sendmsg_and_recvmsg_udp4/1,
+ api_a_sendmsg_and_recvmsg_udp6/1,
+ api_a_send_and_recv_tcp4/1,
+ api_a_send_and_recv_tcp6/1,
+ api_a_sendmsg_and_recvmsg_tcp4/1,
+ api_a_sendmsg_and_recvmsg_tcp6/1,
+ api_a_recvfrom_cancel_udp4/1,
+ api_a_recvfrom_cancel_udp6/1,
+ api_a_recvmsg_cancel_udp4/1,
+ api_a_recvmsg_cancel_udp6/1,
+ api_a_accept_cancel_tcp4/1,
+ api_a_accept_cancel_tcp6/1,
+ api_a_recv_cancel_tcp4/1,
+ api_a_recv_cancel_tcp6/1,
+ api_a_recvmsg_cancel_tcp4/1,
+ api_a_recvmsg_cancel_tcp6/1,
+ api_a_mrecvfrom_cancel_udp4/1,
+ api_a_mrecvfrom_cancel_udp6/1,
+ api_a_mrecvmsg_cancel_udp4/1,
+ api_a_mrecvmsg_cancel_udp6/1,
+ api_a_maccept_cancel_tcp4/1,
+ api_a_maccept_cancel_tcp6/1,
+ api_a_mrecv_cancel_tcp4/1,
+ api_a_mrecv_cancel_tcp6/1,
+ api_a_mrecvmsg_cancel_tcp4/1,
+ api_a_mrecvmsg_cancel_tcp6/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_sock_acceptconn_udp/1,
+ api_opt_sock_acceptconn_tcp/1,
+ api_opt_sock_acceptfilter/1,
+ api_opt_sock_bindtodevice/1,
+ api_opt_sock_broadcast/1,
+ api_opt_sock_debug/1,
+ api_opt_sock_domain/1,
+ api_opt_sock_dontroute/1,
+ api_opt_sock_error/1,
+ api_opt_sock_keepalive/1,
+ api_opt_sock_linger/1,
+ api_opt_ip_add_drop_membership/1,
%% *** API Operation Timeout ***
api_to_connect_tcp4/1,
@@ -107,57 +162,92 @@
%% *** 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_counters_tcp4/1,
+ traffic_send_and_recv_counters_tcp6/1,
+ traffic_send_and_recv_counters_tcpL/1,
+ traffic_sendmsg_and_recvmsg_counters_tcp4/1,
+ traffic_sendmsg_and_recvmsg_counters_tcp6/1,
+ traffic_sendmsg_and_recvmsg_counters_tcpL/1,
+ traffic_sendto_and_recvfrom_counters_udp4/1,
+ traffic_sendto_and_recvfrom_counters_udp6/1,
+ traffic_sendto_and_recvfrom_counters_udpL/1,
+ traffic_sendmsg_and_recvmsg_counters_udp4/1,
+ traffic_sendmsg_and_recvmsg_counters_udp6/1,
+ traffic_sendmsg_and_recvmsg_counters_udpL/1,
+
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 +415,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 +470,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,53 +525,63 @@
%% 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
]).
--include("socket_test_evaluator.hrl").
-
%% Internal exports
%% -export([]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(BASIC_REQ, <<"hejsan">>).
--define(BASIC_REP, <<"hoppsan">>).
+-define(LIB, socket_test_lib).
+-define(TTEST_LIB, socket_test_ttest_lib).
+-define(LOGGER, socket_test_logger).
+
+-define(BASIC_REQ, <<"hejsan">>).
+-define(BASIC_REP, <<"hoppsan">>).
--define(DATA, <<"HOPPSAN">>). % Temporary
--define(FAIL(R), exit(R)).
+-define(DATA, <<"HOPPSAN">>). % Temporary
+-define(FAIL(R), exit(R)).
--define(SLEEP(T), receive after T -> ok end).
+-define(SLEEP(T), receive after T -> ok end).
--define(MINS(M), timer:minutes(M)).
--define(SECS(S), timer:seconds(S)).
+-define(MINS(M), timer:minutes(M)).
+-define(SECS(S), timer:seconds(S)).
--define(TT(T), ct:timetrap(T)).
+-define(TT(T), ct:timetrap(T)).
+
+-define(F(F, A), ?LIB:f(F, A)).
--define(LIB, socket_test_lib).
--define(TTEST_LIB, socket_test_ttest_lib).
--define(LOGGER, socket_test_logger).
-define(TPP_SMALL, lists:seq(1, 8)).
-define(TPP_MEDIUM, lists:flatten(lists:duplicate(1024, ?TPP_SMALL))).
@@ -483,10 +601,10 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- Groups = [{api, "ESOCK_TEST_API", include},
- {socket_closure, "ESOCK_TEST_SOCK_CLOSE", include},
- {traffic, "ESOCK_TEST_TRAFFIC", include},
- {ttest, "ESOCK_TEST_TTEST", exclude}],
+ Groups = [{api, "ESOCK_TEST_API", include},
+ {socket_close, "ESOCK_TEST_SOCK_CLOSE", include},
+ {traffic, "ESOCK_TEST_TRAFFIC", include},
+ {ttest, "ESOCK_TEST_TTEST", exclude}],
[use_group(Group, Env, Default) || {Group, Env, Default} <- Groups].
use_group(Group, Env, Default) ->
@@ -508,99 +626,201 @@ 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_misc, [], api_misc_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_socket, [], api_options_socket_cases()},
+ {api_option_sock_acceptconn, [], api_option_sock_acceptconn_cases()},
+ {api_options_ip, [], api_options_ip_cases()},
+ %% {api_options_ipv6, [], api_options_ipv6_cases()},
+ %% {api_options_tcp, [], api_options_tcp_cases()},
+ %% {api_options_udp, [], api_options_udp_cases()},
+ %% {api_options_sctp, [], api_options_sctp_cases()},
+ {api_op_with_timeout, [], api_op_with_timeout_cases()},
+ {socket_close, [], socket_close_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_counters, [], traffic_counters_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()}
].
api_cases() ->
[
+ {group, api_misc},
{group, api_basic},
+ {group, api_async},
{group, api_options},
{group, api_op_with_timeout}
].
+api_misc_cases() ->
+ [
+ api_m_debug
+ ].
+
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_connect_tcp6,
+ api_a_sendto_and_recvfrom_udp4,
+ api_a_sendto_and_recvfrom_udp6,
+ api_a_sendmsg_and_recvmsg_udp4,
+ api_a_sendmsg_and_recvmsg_udp6,
+ api_a_send_and_recv_tcp4,
+ api_a_send_and_recv_tcp6,
+ api_a_sendmsg_and_recvmsg_tcp4,
+ api_a_sendmsg_and_recvmsg_tcp6,
+ api_a_recvfrom_cancel_udp4,
+ api_a_recvfrom_cancel_udp6,
+ api_a_recvmsg_cancel_udp4,
+ api_a_recvmsg_cancel_udp6,
+ api_a_accept_cancel_tcp4,
+ api_a_accept_cancel_tcp6,
+ api_a_recv_cancel_tcp4,
+ api_a_recv_cancel_tcp6,
+ api_a_recvmsg_cancel_tcp4,
+ api_a_recvmsg_cancel_tcp6,
+ api_a_mrecvfrom_cancel_udp4,
+ api_a_mrecvfrom_cancel_udp6,
+ api_a_mrecvmsg_cancel_udp4,
+ api_a_mrecvmsg_cancel_udp6,
+ api_a_maccept_cancel_tcp4,
+ api_a_maccept_cancel_tcp6,
+ api_a_mrecv_cancel_tcp4,
+ api_a_mrecv_cancel_tcp6,
+ api_a_mrecvmsg_cancel_tcp4,
+ api_a_mrecvmsg_cancel_tcp6
].
api_options_cases() ->
[
+ {group, api_options_otp},
+ {group, api_options_socket},
+ {group, api_options_ip}% ,
+ %% {group, api_options_ipv6},
+ %% {group, api_options_tcp},
+ %% {group, api_options_udp},
+ %% {group, api_options_sctp}
+ ].
+
+api_options_otp_cases() ->
+ [
api_opt_simple_otp_options,
api_opt_simple_otp_rcvbuf_option,
api_opt_simple_otp_controlling_process
].
+api_options_socket_cases() ->
+ [
+ {group, api_option_sock_acceptconn},
+ api_opt_sock_acceptfilter,
+ api_opt_sock_bindtodevice,
+ api_opt_sock_broadcast,
+ api_opt_sock_debug,
+ api_opt_sock_domain,
+ api_opt_sock_dontroute,
+ api_opt_sock_error,
+ api_opt_sock_keepalive,
+ api_opt_sock_linger
+ ].
+
+api_option_sock_acceptconn_cases() ->
+ [
+ api_opt_sock_acceptconn_udp,
+ api_opt_sock_acceptconn_tcp
+ ].
+
+api_options_ip_cases() ->
+ [
+ api_opt_ip_add_drop_membership
+ ].
+
+%% api_options_ipv6_cases() ->
+%% [
+%% ].
+
api_op_with_timeout_cases() ->
[
api_to_connect_tcp4,
@@ -629,7 +849,7 @@ api_op_with_timeout_cases() ->
%% These cases tests what happens when the socket is closed/shutdown,
%% locally or remotely.
-socket_closure_cases() ->
+socket_close_cases() ->
[
{group, sc_ctrl_proc_exit},
{group, sc_local_close},
@@ -638,13 +858,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 +874,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 +897,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 +910,89 @@ 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_counters},
+ {group, traffic_chunks},
+ {group, traffic_pp_send_recv},
+ {group, traffic_pp_sendto_recvfrom},
+ {group, traffic_pp_sendmsg_recvmsg}
+ ].
+
+traffic_counters_cases() ->
+ [
+ traffic_send_and_recv_counters_tcp4,
+ traffic_send_and_recv_counters_tcp6,
+ traffic_send_and_recv_counters_tcpL,
+ traffic_sendmsg_and_recvmsg_counters_tcp4,
+ traffic_sendmsg_and_recvmsg_counters_tcp6,
+ traffic_sendmsg_and_recvmsg_counters_tcpL,
+ traffic_sendto_and_recvfrom_counters_udp4,
+ traffic_sendto_and_recvfrom_counters_udp6,
+ traffic_sendto_and_recvfrom_counters_udpL,
+ traffic_sendmsg_and_recvmsg_counters_udp4,
+ traffic_sendmsg_and_recvmsg_counters_udp6,
+ traffic_sendmsg_and_recvmsg_counters_udpL
+ ].
+
+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 +1398,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 +1415,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 +1432,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 +1516,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 +1533,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 +1550,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 +1634,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 +1651,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 +1668,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 +1715,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 +1729,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 +1739,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.
@@ -1465,6 +1769,80 @@ quiet_mode(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
+%% API MISC %%
+%% %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% A simple test case that tests that the global debug can be channged.
+%% At the same time, it will test the info function (since it uses it
+%% for verification).
+
+api_m_debug(suite) ->
+ [];
+api_m_debug(doc) ->
+ [];
+api_m_debug(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_m_debug,
+ fun() -> has_bugfree_gcc() end,
+ fun() ->
+ ok = api_m_debug()
+ end).
+
+%% For some reason this test case triggers a gcc bug, which causes
+%% a segfault, on an ancient Fedora 16 VM. So, check the version of gcc...
+%% Not pretty, but the simplest way to skip (without actually testing for the host).
+has_bugfree_gcc() ->
+ has_bugfree_gcc(os:type()).
+
+%% Make sure we are on linux
+has_bugfree_gcc({unix, linux}) ->
+ has_bugfree_gcc2(string:trim(os:cmd("cat /etc/issue")));
+has_bugfree_gcc(_) ->
+ ok.
+
+%% Make sure we are on Fedora 16
+has_bugfree_gcc2("Fedora release 16 " ++ _) ->
+ has_bugfree_gcc3(os:cmd("gcc --version"));
+has_bugfree_gcc2("Welcome to SUSE Linux " ++ _) ->
+ has_bugfree_gcc4(os:cmd("gcc --version"));
+has_bugfree_gcc2(_) ->
+ ok.
+
+has_bugfree_gcc3("gcc (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2" ++ _) ->
+ skip("Buggy GCC");
+has_bugfree_gcc3(_) ->
+ ok.
+
+has_bugfree_gcc4("gcc (SUSE Linux) 4.3.2" ++ _) ->
+ skip("Buggy GCC");
+has_bugfree_gcc4(_) ->
+ ok.
+
+api_m_debug() ->
+ i("get initial info"),
+ #{debug := D0} = socket:info(),
+ D1 = not D0,
+ i("set new debug (~w => ~w)", [D0, D1]),
+ ok = socket:debug(D1),
+ i("get updated info (~w)", [D1]),
+ #{debug := D1} = socket:info(),
+ D2 = not D1,
+ i("set new debug (~w => ~w)", [D1, D2]),
+ ok = socket:debug(D2),
+ i("get updated info (~w)", [D2]),
+ #{debug := D2} = socket:info(),
+ i("ok"),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% %%
%% API BASIC %%
%% %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1510,6 +1888,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 +2051,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 +2114,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 +2186,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 +2281,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 +2336,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 +2396,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 +2473,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 +2487,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 +2510,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 +2579,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 +2612,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 +2627,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 +2711,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 +2774,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 +2861,4313 @@ api_b_send_and_recv_tcp(InitState) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically establish a TCP connection via an async connect. IPv4.
+
+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() ->
+ ok = api_a_connect_tcpD(inet)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically establish a TCP connection via an async connect. IPv6.
+
+api_a_connect_tcp6(suite) ->
+ [];
+api_a_connect_tcp6(doc) ->
+ [];
+api_a_connect_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_connect_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ ok = api_a_connect_tcpD(inet6)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+api_a_connect_tcpD(Domain) ->
+ 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 => Domain,
+ connect => Connect,
+ send => Send,
+ recv => Recv},
+ api_a_connect_tcp(InitState).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+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 IPv6 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_udp6(suite) ->
+ [];
+api_a_sendto_and_recvfrom_udp6(doc) ->
+ [];
+api_a_sendto_and_recvfrom_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_a_sendto_and_recvfrom_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Send = fun(Sock, Data, Dest) ->
+ socket:sendto(Sock, Data, Dest)
+ end,
+ Recv = fun(Sock) ->
+ socket:recvfrom(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet6,
+ 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).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive on an IPv6 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_udp6(suite) ->
+ [];
+api_a_sendmsg_and_recvmsg_udp6(doc) ->
+ [];
+api_a_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_a_sendmsg_and_recvmsg_udp6,
+ fun() -> has_support_ipv6() end,
+ 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 => inet6,
+ 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 "common" functions (send and recv)
+%% on an IPv6 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_tcp6(suite) ->
+ [];
+api_a_send_and_recv_tcp6(doc) ->
+ [];
+api_a_send_and_recv_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_send_and_recv_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Send = fun(Sock, Data) ->
+ socket:send(Sock, Data)
+ end,
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet6,
+ 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).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the msg functions (sendmsg and recvmsg)
+%% on an IPv6 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_tcp6(suite) ->
+ [];
+api_a_sendmsg_and_recvmsg_tcp6(doc) ->
+ [];
+api_a_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_sendmsg_and_recvmsg_tcp6,
+ fun() -> has_support_ipv6() end,
+ 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 => inet6,
+ 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. IPv4
+%%
+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 recvfrom,
+%% wait some time and then cancel. IPv6
+%%
+api_a_recvfrom_cancel_udp6(suite) ->
+ [];
+api_a_recvfrom_cancel_udp6(doc) ->
+ [];
+api_a_recvfrom_cancel_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvfrom_cancel_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvfrom(Sock, 0, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvmsg,
+%% wait some time and then cancel. IPv6
+%%
+api_a_recvmsg_cancel_udp6(suite) ->
+ [];
+api_a_recvmsg_cancel_udp6(doc) ->
+ [];
+api_a_recvmsg_cancel_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvmsg_cancel_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to accept,
+%% wait some time and then cancel. IPv6
+%%
+api_a_accept_cancel_tcp6(suite) ->
+ [];
+api_a_accept_cancel_tcp6(doc) ->
+ [];
+api_a_accept_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_accept_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Accept = fun(Sock) ->
+ case socket:accept(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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 recv,
+%% wait some time and then cancel. IPv6
+%%
+api_a_recv_cancel_tcp6(suite) ->
+ [];
+api_a_recv_cancel_tcp6(doc) ->
+ [];
+api_a_recv_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recv_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically we make an async (Timeout = nowait) call to recvmsg,
+%% wait some time and then cancel. IPv6
+%%
+api_a_recvmsg_cancel_tcp6(suite) ->
+ [];
+api_a_recvmsg_cancel_tcp6(doc) ->
+ [];
+api_a_recvmsg_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_a_recvmsg_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recvmsg(Sock, nowait)
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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 recvfrom
+%% (from *several* processes), wait some time and then cancel.
+%% This should result in abort messages to the 'other' processes. IPv6
+%%
+api_a_mrecvfrom_cancel_udp6(suite) ->
+ [];
+api_a_mrecvfrom_cancel_udp6(doc) ->
+ [];
+api_a_mrecvfrom_cancel_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvfrom_cancel_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvfrom(Sock, 0, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% 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. IPv6
+%%
+api_a_mrecvmsg_cancel_udp6(suite) ->
+ [];
+api_a_mrecvmsg_cancel_udp6(doc) ->
+ [];
+api_a_mrecvmsg_cancel_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvmsg_cancel_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ case socket:recvmsg(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% 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. IPv6
+%%
+api_a_maccept_cancel_tcp6(suite) ->
+ [];
+api_a_maccept_cancel_tcp6(doc) ->
+ [];
+api_a_maccept_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_maccept_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Accept = fun(Sock) ->
+ case socket:accept(Sock, nowait) of
+ {ok, _} = OK ->
+ OK;
+ {select, _} = SELECT ->
+ SELECT;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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 recv
+%% (from *several* processes), wait some time and then cancel,
+%% This should result in abort messages to the 'other' processes. IPv6
+%%
+api_a_mrecv_cancel_tcp6(suite) ->
+ [];
+api_a_mrecv_cancel_tcp6(doc) ->
+ [];
+api_a_mrecv_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecv_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recv(Sock, 0, nowait)
+ end,
+ InitState = #{domain => inet6,
+ 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. IPv4
+%%
+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).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% 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. IPv6
+%%
+api_a_mrecvmsg_cancel_tcp6(suite) ->
+ [];
+api_a_mrecvmsg_cancel_tcp6(doc) ->
+ [];
+api_a_mrecvmsg_cancel_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(20)),
+ tc_try(api_a_mrecvmsg_cancel_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ Recv = fun(Sock) ->
+ socket:recvmsg(Sock, nowait)
+ end,
+ InitState = #{domain => inet6,
+ 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 +7502,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 +7747,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 +8143,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 +8388,2027 @@ api_opt_simple_otp_controlling_process() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option acceptconn for UDP.
+%% This should be possible to get but not set.
+
+api_opt_sock_acceptconn_udp(suite) ->
+ [];
+api_opt_sock_acceptconn_udp(doc) ->
+ [];
+api_opt_sock_acceptconn_udp(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_acceptconn_udp,
+ fun() ->
+ has_support_sock_acceptconn()
+ end,
+ fun() -> api_opt_sock_acceptconn_udp() end).
+
+
+
+api_opt_sock_acceptconn_udp() ->
+ Opt = acceptconn,
+ Set = fun(S, Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{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 => "[get] verify socket (before bind)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, enoprotoopt = Reason} ->
+ %% On some platforms this is not accepted
+ %% for UDP, so skip this part (UDP).
+ ?SEV_EPRINT("Expected Failure: "
+ "~p => SKIP", [Reason]),
+ (catch socket:close(Sock)),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify socket (before bind)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p",
+ [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ #{desc => "bind socket to local address",
+ cmd => fun(#{sock := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[get] verify socket (after bind)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify socket (after bind)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p",
+ [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option acceptconn for TCP.
+%% This should be possible to get but not set.
+
+api_opt_sock_acceptconn_tcp(suite) ->
+ [];
+api_opt_sock_acceptconn_tcp(doc) ->
+ [];
+api_opt_sock_acceptconn_tcp(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_acceptconn_tcp,
+ fun() ->
+ has_support_sock_acceptconn()
+ end,
+ fun() -> api_opt_sock_acceptconn_tcp() end).
+
+
+
+api_opt_sock_acceptconn_tcp() ->
+ Opt = acceptconn,
+ Set = fun(S, Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ 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
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify listen socket (before bind)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, enoprotoopt = Reason} ->
+ ?SEV_EPRINT("Expected Failure: "
+ "~p => SKIP", [Reason]),
+ (catch socket:close(Sock)),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify listen socket (before bind)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "bind listen socket to local address",
+ cmd => fun(#{lsock := Sock, local_sa := LSA} = State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ {ok, State#{server_sa => LSA#{port => Port}}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify listen socket (after bind)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify listen socket (after bind)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "make listen socket accept connections",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case socket:listen(Sock) of
+ ok ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify listen socket (after listen)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, true} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Accepting connections"),
+ ok;
+ {ok, false} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Not accepting connections"),
+ {error, {unexpected_success, {Opt, false}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify listen socket (after listen)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Set(Sock, false) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=false)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "create (connecting) socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{csockc => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "bind connecting socket to local address",
+ cmd => fun(#{csockc := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[get] verify connecting socket (before connect)",
+ cmd => fun(#{csockc := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify connecting socket (before connect)",
+ cmd => fun(#{csockc := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "connect to server",
+ cmd => fun(#{csockc := Sock, server_sa := SSA} = _State) ->
+ case socket:connect(Sock, SSA) of
+ ok ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "accept connection",
+ cmd => fun(#{lsock := Sock} = State) ->
+ case socket:accept(Sock) of
+ {ok, CSock} ->
+ {ok, State#{csocks => CSock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify connecting socket (after connect)",
+ cmd => fun(#{csockc := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify connecting socket (after connect)",
+ cmd => fun(#{csockc := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ #{desc => "[get] verify connected socket",
+ cmd => fun(#{csocks := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Not accepting connections"),
+ ok;
+ {ok, true} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Accepting connections"),
+ {error, {unexpected_success, {Opt, true}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify connected socket",
+ cmd => fun(#{csocks := Sock} = _State) ->
+ case Set(Sock, true) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=true)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ #{desc => "[get] verify listen socket (after connect)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, true} ->
+ ?SEV_IPRINT("Expected Success: "
+ "Accepting connections"),
+ ok;
+ {ok, false} ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Not accepting connections"),
+ {error, {unexpected_success, {Opt, false}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[set] verify listen socket (after connect)",
+ cmd => fun(#{lsock := Sock} = _State) ->
+ case Set(Sock, false) of
+ {error, Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ ok;
+ ok ->
+ ?SEV_EPRINT("Unexpected Success: "
+ "Set acceptconn (=false)"),
+ {error, unexpected_success}
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close connecting socket(s)",
+ cmd => fun(#{csockc := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(csockc, State0),
+ State2 = maps:remove(csocks, State1), %% Auto-close
+ {ok, maps:remove(csockc, State2)}
+ end},
+ #{desc => "close listen socket",
+ cmd => fun(#{lsock := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(lsock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option acceptfilter. PLACEHOLDER!
+
+api_opt_sock_acceptfilter(suite) ->
+ [];
+api_opt_sock_acceptfilter(doc) ->
+ [];
+api_opt_sock_acceptfilter(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_acceptfilter,
+ fun() -> not_yet_implemented() end,
+ fun() -> ok end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option bindtodevice.
+%% It has not always been possible to 'get' this option
+%% (atleast on linux).
+
+api_opt_sock_bindtodevice(suite) ->
+ [];
+api_opt_sock_bindtodevice(doc) ->
+ [];
+api_opt_sock_bindtodevice(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_bindtodevice,
+ fun() -> has_support_sock_bindtodevice() end,
+ fun() -> api_opt_sock_bindtodevice() end).
+
+
+api_opt_sock_bindtodevice() ->
+ Opt = bindtodevice,
+ Set = fun(S, Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name, addr := Addr}} ->
+ ?SEV_IPRINT("local host info (~p): "
+ "~n Name: ~p"
+ "~n Addr: ~p",
+ [Domain, Name, Addr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ {ok, State#{dev => Name,
+ local_sa => LSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "create UDP socket 1",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{usock1 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "create UDP socket 2",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{usock2 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "create TCP socket 1",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{tsock1 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "create TCP socket 2",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{tsock2 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[get] verify UDP socket 1 (before bindtodevice)",
+ cmd => fun(#{usock1 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, enoprotoopt = Reason} ->
+ ?SEV_EPRINT("Unexpected Failure: ~p => SKIP",
+ [Reason]),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify UDP socket 2 (before bind)",
+ cmd => fun(#{usock2 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify TCP socket 1 (before bindtodevice)",
+ cmd => fun(#{tsock1 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify TCP socket 2 (before bind)",
+ cmd => fun(#{tsock2 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "Bind UDP socket 1 to device",
+ cmd => fun(#{usock1 := Sock, dev := Dev} = State) ->
+ case Set(Sock, Dev) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, eperm = Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ (catch socket:close(Sock)),
+ {ok, State#{usock1 => skip}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Bind UDP socket 2 to local address",
+ cmd => fun(#{usock2 := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Bind TCP socket 1 to device",
+ cmd => fun(#{usock1 := USock1,
+ tsock1 := Sock, dev := Dev} = State) ->
+ case Set(Sock, Dev) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, eperm = Reason} when (USock1 =:= skip) ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ {skip, Reason};
+ {error, eperm = Reason} ->
+ ?SEV_IPRINT("Expected Failure: ~p", [Reason]),
+ (catch socket:close(Sock)),
+ {ok, State#{tsock1 => skip}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Bind TCP socket 2 to local address",
+ cmd => fun(#{tsock2 := Sock, local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[get] verify UDP socket 1 (after bindtodevice)",
+ cmd => fun(#{usock1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP'ed (previous eperm)"),
+ ok;
+ (#{usock1 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify UDP socket 2 (after bind)",
+ cmd => fun(#{usock2 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify TCP socket 1 (after bindtodevice)",
+ cmd => fun(#{tsock1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP'ed (previous eperm)"),
+ ok;
+ (#{tsock1 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[get] verify TCP socket 2 (after bind)",
+ cmd => fun(#{tsock2 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Dev} ->
+ ?SEV_IPRINT("Expected Success: ~p", [Dev]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p", [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ %% *** Termination ***
+ #{desc => "close UDP socket 1",
+ cmd => fun(#{usock1 := skip} = State) ->
+ ?SEV_IPRINT("SKIP'ed (already closed)"),
+ {ok, maps:remove(usock1, State)};
+ (#{usock1 := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(usock1, State)}
+ end},
+ #{desc => "close UDP socket 2",
+ cmd => fun(#{usock2 := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(usock2, State)}
+ end},
+ #{desc => "close TCP socket 1",
+ cmd => fun(#{tsock1 := skip} = State) ->
+ ?SEV_IPRINT("SKIP'ed (already closed)"),
+ {ok, maps:remove(tsock1, State)};
+ (#{tsock1 := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(tsock1, State)}
+ end},
+ #{desc => "close TCP socket 2",
+ cmd => fun(#{tsock2 := Sock} = State) ->
+ socket:close(Sock),
+ {ok, maps:remove(tsock2, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option broadcast.
+%% Make it possible for datagram sockets to send packets to a broadcast
+%% address (IPv4 only).
+
+api_opt_sock_broadcast(suite) ->
+ [];
+api_opt_sock_broadcast(doc) ->
+ [];
+api_opt_sock_broadcast(_Config) when is_list(_Config) ->
+ ?TT(?SECS(30)),
+ tc_try(api_opt_sock_broadcast,
+ fun() -> has_support_sock_broadcast() end,
+ fun() -> api_opt_sock_broadcast() end).
+
+
+api_opt_sock_broadcast() ->
+ Opt = broadcast,
+ Set = fun(S, Val) when is_boolean(Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "[socket 1] create UDP socket (listening 1)",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock1 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "[socket 1] Bind UDP socket (to limited broadcast address)",
+ cmd => fun(#{sock1 := Sock} = State) ->
+ BSA = #{family => inet,
+ addr => broadcast},
+ ?SEV_IPRINT("Try bind (socket 1) to: "
+ "~n ~p", [BSA]),
+ case socket:bind(Sock, BSA) of
+ {ok, Port} ->
+ ?SEV_IPRINT("Expected Success (bound): ~p",
+ [Port]),
+ {ok, State#{sa1 => BSA#{port => Port}}};
+ {error, eaddrnotavail = Reason} ->
+ ?SEV_IPRINT("~p => "
+ "SKIP limited broadcast test",
+ [Reason]),
+ {ok, State#{sa1 => skip}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 1] UDP socket sockname",
+ cmd => fun(#{sa1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP limited broadcast test"),
+ ok;
+ (#{sock1 := Sock} = _State) ->
+ case socket:sockname(Sock) of
+ {ok, SA} ->
+ ?SEV_IPRINT("SA: ~p", [SA]),
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[socket 2] create UDP socket (listening 2)",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock2 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "[socket 2] Bind UDP socket (to subnet-directed broadcast address)",
+ cmd => fun(#{sock2 := Sock,
+ bsa := BSA} = State) ->
+ ?SEV_IPRINT("Try bind (socket 1) to: "
+ "~n ~p", [BSA]),
+ case socket:bind(Sock, BSA) of
+ {ok, Port} ->
+ ?SEV_IPRINT("Expected Success (bound): ~p",
+ [Port]),
+ {ok, State#{sa2 => BSA#{port => Port}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 2] UDP socket sockname",
+ cmd => fun(#{sock2 := Sock} = _State) ->
+ case socket:sockname(Sock) of
+ {ok, SA} ->
+ ?SEV_IPRINT("SA: ~p", [SA]),
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[socket 3] create UDP socket (sender)",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{sock3 => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3][get] verify UDP socket (before bind and set)",
+ cmd => fun(#{sock3 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, false} ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast not allowed"),
+ ok;
+ {ok, true} ->
+ ?SEV_IPRINT("Unexpected Success result: "
+ "broadcast already allowed"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3] Try make broadcast allowed",
+ cmd => fun(#{sock3 := Sock} = _State) ->
+ case Set(Sock, true) of
+ ok ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast now allowed"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3] verify UDP socket broadcast allowed",
+ cmd => fun(#{sock3 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, true} ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast allowed"),
+ ok;
+ {ok, false} ->
+ ?SEV_IPRINT("Unexpected Success result: "
+ "broadcast *not* allowed"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3] Bind UDP socket (to local address)",
+ cmd => fun(#{sock3 := Sock, lsa := LSA} = State) ->
+ ?SEV_IPRINT("Try bind (socket 2) to: "
+ "~n ~p", [LSA]),
+ case socket:bind(Sock, LSA) of
+ {ok, Port} ->
+ ?SEV_IPRINT("Expected Success (bound): ~p",
+ [Port]),
+ {ok, State#{sa3 => LSA#{port => Port}}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 3] verify UDP socket (after set)",
+ cmd => fun(#{sock3 := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, true} ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast allowed"),
+ ok;
+ {ok, false} ->
+ ?SEV_IPRINT("Unexpected Success result: "
+ "broadcast not allowed"),
+ {error, not_allowed};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[socket 3] try send to limited broadcast address",
+ cmd => fun(#{sa1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP limited broadcast test"),
+ ok;
+ (#{sock3 := Sock,
+ sa1 := Dest} = _State) ->
+ Data = list_to_binary("hejsan"),
+ ?SEV_IPRINT("try send to bradcast address: "
+ "~n ~p", [Dest]),
+ case socket:sendto(Sock, Data, Dest) of
+ ok ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast message sent"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 1] try recv",
+ cmd => fun(#{sa1 := skip} = _State) ->
+ ?SEV_IPRINT("SKIP limited broadcast test"),
+ ok;
+ (#{sock1 := Sock} = State) ->
+ case socket:recvfrom(Sock, 0, 5000) of
+ {ok, _} ->
+ ?SEV_IPRINT("Expected Success: "
+ "received message"),
+ ok;
+ {error, timeout = Reason} ->
+ %% Some platforms seem to balk at this.
+ %% It spossible to bind to this, and
+ %% send to it, but no data is received.
+ %% At some point we should investigate...
+ %% For now, we just skip this part of
+ %% the test...
+ ?SEV_IPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ {ok, State#{sa1 => skip}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "[socket 3] try send to subnet-directed broadcast address",
+ cmd => fun(#{sock3 := Sock,
+ sa2 := Dest} = _State) ->
+ Data = list_to_binary("hejsan"),
+ ?SEV_IPRINT("try send to bradcast address: "
+ "~n ~p", [Dest]),
+ case socket:sendto(Sock, Data, Dest) of
+ ok ->
+ ?SEV_IPRINT("Expected Success: "
+ "broadcast message sent"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "[socket 2] try recv",
+ cmd => fun(#{sock2 := Sock, sa1 := SA1} = _State) ->
+ case socket:recvfrom(Sock, 0, 5000) of
+ {ok, _} ->
+ ?SEV_IPRINT("Expected Success: "
+ "received message"),
+ ok;
+ {error, timeout = Reason} when (SA1 =:= skip) ->
+ ?SEV_IPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ {skip, "receive timeout"};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "[socket 3] close UDP socket (sender)",
+ cmd => fun(#{sock3 := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock3, State0),
+ State2 = maps:remove(sa3, State1),
+ {ok, State2}
+ end},
+ #{desc => "[socket 2] close UDP socket (listener 2)",
+ cmd => fun(#{sock2 := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock2, State0),
+ State2 = maps:remove(sa2, State1),
+ {ok, State2}
+ end},
+ #{desc => "[socket 1] close UDP socket (listener 1)",
+ cmd => fun(#{sock1 := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock1, State0),
+ State2 = maps:remove(sa1, State1),
+ {ok, State2}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option debug.
+%% On linux, this test requires that the user running the test to have
+%% CAP_NET_ADMIN capabilities or be root (effective user ID of 0),
+%% therefor we explicitly test for the result eacces when attempting to
+%% set, and skip if we get it.
+
+api_opt_sock_debug(suite) ->
+ [];
+api_opt_sock_debug(doc) ->
+ [];
+api_opt_sock_debug(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_debug,
+ fun() -> has_support_sock_debug() end,
+ fun() -> api_opt_sock_debug() end).
+
+
+api_opt_sock_debug() ->
+ Opt = debug,
+ Set = fun(S, Val) when is_integer(Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "create UDP 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 => "Get current debug value",
+ cmd => fun(#{sock := Sock} = State) ->
+ case Get(Sock) of
+ {ok, Debug} when is_integer(Debug) ->
+ ?SEV_IPRINT("Success: ~p", [Debug]),
+ {ok, State#{debug => Debug}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Try enable socket debug",
+ cmd => fun(#{sock := Sock, debug := Debug} = State) ->
+ NewDebug = Debug + 1,
+ case Set(Sock, NewDebug) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ {ok, State#{debug => NewDebug}};
+ {error, eacces = Reason} ->
+ ?SEV_EPRINT("NO ACCESS => SKIP"),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Get current (new) debug value",
+ cmd => fun(#{sock := Sock, debug := Debug} = _State) ->
+ case Get(Sock) of
+ {ok, Debug} when is_integer(Debug) ->
+ ?SEV_IPRINT("Success: ~p", [Debug]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close UDP socket",
+ cmd => fun(#{sock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock, State0),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option domain.
+%% This is a read only option. Also not available on all platforms.
+
+api_opt_sock_domain(suite) ->
+ [];
+api_opt_sock_domain(doc) ->
+ [];
+api_opt_sock_domain(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_domain,
+ fun() -> has_support_sock_domain() end,
+ fun() -> api_opt_sock_domain() end).
+
+
+api_opt_sock_domain() ->
+ Opt = domain,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "create IPv4 UDP socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, dgram, udp) of
+ {ok, Sock} ->
+ {ok, State#{usock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "Get domain for the UDP socket",
+ cmd => fun(#{domain := Domain, usock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Domain} ->
+ ?SEV_IPRINT("Success: ~p", [Domain]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "create TCP socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ {ok, State#{tsock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "Get domain for the TCP socket",
+ cmd => fun(#{domain := Domain, tsock := Sock} = _State) ->
+ case Get(Sock) of
+ {ok, Domain} ->
+ ?SEV_IPRINT("Success: ~p", [Domain]),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close UDP socket",
+ cmd => fun(#{usock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(usock, State0),
+ {ok, State1}
+ end},
+ #{desc => "close TCP socket",
+ cmd => fun(#{tsock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(tsock, State0),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option dontroute.
+%% The man page has the following to say:
+%% "Don't send via a gateway, send only to directly connected hosts.
+%% The same effect can be achieved by setting the MSG_DONTROUTE
+%% flag on a socket send(2) operation."
+%% Since its "kind of" difficult to check if it actually takes an
+%% effect (you would need a gateway for that and a machine "on the
+%% other side"), we only test if we can set and get the value.
+%% Better then nothing.
+
+api_opt_sock_dontroute(suite) ->
+ [];
+api_opt_sock_dontroute(doc) ->
+ [];
+api_opt_sock_dontroute(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_dontroute,
+ fun() -> has_support_sock_dontroute() end,
+ fun() -> api_opt_sock_dontroute() end).
+
+
+api_opt_sock_dontroute() ->
+ Opt = dontroute,
+ Set = fun(S, Val) when is_boolean(Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "create UDP 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 => "Get current value",
+ cmd => fun(#{sock := Sock} = State) ->
+ case Get(Sock) of
+ {ok, Val} when is_boolean(Val) ->
+ ?SEV_IPRINT("Success: ~p", [Val]),
+ {ok, State#{dontroute => Val}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Try change value",
+ cmd => fun(#{sock := Sock, dontroute := Current} = State) ->
+ New = not Current,
+ ?SEV_IPRINT("Change from ~p to ~p", [Current, New]),
+ case Set(Sock, New) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ {ok, State#{dontroute => New}};
+ {error, eopnotsupp = Reason} ->
+ ?SEV_EPRINT("Expected Failure: ~p",
+ [Reason]),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Verify changed value",
+ cmd => fun(#{sock := Sock, dontroute := Val} = _State) ->
+ case Get(Sock) of
+ {ok, Val} ->
+ ?SEV_IPRINT("Expected Success"),
+ ok;
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close UDP socket",
+ cmd => fun(#{sock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock, State0),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option error. PLACEHOLDER!
+
+api_opt_sock_error(suite) ->
+ [];
+api_opt_sock_error(doc) ->
+ [];
+api_opt_sock_error(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_error,
+ fun() -> not_yet_implemented() end,
+ fun() -> ok end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option keepalive.
+%% This is bit tricky to test, partly because we have no control over
+%% the underlying TCP timeouts. So, for now, we just test that we can
+%% change the value.
+
+api_opt_sock_keepalive(suite) ->
+ [];
+api_opt_sock_keepalive(doc) ->
+ [];
+api_opt_sock_keepalive(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_keepalive,
+ fun() -> has_support_sock_keepalive() end,
+ fun() -> api_opt_sock_keepalive() end).
+
+
+api_opt_sock_keepalive() ->
+ Opt = keepalive,
+ Set = fun(S, Val) when is_boolean(Val) ->
+ socket:setopt(S, socket, Opt, Val)
+ end,
+ Get = fun(S) ->
+ socket:getopt(S, socket, Opt)
+ end,
+
+ TesterSeq =
+ [
+ #{desc => "which local address",
+ cmd => fun(#{domain := Domain} = State) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name,
+ addr := Addr,
+ broadaddr := BAddr}} ->
+ ?SEV_IPRINT("local host info: "
+ "~n Name: ~p"
+ "~n Addr: ~p"
+ "~n Broadcast Addr: ~p",
+ [Name, Addr, BAddr]),
+ LSA = #{family => Domain,
+ addr => Addr},
+ BSA = #{family => Domain,
+ addr => BAddr},
+ {ok, State#{lsa => LSA,
+ bsa => BSA}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "create TCP 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 => "Get current value",
+ cmd => fun(#{sock := Sock} = State) ->
+ case Get(Sock) of
+ {ok, Val} when is_boolean(Val) ->
+ ?SEV_IPRINT("Success: ~p", [Val]),
+ {ok, State#{keepalive => Val}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Try change the value",
+ cmd => fun(#{sock := Sock, keepalive := Current} = State) ->
+ New = not Current,
+ ?SEV_IPRINT("Try change value from ~p to ~p",
+ [Current, New]),
+ case Set(Sock, New) of
+ ok ->
+ ?SEV_IPRINT("Expected Success"),
+ {ok, State#{keepalive => New}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected Failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+ #{desc => "Verify (new) current value",
+ cmd => fun(#{sock := Sock, keepalive := Val} = _State) ->
+ case Get(Sock) of
+ {ok, Val} ->
+ ?SEV_IPRINT("Expected Success (~p)", [Val]),
+ ok;
+ {ok, OtherVal} ->
+ ?SEV_IPRINT("Unexpected Success: ~p",
+ [OtherVal]),
+ {error, {unexpected_success_value,
+ Val, OtherVal}};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Unexpected failure: ~p",
+ [Reason]),
+ ERROR
+ end
+ end},
+
+ %% *** Termination ***
+ #{desc => "close UDP socket",
+ cmd => fun(#{sock := Sock} = State0) ->
+ socket:close(Sock),
+ State1 = maps:remove(sock, State0),
+ {ok, State1}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ Domain = inet,
+
+ i("start tester evaluator"),
+ InitState = #{domain => Domain},
+ Tester = ?SEV_START("tester", TesterSeq, InitState),
+
+ i("await evaluator(s)"),
+ ok = ?SEV_AWAIT_FINISH([Tester]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Tests the socket option linger. PLACEHOLDER!
+
+api_opt_sock_linger(suite) ->
+ [];
+api_opt_sock_linger(doc) ->
+ [];
+api_opt_sock_linger(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(api_opt_sock_linger,
+ fun() -> not_yet_implemented() end,
+ fun() -> ok end).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% 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_support_ip_add_membership(),
+ has_support_ip_drop_membership(),
+ has_support_ip_multicast()
+ 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
+ ],
+
+
+ Domain = inet,
+ i("get multicast address"),
+ 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 ->
+ %% Actually, what is "not supported". is netstat!
+ 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),
+ %% On some platforms the netstat barfs out some crap on stderr
+ %% before the actual info...
+ case os:cmd("netstat -g 2>/dev/null | grep " ++ IfName) of
+ [] ->
+ %% Can't figure out if we support multicast or not...
+ not_supported(no_netstat);
+ NetstatGroupsStr ->
+ try
+ begin
+ NetstatGroups0 = string:tokens(NetstatGroupsStr, [$\n]),
+ NetstatGroups = [string:tokens(G, [$ ]) ||
+ G <- NetstatGroups0],
+ MAddrs = [WhichMAddr(NetstatGroup) ||
+ NetstatGroup <- NetstatGroups],
+ which_multicast_address3(Domain, MAddrs)
+ end
+ catch
+ throw:E:_ ->
+ throw(E);
+ C:E:S ->
+ not_supported({multicast, {C,E,S}})
+ end
+ end.
+
+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 ?LIB:which_local_host_info(Domain) of
+ {ok, #{name := Name}} ->
+ Name;
+ {error, Reason} ->
+ not_supported({multicast, Reason})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
%% API OPERATIONS WITH TIMEOUT %%
@@ -3434,11 +10425,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 +10445,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 +10484,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 +10524,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 +10595,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 +10745,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 +10896,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 +10974,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 +10991,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 +11008,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 +11132,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",
@@ -4489,6 +11475,7 @@ api_to_send_tcp6(doc) ->
[];
api_to_send_tcp6(_Config) when is_list(_Config) ->
tc_try(api_to_send_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
not_yet_implemented()%% ,
%% ok = api_to_send_tcp(inet6)
@@ -4521,6 +11508,7 @@ api_to_sendto_udp6(doc) ->
[];
api_to_sendto_udp6(_Config) when is_list(_Config) ->
tc_try(api_to_sendto_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
not_yet_implemented()%% ,
%% ok = api_to_sendto_to_udp(inet6)
@@ -4553,6 +11541,7 @@ api_to_sendmsg_tcp6(doc) ->
[];
api_to_sendmsg_tcp6(_Config) when is_list(_Config) ->
tc_try(api_to_sendmsg_tcp6,
+ fun() -> has_support_ipv6() end,
fun() ->
not_yet_implemented()%% ,
%% ok = api_to_sendmsg_tcp(inet6)
@@ -4587,6 +11576,7 @@ api_to_recv_udp6(doc) ->
[];
api_to_recv_udp6(_Config) when is_list(_Config) ->
tc_try(api_to_recv_udp6,
+ fun() -> has_support_ipv6() end,
fun() ->
not_yet_implemented()%% ,
%% ok = api_to_recv_udp(inet6)
@@ -4602,9 +11592,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 +11612,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 +11653,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 +11771,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 +11948,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 +11968,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 +11988,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 +12064,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 +12084,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 +12105,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 +12125,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 +12156,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(30)),
tc_try(sc_cpe_socket_cleanup_tcp4,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet,
type => stream,
protocol => tcp},
@@ -5190,10 +12176,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(30)),
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 +12190,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(30)),
+ 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 +12218,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(30)),
tc_try(sc_cpe_socket_cleanup_udp4,
fun() ->
- ?TT(?SECS(5)),
InitState = #{domain => inet,
type => dgram,
protocol => udp},
@@ -5232,10 +12239,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(30)),
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 +12251,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(30)),
+ 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 =
@@ -5337,8 +12366,15 @@ sc_cpe_socket_cleanup(InitState) ->
ERROR
end
end},
+
+ ?SEV_SLEEP(?SECS(5)),
+
%% The reason we get closed, is that as long as there is a ref to
%% the resource (socket), then it will not be garbage collected.
+ %% Note that its still a race that the nif has processed that the
+ %% "controlling process" has terminated. There really is no
+ %% proper timeout for this, but the 5 seconds "should" be enough...
+ %% We should really have some way to subscribe to socket events...
#{desc => "verify no socket (closed)",
cmd => fun(#{owner := Pid, sock := Sock} = _State) ->
case socket:getopt(Sock, otp, controlling_process) of
@@ -5386,12 +12422,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 +12443,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 +12456,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 +12500,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 +12514,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 +12540,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 +12566,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 +12598,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 +12623,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 +12750,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 +12765,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 +12782,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 +12824,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 +12882,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 +12940,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 +13108,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 +13129,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 +13183,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 +13240,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 +13544,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 +13566,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 +13587,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 +13602,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 +13635,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 +13657,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 +13700,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 +13721,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 +13773,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 +13816,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 +13838,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 +14171,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 +14192,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 +14205,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 +14249,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 +14262,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 +14285,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 +14475,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 +14550,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 +14954,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 +14979,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 +14996,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 +15028,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 +15118,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 +15139,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 +15152,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 +15183,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 +15191,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 +15202,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 +15234,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 +15298,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 +15311,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 +15334,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 +15449,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 +15518,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 +15851,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 +15880,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 +15895,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 +15911,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 +15922,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 +15979,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 +16094,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,20 +16130,2105 @@ 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).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use TCP on IPv4.
+
+traffic_send_and_recv_counters_tcp4(suite) ->
+ [];
+traffic_send_and_recv_counters_tcp4(doc) ->
+ [];
+traffic_send_and_recv_counters_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_send_and_recv_counters_tcp4,
+ fun() ->
+ InitState = #{domain => inet,
+ proto => tcp,
+ recv => fun(S) -> socket:recv(S) end,
+ send => fun(S, D) -> socket:send(S, D) end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use TCP on IPv6.
+
+traffic_send_and_recv_counters_tcp6(suite) ->
+ [];
+traffic_send_and_recv_counters_tcp6(doc) ->
+ [];
+traffic_send_and_recv_counters_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_send_and_recv_counters_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ InitState = #{domain => inet6,
+ proto => tcp,
+ recv => fun(S) -> socket:recv(S) end,
+ send => fun(S, D) -> socket:send(S, D) end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use default (TCP) on local.
+
+traffic_send_and_recv_counters_tcpL(suite) ->
+ [];
+traffic_send_and_recv_counters_tcpL(doc) ->
+ [];
+traffic_send_and_recv_counters_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_send_and_recv_counters_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ recv => fun(S) -> socket:recv(S) end,
+ send => fun(S, D) -> socket:send(S, D) end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use TCP on IPv4.
+
+traffic_sendmsg_and_recvmsg_counters_tcp4(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcp4(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_tcp4,
+ fun() ->
+ InitState = #{domain => inet,
+ proto => tcp,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := _Source,
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use TCP on IPv6.
+
+traffic_sendmsg_and_recvmsg_counters_tcp6(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcp6(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_tcp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ InitState = #{domain => inet6,
+ proto => tcp,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := _Source,
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use default (TCP) on local.
+
+traffic_sendmsg_and_recvmsg_counters_tcpL(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcpL(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_tcpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_tcpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := _Source,
+ iov := [Data]}} ->
+ {ok, Data};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data) ->
+ MsgHdr = #{iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+traffic_send_and_recv_tcp(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 listen socket",
+ cmd => fun(#{domain := Domain, proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
+ {ok, Sock} ->
+ {ok, State#{lsock => Sock}};
+ {error, eafnosupport = Reason} ->
+ {skip, Reason};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ 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}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ local_sa := #{path := Path}}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester,
+ lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "accept",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
+ {ok, Sock} ->
+ {ok, State#{csock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "initial counter validation (=zero)",
+ cmd => fun(#{csock := Sock} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("Validate initial counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(Counters)
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (accept)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (1)",
+ cmd => fun(#{csock := Sock,
+ recv := Recv} = State) ->
+ case Recv(Sock) of
+ {ok, Data} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 1)",
+ cmd => fun(#{csock := Sock,
+ read_pkg := Pkg,
+ read_byte := Byte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, Pkg},
+ {read_byte, Byte},
+ {read_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (1)",
+ cmd => fun(#{csock := Sock,
+ send := Send} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => 1,
+ write_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 1)",
+ cmd => fun(#{csock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (2)",
+ cmd => fun(#{csock := Sock,
+ recv := Recv,
+ read_pkg := Pkg,
+ read_byte := Byte} = State) ->
+ case Recv(Sock) of
+ {ok, Data} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => Pkg + 1,
+ read_byte => Byte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 2)",
+ cmd => fun(#{csock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (2)",
+ cmd => fun(#{csock := Sock,
+ send := Send,
+ write_pkg := Pkg,
+ write_byte := Byte} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => Pkg + 1,
+ write_byte => Byte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 2)",
+ cmd => fun(#{csock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ 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 connection socket (just in case)",
+ cmd => fun(#{csock := Sock} = State) ->
+ (catch socket:close(Sock)),
+ {ok, maps:remove(csock, State)}
+ end},
+ #{desc => "close listen socket",
+ 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)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ ClientSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start (from tester)",
+ 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},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which server (local) address",
+ 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,
+ proto := Proto} = State) ->
+ case socket:open(Domain, stream, Proto) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, eafnosupport = Reason} ->
+ {skip, Reason};
+ {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),
+ ok
+ 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_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (1)",
+ cmd => fun(#{sock := Sock,
+ send := Send} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => 1,
+ write_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 1)",
+ cmd => fun(#{sock := Sock,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{write_pkg, SPkg},
+ {write_byte, SByte},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (1)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv} = State) ->
+ case Recv(Sock) of
+ {ok, Data} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 1)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (2)",
+ cmd => fun(#{sock := Sock,
+ send := Send,
+ write_pkg := SPkg,
+ write_byte := SByte} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => SPkg + 1,
+ write_byte => SByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (2)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv,
+ read_pkg := RPkg,
+ read_byte := RByte} = State) ->
+ case Recv(Sock) of
+ {ok, Data} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => RPkg + 1,
+ read_byte => RByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ 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 connection socket",
+ 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) ->
+ 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(#{domain := local,
+ server := Pid} = State) ->
+ {ok, Path} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{path => Path}};
+ (#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{domain := local,
+ client := Pid,
+ path := Path} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Path),
+ ok;
+ (#{client := Pid,
+ 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},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (with connect)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, connect),
+ ok
+ 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 continue (recv_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_and_validate),
+ ok
+ end},
+ #{desc => "order client to continue (send_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_and_validate),
+ ok
+ end},
+ #{desc => "await client ready (send_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_and_validate)
+ end},
+ #{desc => "await server ready (recv_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (recv_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_and_validate),
+ ok
+ end},
+ #{desc => "order server to continue (send_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_and_validate),
+ ok
+ end},
+ #{desc => "await server ready (send_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_and_validate)
+ end},
+ #{desc => "await client ready (recv_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to continue (recv_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_and_validate),
+ ok
+ end},
+ #{desc => "order client to continue (send_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_and_validate),
+ ok
+ end},
+ #{desc => "await client ready (send_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_and_validate)
+ end},
+ #{desc => "await server ready (recv_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (recv_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_and_validate),
+ ok
+ end},
+ #{desc => "order server to continue (send_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_and_validate),
+ ok
+ end},
+ #{desc => "await server ready (send_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_and_validate)
+ end},
+ #{desc => "await client ready (recv_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_and_validate)
+ 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"),
+ ServerInitState = InitState#{host => local_host()},
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start client evaluator(s)"),
+ ClientInitState = InitState#{host => local_host()},
+ 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]).
+
+
+
+traffic_sar_counters_validation(Counters) ->
+ traffic_sar_counters_validation(Counters, []).
+
+traffic_sar_counters_validation(Counters, []) ->
+ (catch lists:foreach(
+ fun({_Cnt, 0}) -> ok;
+ ({Cnt, Val}) -> throw({error, {invalid_counter, Cnt, Val}})
+ end,
+ Counters));
+traffic_sar_counters_validation(Counters, [{Cnt, Val}|ValidateCounters]) ->
+ case lists:keysearch(Cnt, 1, Counters) of
+ {value, {Cnt, Val}} ->
+ Counters2 = lists:keydelete(Cnt, 1, Counters),
+ traffic_sar_counters_validation(Counters2, ValidateCounters);
+ {value, {Cnt, _Val}} when (Val =:= any) ->
+ Counters2 = lists:keydelete(Cnt, 1, Counters),
+ traffic_sar_counters_validation(Counters2, ValidateCounters);
+ {value, {Cnt, InvVal}} ->
+ {error, {invalid_counter, Cnt, InvVal, Val}};
+ false ->
+ {error, {unknown_counter, Cnt, Counters}}
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use UDP on IPv4.
+
+traffic_sendto_and_recvfrom_counters_udp4(suite) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udp4(doc) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendto_and_recvfrom_counters_udp4,
+ fun() ->
+ InitState = #{domain => inet,
+ proto => udp,
+ recv => fun(S) ->
+ socket:recvfrom(S)
+ end,
+ send => fun(S, Data, Dest) ->
+ socket:sendto(S, Data, Dest)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use UDP on IPv6.
+
+traffic_sendto_and_recvfrom_counters_udp6(suite) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udp6(doc) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendto_and_recvfrom_counters_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ InitState = #{domain => inet6,
+ proto => udp,
+ recv => fun(S) ->
+ socket:recvfrom(S)
+ end,
+ send => fun(S, Data, Dest) ->
+ socket:sendto(S, Data, Dest)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use default (UDP) on local.
+
+traffic_sendto_and_recvfrom_counters_udpL(suite) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udpL(doc) ->
+ [];
+traffic_sendto_and_recvfrom_counters_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendto_and_recvfrom_counters_udp4,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ recv => fun(S) ->
+ socket:recvfrom(S)
+ end,
+ send => fun(S, Data, Dest) ->
+ socket:sendto(S, Data, Dest)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use UDP on IPv4.
+
+traffic_sendmsg_and_recvmsg_counters_udp4(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udp4(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udp4(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_udp4,
+ fun() ->
+ InitState = #{domain => inet,
+ proto => udp,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use UDP on IPv6.
+
+traffic_sendmsg_and_recvmsg_counters_udp6(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udp6(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udp6(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_udp6,
+ fun() -> has_support_ipv6() end,
+ fun() ->
+ InitState = #{domain => inet6,
+ proto => udp,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% This test case is intended to (simply) test that the counters
+%% for both read and write.
+%% So that its easy to extend, we use fun's for read and write.
+%% We use default (UDP) on local.
+
+traffic_sendmsg_and_recvmsg_counters_udpL(suite) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udpL(doc) ->
+ [];
+traffic_sendmsg_and_recvmsg_counters_udpL(_Config) when is_list(_Config) ->
+ ?TT(?SECS(15)),
+ tc_try(traffic_sendmsg_and_recvmsg_counters_udpL,
+ fun() -> has_support_unix_domain_socket() end,
+ fun() ->
+ InitState = #{domain => local,
+ proto => default,
+ recv => fun(S) ->
+ case socket:recvmsg(S) of
+ {ok, #{addr := Source,
+ iov := [Data]}} ->
+ {ok, {Source, Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end,
+ send => fun(S, Data, Dest) ->
+ MsgHdr = #{addr => Dest,
+ iov => [Data]},
+ socket:sendmsg(S, MsgHdr)
+ end},
+ ok = traffic_send_and_recv_udp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+traffic_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, proto := Proto} = State) ->
+ case socket:open(Domain, dgram, Proto) of
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{domain := local,
+ sock := Sock,
+ local_sa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok; % We do not care about the port for local
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{sock := LSock,
+ local_sa := LSA} = State) ->
+ case socket:bind(LSock, LSA) of
+ {ok, Port} ->
+ {ok, State#{lport => Port}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "initial counter validation (=zero)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("Validate initial counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(Counters)
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{domain := local,
+ tester := Tester,
+ local_sa := #{path := Path}}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Path),
+ ok;
+ (#{tester := Tester,
+ lport := Port}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Port),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (1)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv} = State) ->
+ case Recv(Sock) of
+ {ok, {ClientSA, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{client_sa => ClientSA,
+ read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 1)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := Pkg,
+ read_byte := Byte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, Pkg},
+ {read_byte, Byte},
+ {read_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (1)",
+ cmd => fun(#{sock := Sock,
+ send := Send,
+ client_sa := ClientSA} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data, ClientSA) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => 1,
+ write_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 1)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (2)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv,
+ read_pkg := Pkg,
+ read_byte := Byte} = State) ->
+ case Recv(Sock) of
+ {ok, {Source, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{client_sa => Source,
+ read_pkg => Pkg + 1,
+ read_byte => Byte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (2)",
+ cmd => fun(#{sock := Sock,
+ client_sa := ClientSA,
+ send := Send,
+ write_pkg := Pkg,
+ write_byte := Byte} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data, ClientSA) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => Pkg + 1,
+ write_byte => Byte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ 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 (just in case)",
+ 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(lsock, State1)};
+ (#{sock := Sock} = State) ->
+ (catch socket:close(Sock)),
+ {ok, maps:remove(sock, State)}
+ end},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ ClientSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start (from tester)",
+ 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},
+ #{desc => "monitor tester",
+ cmd => fun(#{tester := Tester} = _State) ->
+ _MRef = erlang:monitor(process, Tester),
+ ok
+ end},
+
+ %% *** Init part ***
+ #{desc => "which server (local) address",
+ 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,
+ proto := Proto} = State) ->
+ case socket:open(Domain, dgram, Proto) 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 => "initial counter validation (=zero)",
+ cmd => fun(#{sock := Sock} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("Validate initial counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(Counters)
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (send_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (1)",
+ cmd => fun(#{sock := Sock,
+ send := Send,
+ server_sa := ServerSA} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data, ServerSA) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => 1,
+ write_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 1)",
+ cmd => fun(#{sock := Sock,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{write_pkg, SPkg},
+ {write_byte, SByte},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (1)",
+ cmd => fun(#{sock := Sock,
+ recv := Recv,
+ server_sa := #{family := local} = ServerSA} = State) ->
+ case Recv(Sock) of
+ {ok, {ServerSA, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{sock := Sock,
+ recv := Recv,
+ server_sa := #{addr := Addr, port := Port}} = State) ->
+ case Recv(Sock) of
+ {ok, {#{addr := Addr, port := Port}, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => 1,
+ read_byte => size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 1)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 1)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (send_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, send_and_validate)
+ end},
+ #{desc => "send (2)",
+ cmd => fun(#{sock := Sock,
+ send := Send,
+ server_sa := ServerSA,
+ write_pkg := SPkg,
+ write_byte := SByte} = State) ->
+ Data = ?DATA,
+ case Send(Sock, Data, ServerSA) of
+ ok ->
+ ?SEV_IPRINT("sent ~p bytes", [size(Data)]),
+ {ok, State#{write_pkg => SPkg + 1,
+ write_byte => SByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (send 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (send_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_and_validate),
+ ok
+ end},
+
+ #{desc => "await continue (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_and_validate)
+ end},
+ #{desc => "recv (2)",
+ cmd => fun(#{sock := Sock,
+ server_sa := #{family := local} = ServerSA,
+ recv := Recv,
+ read_pkg := RPkg,
+ read_byte := RByte} = State) ->
+ case Recv(Sock) of
+ {ok, {ServerSA, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => RPkg + 1,
+ read_byte => RByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end;
+ (#{sock := Sock,
+ server_sa := #{addr := Addr, port := Port},
+ recv := Recv,
+ read_pkg := RPkg,
+ read_byte := RByte} = State) ->
+ case Recv(Sock) of
+ {ok, {#{addr := Addr, port := Port}, Data}} ->
+ ?SEV_IPRINT("recv ~p bytes", [size(Data)]),
+ {ok, State#{read_pkg => RPkg + 1,
+ read_byte => RByte + size(Data)}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "validate (recv 2)",
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
+ write_pkg := SPkg,
+ write_byte := SByte} = _State) ->
+ try socket:info(Sock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("validate counters: "
+ "~n ~p", [Counters]),
+ traffic_sar_counters_validation(
+ Counters,
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any}])
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
+ #{desc => "announce ready (recv_and_validate 2)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, recv_and_validate),
+ 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 connection socket",
+ 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) ->
+ 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(#{domain := local,
+ server := Pid} = State) ->
+ {ok, Path} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{path => Path}};
+ (#{server := Pid} = State) ->
+ {ok, Port} = ?SEV_AWAIT_READY(Pid, server, init),
+ {ok, State#{port => Port}}
+ end},
+
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{domain := local,
+ client := Pid,
+ path := Path} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Path),
+ ok;
+ (#{client := Pid,
+ 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 (recv_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_and_validate),
+ ok
+ end},
+ #{desc => "order client to continue (send_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_and_validate),
+ ok
+ end},
+ #{desc => "await client ready (send_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_and_validate)
+ end},
+ #{desc => "await server ready (recv_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (recv_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_and_validate),
+ ok
+ end},
+ #{desc => "order server to continue (send_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_and_validate),
+ ok
+ end},
+ #{desc => "await server ready (send_and_validate 1)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_and_validate)
+ end},
+ #{desc => "await client ready (recv_and_validate 1)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order server to continue (recv_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, recv_and_validate),
+ ok
+ end},
+ #{desc => "order client to continue (send_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send_and_validate),
+ ok
+ end},
+ #{desc => "await client ready (send_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, send_and_validate)
+ end},
+ #{desc => "await server ready (recv_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, recv_and_validate)
+ end},
+
+ ?SEV_SLEEP(?SECS(1)),
+
+ #{desc => "order client to continue (recv_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, recv_and_validate),
+ ok
+ end},
+ #{desc => "order server to continue (send_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Server, send_and_validate),
+ ok
+ end},
+ #{desc => "await server ready (send_and_validate 2)",
+ cmd => fun(#{server := Server} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, send_and_validate)
+ end},
+ #{desc => "await client ready (recv_and_validate 2)",
+ cmd => fun(#{client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, recv_and_validate)
+ 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"),
+ ServerInitState = InitState#{host => local_host()},
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
+
+ i("start client evaluator(s)"),
+ ClientInitState = InitState#{host => local_host()},
+ 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]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 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.
@@ -8773,10 +18240,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 +18262,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 +18314,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 +18327,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 +18350,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 +18552,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 +18616,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 +19174,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 +19207,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 +19228,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 +19259,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 +19297,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 +19325,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 +19387,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 +19415,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 +19466,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,6 +19500,7 @@ 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)
@@ -9917,6 +19509,47 @@ traffic_ping_pong_large_send_and_recv_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 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.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 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;
@@ -9936,6 +19569,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)
@@ -9959,9 +19593,40 @@ traffic_ping_pong_small_sendto_and_recvfrom_udp6(_Config) when is_list(_Config)
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) ->
+ 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() ->
+ ?TT(?SECS(45)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendto_and_recvfrom_udp(InitState)
@@ -9989,6 +19654,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 +19682,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 +19739,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 +19767,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 +19822,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)
@@ -10121,8 +19848,37 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6(_Config) when is_list(_Config)
tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(20)),
- InitState = #{domain => ine6,
+ ?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 '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(30)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10146,15 +19902,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)),
+ ?TT(?SECS(60)),
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 +19940,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() ->
- ?TT(?SECS(30)),
+ has_support_ipv6(),
+ traffic_ping_pong_large_sendmsg_and_recvmsg_cond()
+ end,
+ fun() ->
+ ?TT(?SECS(60)),
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(60)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_tcp(InitState)
@@ -10203,6 +20004,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)
@@ -10228,8 +20030,37 @@ traffic_ping_pong_small_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
tc_try(traffic_ping_pong_small_sendmsg_and_recvmsg_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(30)),
- InitState = #{domain => inet,
+ ?TT(?SECS(60)),
+ 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(60)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10254,8 +20085,9 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config)
Num = ?TPP_MEDIUM_NUM,
tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udp4,
fun() ->
- ?TT(?SECS(30)),
+ ?TT(?SECS(60)),
InitState = #{domain => inet,
+ proto => udp,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10281,8 +20113,38 @@ traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6(_Config) when is_list(_Config)
tc_try(traffic_ping_pong_medium_sendmsg_and_recvmsg_udp6,
fun() -> has_support_ipv6() end,
fun() ->
- ?TT(?SECS(20)),
- InitState = #{domain => ine6,
+ ?TT(?SECS(60)),
+ 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(60)),
+ InitState = #{domain => local,
+ proto => default,
msg => Msg,
num => Num},
ok = traffic_ping_pong_sendmsg_and_recvmsg_udp(InitState)
@@ -10302,14 +20164,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 +20193,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).
@@ -10331,12 +20214,14 @@ traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) ->
?SEV_IPRINT("RcvBuf is ~p (needs atleast ~p)",
[RcvSz, 16+size(Msg)]),
if (RcvSz < size(Msg)) ->
- case socket:setopt(Sock,
- socket, rcvbuf, 1024+size(Msg)) of
+ NewRcvSz = 1024+size(Msg),
+ case socket:setopt(Sock, socket, rcvbuf, NewRcvSz) of
ok ->
ok;
{error, enobufs} ->
- skip({failed_change, rcvbuf});
+ skip(?F("Change ~w buffer size (to ~w) "
+ "not allowed",
+ [rcvbuf, NewRcvSz]));
{error, Reason1} ->
?FAIL({rcvbuf, Reason1})
end;
@@ -10347,12 +20232,14 @@ traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) ->
?SEV_IPRINT("SndBuf is ~p (needs atleast ~p)",
[SndSz, 16+size(Msg)]),
if (SndSz < size(Msg)) ->
- case socket:setopt(Sock,
- socket, sndbuf, 1024+size(Msg)) of
+ NewSndSz = 1024+size(Msg),
+ case socket:setopt(Sock, socket, sndbuf, NewSndSz) of
ok ->
ok;
{error, enobufs} ->
- skip({failed_change, sndbuf});
+ skip(?F("Change ~w buffer size (to ~w) "
+ "not allowed",
+ [sndbuf, NewSndSz]));
{error, Reason2} ->
?FAIL({sndbuf, Reason2})
end;
@@ -10381,13 +20268,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 +20281,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 +20308,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 +20423,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)),
+ 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 ***
@@ -10577,12 +20488,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 +20796,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 +20890,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 +20908,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 +20920,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 +20960,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 +21007,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 +21017,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 +21040,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 +21219,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 +21232,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 +21283,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 +21326,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 +21435,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 +21686,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 +21787,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 +21805,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).
@@ -11881,7 +21827,9 @@ tpp_udp_client_handler_msg_exchange_loop(_Sock, _Dest, _Send, _Recv, _Msg,
Start) ->
Stop = ?LIB:timestamp(),
{Sent, Received, Start, Stop};
-tpp_udp_client_handler_msg_exchange_loop(Sock, Dest, Send, Recv, Data,
+tpp_udp_client_handler_msg_exchange_loop(Sock,
+ #{family := local} = Dest,
+ Send, Recv, Data,
Num, N, Sent, Received, Start) ->
case tpp_udp_send_req(Sock, Send, Data, Dest) of
{ok, SendSz} ->
@@ -11900,6 +21848,28 @@ tpp_udp_client_handler_msg_exchange_loop(Sock, Dest, Send, Recv, Data,
{error, SReason} ->
?SEV_EPRINT("send (~w of ~w): ~p", [N, Num, SReason]),
exit({send, SReason, N})
+ end;
+tpp_udp_client_handler_msg_exchange_loop(Sock,
+ #{addr := Addr, port := Port} = Dest0,
+ Send, Recv, Data,
+ Num, N, Sent, Received, Start) ->
+ case tpp_udp_send_req(Sock, Send, Data, Dest0) of
+ {ok, SendSz} ->
+ case tpp_udp_recv_rep(Sock, Recv) of
+ {ok, NewData, RecvSz, #{addr := Addr, port := Port} = Dest1} ->
+ tpp_udp_client_handler_msg_exchange_loop(Sock, Dest1,
+ Send, Recv,
+ NewData, Num, N+1,
+ Sent+SendSz,
+ Received+RecvSz,
+ Start);
+ {error, RReason} ->
+ ?SEV_EPRINT("recv (~w of ~w): ~p", [N, Num, RReason]),
+ exit({recv, RReason, N})
+ end;
+ {error, SReason} ->
+ ?SEV_EPRINT("send (~w of ~w): ~p", [N, Num, SReason]),
+ exit({send, SReason, N})
end.
@@ -11997,8 +21967,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 +21977,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 +21985,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 +25076,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 +25148,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 +25219,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 +25292,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 +25364,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 +25435,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 +25506,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 +25580,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 +25650,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 +26156,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 +26228,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 +26299,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 +26372,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 +26444,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 +26515,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 +26586,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 +26660,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 +26730,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 +27236,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 +27308,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 +27379,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 +27452,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 +27524,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 +27595,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 +27666,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 +27740,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 +27808,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 +27855,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 +27892,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 +27947,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 +27974,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 +28034,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 +28082,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 +28121,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 +28135,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 +28205,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 +28219,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 +28280,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"
@@ -17665,16 +28356,22 @@ ttest_tcp(InitState) ->
?SEV_FINISH_NORMAL
],
+ Domain = maps:get(domain, InitState),
+ LHost = local_host(),
+ LAddr = which_local_addr(Domain),
+
i("start server evaluator"),
- ServerInitState = #{host => local_host(),
- domain => maps:get(domain, InitState),
+ ServerInitState = #{host => LHost,
+ addr => LAddr,
+ domain => Domain,
mod => maps:get(server_mod, InitState),
active => maps:get(server_active, InitState)},
Server = ?SEV_START("server", ServerSeq, ServerInitState),
i("start client evaluator"),
- ClientInitState = #{host => local_host(),
- domain => maps:get(domain, InitState),
+ ClientInitState = #{host => LHost,
+ addr => LAddr,
+ domain => Domain,
mod => maps:get(client_mod, InitState),
active => maps:get(client_active, InitState),
msg_id => maps:get(msg_id, InitState),
@@ -17683,8 +28380,14 @@ ttest_tcp(InitState) ->
Client = ?SEV_START("client", ClientSeq, ClientInitState),
i("start 'tester' evaluator"),
- TesterInitState = #{server => Server#ev.pid,
- client => Client#ev.pid},
+ TesterInitState = #{domain => Domain,
+ msg_id => maps:get(msg_id, InitState),
+ client => Client#ev.pid,
+ client_mod => maps:get(client_mod, InitState),
+ client_active => maps:get(client_active, InitState),
+ server => Server#ev.pid,
+ server_mod => maps:get(server_mod, InitState),
+ server_active => maps:get(server_active, InitState)},
Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
i("await evaluator(s)"),
@@ -17692,12 +28395,15 @@ ttest_tcp(InitState) ->
-ttest_tcp_server_start(Node, gen, Active) ->
- Transport = socket_test_ttest_tcp_gen,
+ttest_tcp_server_start(Node, Domain, gen, Active) ->
+ TransportMod = socket_test_ttest_tcp_gen,
+ Transport = {TransportMod, #{domain => Domain}},
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 +28411,211 @@ ttest_tcp_server_stop(Pid) ->
ttest_tcp_client_start(Node,
Notify,
- gen,
- Active, Addr, Port, MsgID, MaxOutstanding, RunTime) ->
- Transport = socket_test_ttest_tcp_gen,
+ Domain, gen,
+ ServerInfo, Active, MsgID, MaxOutstanding, RunTime) ->
+ TransportMod = socket_test_ttest_tcp_gen,
+ Transport = {TransportMod, #{domain => Domain}},
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 +28687,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 ->
@@ -17836,39 +28709,6 @@ sock_sockname(Sock) ->
?FAIL({sockname, C, E, S})
end.
-
-%% sock_listen(Sock) ->
-%% sock_listen2(fun() -> socket:listen(Sock) end).
-
-%% sock_listen(Sock, BackLog) ->
-%% sock_listen2(fun() -> socket:listen(Sock, BackLog) end).
-
-%% sock_listen2(Listen) ->
-%% try Listen() of
-%% ok ->
-%% ok;
-%% {error, Reason} ->
-%% ?FAIL({listen, Reason})
-%% catch
-%% C:E:S ->
-%% ?FAIL({listen, C, E, S})
-%% end.
-
-
-%% sock_accept(LSock) ->
-%% try socket:accept(LSock) of
-%% {ok, Sock} ->
-%% Sock;
-%% {error, Reason} ->
-%% i("sock_accept -> error: ~p", [Reason]),
-%% ?FAIL({accept, Reason})
-%% catch
-%% C:E:S ->
-%% i("sock_accept -> failed: ~p, ~p, ~p", [C, E, S]),
-%% ?FAIL({accept, C, E, S})
-%% end.
-
-
sock_close(Sock) ->
try socket:close(Sock) of
ok ->
@@ -17899,64 +28739,213 @@ 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 socket address (not 127.0...)
+%% We should really implement this using the (new) net module,
+%% but until that gets the necessary functionality...
+which_local_socket_addr(Domain) ->
+ case ?LIB:which_local_host_info(Domain) of
+ {ok, #{addr := Addr}} ->
+ #{family => Domain,
+ addr => Addr};
+ {error, Reason} ->
+ ?FAIL(Reason)
+ end.
+
+
+
+which_local_addr(local = _Domain) ->
+ 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) ->
- case inet:getifaddrs() of
- {ok, IFL} ->
- which_addr(Domain, IFL);
+ ?LIB:which_local_addr(Domain).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% 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_support_ip_multicast() ->
+ case os:type() of
+ {unix, OsName} when (OsName =:= linux) orelse
+ (OsName =:= sunos) ->
+ case ?LIB:which_local_host_info(inet) of
+ {ok, #{flags := Flags}} ->
+ case lists:member(multicast, Flags) of
+ true ->
+ ok;
+ false ->
+ not_supported(multicast)
+ end;
+ {error, Reason} ->
+ not_supported({multicast, Reason})
+ end;
+ {unix, OsName} ->
+ skip(?F("Not Supported: platform ~w", [OsName]));
+ Type ->
+ skip(?F("Not Supported: platform ~p", [Type]))
+ end.
+
+has_support_sock_acceptconn() ->
+ has_support_socket_option_sock(acceptconn).
+
+has_support_sock_bindtodevice() ->
+ has_support_socket_option_sock(bindtodevice).
+
+has_support_sock_broadcast() ->
+ has_support_socket_option_sock(broadcast),
+ case ?LIB:which_local_host_info(inet) of
+ {ok, #{flags := Flags}} ->
+ case lists:member(broadcast, Flags) of
+ true ->
+ ok;
+ false ->
+ not_supported({broadcast, Flags})
+ end;
{error, Reason} ->
- ?FAIL({inet, getifaddrs, Reason})
+ not_supported({broadcast, Reason})
end.
-which_addr(_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)
- end;
-which_addr(Domain, [_|IFL]) ->
- which_addr(Domain, IFL).
+has_support_sock_debug() ->
+ has_support_socket_option_sock(debug).
-which_addr2(_Domain, []) ->
- {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).
+has_support_sock_domain() ->
+ has_support_socket_option_sock(domain).
+has_support_sock_dontroute() ->
+ has_support_socket_option_sock(dontroute).
+has_support_sock_keepalive() ->
+ has_support_socket_option_sock(keepalive).
+has_support_ip_add_membership() ->
+ has_support_socket_option_ip(add_membership).
+
+has_support_ip_drop_membership() ->
+ has_support_socket_option_ip(drop_membership).
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Here are all the *general* test vase condition functions.
+has_support_socket_option_ip(Opt) ->
+ has_support_socket_option(ip, Opt).
+
+has_support_socket_option_sock(Opt) ->
+ has_support_socket_option(socket, Opt).
+
+has_support_socket_option(Level, Option) ->
+ case socket:supports(options, Level, Option) of
+ true ->
+ ok;
+ false ->
+ skip(?F("Not Supported: ~w option ~w", [Level, Option]))
+ end.
+
+
+
+
+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.
%% Currently we just skip.
has_support_ipv6() ->
- %% case socket:supports(ipv6) of
- %% true ->
- %% ok;
- %% false ->
- %% {error, not_supported}
- %% end.
- not_yet_implemented().
+ ?LIB: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").