aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-10-30 18:26:10 +0100
committerMicael Karlberg <[email protected]>2018-10-30 18:26:10 +0100
commit3f46e8a184a503ead01674ee180e7222b3928712 (patch)
tree4a4f245517d476d3f7e82949b9988750c9664bc7 /erts
parent06f79ae03385ad668b143f4f1f7085131c2973ed (diff)
downloadotp-3f46e8a184a503ead01674ee180e7222b3928712.tar.gz
otp-3f46e8a184a503ead01674ee180e7222b3928712.tar.bz2
otp-3f46e8a184a503ead01674ee180e7222b3928712.zip
[socket-nif] Add a send and receive chunks test case
The send and recv test case triggered a two bugs. One was that there was no re-selecting when only a portion of the data was received (which meant that we stopped reading). Also, the wrong 'current' (writer) was reset when demonitor current reader after a successful read (which meant that future readers would never have been monitored). OTP-14831
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/nifs/common/socket_nif.c20
-rw-r--r--erts/emulator/test/socket_SUITE.erl1568
-rw-r--r--erts/preloaded/ebin/socket.beambin68544 -> 68564 bytes
-rw-r--r--erts/preloaded/src/socket.erl11
4 files changed, 1305 insertions, 294 deletions
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index f9eb041ad1..27395b5cf6 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -13479,7 +13479,7 @@ ERL_NIF_TERM recv_update_current_reader(ErlNifEnv* env,
descP->currentReader.ref);
} else {
- descP->currentWriterP = NULL;
+ descP->currentReaderP = NULL;
}
}
@@ -13744,14 +13744,23 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
} else {
/* +++ We got only a part of what was expected +++
- * +++ => receive more later. +++ */
+ * +++ => select for more more later and +++
+ * +++ deliver what we got. +++ */
SSDBG( descP, ("SOCKET", "recv_check_result -> [%d] "
"only part of message - expect more\r\n", toRead) );
+ /* SELECT for more data */
+
+ SELECT(env, descP->sock, (ERL_NIF_SELECT_READ),
+ descP, NULL, recvRef);
+
cnt_inc(&descP->readByteCnt, read);
- return esock_make_ok3(env, atom_false, MKBIN(env, bufP));
+ data = MKBIN(env, bufP);
+ data = MKSBIN(env, data, 0, read);
+
+ return esock_make_ok3(env, atom_false, data);
}
}
}
@@ -16709,7 +16718,7 @@ int esock_monitor(const char* slogan,
int res;
SSDBG( descP, ("SOCKET", "[%d] %s: try monitor", descP->sock, slogan) );
- // esock_dbg_printf("MONP", "[%d] %s\r\n", descP->sock, slogan);
+ /* esock_dbg_printf("MONP", "[%d] %s\r\n", descP->sock, slogan); */
res = enif_monitor_process(env, descP, pid, &monP->mon);
if (res != 0) {
@@ -16722,7 +16731,7 @@ int esock_monitor(const char* slogan,
descP->sock,
monP->raw[0], monP->raw[1],
monP->raw[2], monP->raw[3]);
- } */
+ } */
return res;
}
@@ -16737,6 +16746,7 @@ int esock_demonitor(const char* slogan,
int res;
SSDBG( descP, ("SOCKET", "[%d] %s: try demonitor\r\n", descP->sock, slogan) );
+
/*
esock_dbg_printf("DEMONP", "[%d] %s: %u,%u,%u,%u\r\n",
descP->sock, slogan,
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index 3308b9364e..7a1a362181 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -84,10 +84,11 @@
sc_rc_recv_response_tcp4/1,
sc_rc_recv_response_tcp6/1,
sc_rc_recvmsg_response_tcp4/1,
- sc_rc_recvmsg_response_tcp6/1
+ sc_rc_recvmsg_response_tcp6/1,
%% Traffic
-
+ traffic_send_and_recv_chunks_tcp4/1,
+ traffic_send_and_recv_chunks_tcp6/1
%% Tickets
@@ -99,21 +100,6 @@
%% Internal exports
%% -export([]).
-%% -record(ev, {name :: string(),
-%% pid :: pid(),
-%% mref :: reference()}).
-%% -type ev() :: #ev{}.
--define(MKEV(N,P,R), #ev{name = N, pid = P, mref = R}).
-%% -type initial_evaluator_state() :: map().
-%% -type evaluator_state() :: map().
-%% -type command_fun() ::
-%% fun((State :: evaluator_state()) -> ok) |
-%% fun((State :: evaluator_state()) -> {ok, evaluator_state()}) |
-%% fun((State :: evaluator_state()) -> {error, term()}).
-
-%% -type command() :: #{desc := string(),
-%% cmd := command_fun()}.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -139,7 +125,8 @@ suite() ->
all() ->
[
{group, api},
- {group, socket_closure}
+ {group, socket_closure},
+ {group, traffic}
%% {group, tickets}
].
@@ -151,7 +138,8 @@ groups() ->
{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_close, [], sc_rc_cases()},
+ {traffic, [], traffic_cases()}
%% {tickets, [], ticket_cases()}
].
@@ -252,8 +240,11 @@ sc_rc_cases() ->
].
-%% traffic_cases() ->
-%% [snr_send_and_recv_chunks].
+traffic_cases() ->
+ [
+ traffic_send_and_recv_chunks_tcp4,
+ traffic_send_and_recv_chunks_tcp6
+ ].
%% ticket_cases() ->
@@ -881,8 +872,7 @@ api_b_send_and_recv_tcp(InitState) ->
end},
#{desc => "await client ready (init)",
cmd => fun(#{client := Pid} = _State) ->
- ?SEV_AWAIT_READY(Pid, client, init),
- ok
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
end},
%% *** The actual test ***
@@ -4315,6 +4305,439 @@ sc_lc_recvmsg_response_udp6(_Config) when is_list(_Config) ->
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 IPv4.
+
+sc_lc_acceptor_response_tcp4(suite) ->
+ [];
+sc_lc_acceptor_response_tcp4(doc) ->
+ [];
+sc_lc_acceptor_response_tcp4(_Config) when is_list(_Config) ->
+ 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).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 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 IPv6.
+
+sc_lc_acceptor_response_tcp6(suite) ->
+ [];
+sc_lc_acceptor_response_tcp6(doc) ->
+ [];
+sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) ->
+ tc_try(sc_lc_acceptor_response_tcp6,
+ fun() ->
+ not_yet_implemented(),
+ ?TT(?SECS(10)),
+ InitState = #{domain => inet,
+ type => stream,
+ protocol => tcp},
+ ok = sc_lc_acceptor_response_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sc_lc_acceptor_response_tcp(InitState) ->
+ PrimAcceptorSeq =
+ [
+ %% *** Wait for start order part ***
+ #{desc => "await start (from tester)",
+ 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) ->
+ LAddr = which_local_addr(Domain),
+ LSA = #{family => Domain, addr => LAddr},
+ {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
+ {ok, Sock} ->
+ {ok, State#{sock => Sock}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "bind to local address",
+ cmd => fun(#{sock := Sock, lsa := LSA} = _State) ->
+ case socket:bind(Sock, LSA) of
+ {ok, _Port} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "make listen socket",
+ cmd => fun(#{sock := Sock}) ->
+ socket:listen(Sock)
+ end},
+ #{desc => "announce ready (init)",
+ cmd => fun(#{tester := Tester, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_READY(Tester, init, Sock),
+ ok
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_CONTINUE(Tester, tester, accept) of
+ {ok, Timeout} ->
+ {ok, State#{timeout => Timeout}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "await connection",
+ cmd => fun(#{sock := Sock, timeout := Timeout} = _State) ->
+ case socket:accept(Sock, Timeout) of
+ {error, timeout} ->
+ ok;
+ {ok, Sock} ->
+ ?SEV_EPRINT("unexpected success"),
+ (catch socket:close(Sock)),
+ {error, unexpected_success};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept timeout)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_timeout),
+ ok
+ end},
+ #{desc => "await continue (close)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ok = ?SEV_AWAIT_CONTINUE(Tester, tester, close)
+ end},
+ #{desc => "close socket",
+ cmd => fun(#{sock := Sock} = State) ->
+ case socket:close(Sock) of
+ ok ->
+ {ok, maps:remove(sock, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (close)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, close),
+ 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
+ ],
+
+ SecAcceptorSeq =
+ [
+ %% *** Init 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)
+ end},
+
+ %% The actual test
+ #{desc => "await continue (accept)",
+ cmd => fun(#{tester := Tester} = _State) ->
+ ok = ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ end},
+ #{desc => "accept",
+ cmd => fun(#{sock := Sock} = State) ->
+ case socket:accept(Sock) of
+ {error, closed} ->
+ {ok, maps:remove(sock, State)};
+ {ok, _} ->
+ {error, unexpected_success};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (accept closed)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, accept_closed)
+ 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},
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+ TesterSeq =
+ [
+ %% *** Init part ***
+ #{desc => "monitor 'primary acceptor'",
+ cmd => fun(#{prim_acc := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor 'secondary acceptor 1'",
+ cmd => fun(#{sec_acc1 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor secondary acceptor 2",
+ cmd => fun(#{sec_acc2 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "monitor secondary acceptor 3",
+ cmd => fun(#{sec_acc3 := Pid} = _State) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ %% Start the primary server
+ #{desc => "order 'primary acceptor' start",
+ cmd => fun(#{prim_acc := Pid} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid),
+ ok
+ end},
+ #{desc => "await 'primary acceptor' ready (init)",
+ cmd => fun(#{prim_acc := Pid} = State) ->
+ {ok, Sock} = ?SEV_AWAIT_READY(Pid, prim_acc, init),
+ {ok, State#{sock => Sock}}
+ end},
+
+ %% Start the secondary acceptor 1
+ #{desc => "order 'secondary acceptor 1' start",
+ cmd => fun(#{sec_acc1 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await 'secondary acceptor 1' ready (init)",
+ cmd => fun(#{sec_acc1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, sec_acc1, init)
+ end},
+
+ %% Start the secondary acceptor 2
+ #{desc => "order 'secondary acceptor 2' start",
+ cmd => fun(#{sec_acc2 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await 'secondary acceptor 2' ready (init)",
+ cmd => fun(#{sec_acc2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, sec_acc2, init)
+ end},
+
+ %% Start the secondary acceptor 3
+ #{desc => "order 'secondary acceptor 3' start",
+ cmd => fun(#{sec_acc3 := Pid, sock := Sock} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, Sock),
+ ok
+ end},
+ #{desc => "await 'secondary acceptor 3' ready (init)",
+ cmd => fun(#{sec_acc3 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, sec_acc3, init)
+ end},
+
+
+ %% The actual test
+ %% Make all the seondary servers continue, with an infinit recvfrom
+ %% and then the prim-server with a timed recvfrom.
+ %% After the prim server notifies us (about the timeout) we order it
+ %% to close the socket, which should cause the all the secondary
+ %% server to return with error-closed.
+
+ #{desc => "order 'secondary acceptor 1' to continue (accept)",
+ cmd => fun(#{sec_acc1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ ?SEV_SLEEP(?SECS(1)),
+ #{desc => "order 'secondary acceptor 2' to continue (accept)",
+ cmd => fun(#{sec_acc2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ ?SEV_SLEEP(?SECS(1)),
+ #{desc => "order 'secondary acceptor 3' to continue (accept)",
+ cmd => fun(#{sec_acc3 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
+ ok
+ end},
+ ?SEV_SLEEP(?SECS(1)),
+ #{desc => "order 'primary acceptor' to continue",
+ cmd => fun(#{prim_acc := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, accept, ?SECS(5)),
+ ok
+ end},
+ #{desc => "await 'primary acceptor' ready (accept timeout)",
+ cmd => fun(#{prim_acc := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, prim_acc, accept_timeout)
+ end},
+ #{desc => "order 'primary acceptor' to continue (close)",
+ cmd => fun(#{prim_acc := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, close),
+ ok
+ end},
+ #{desc => "await 'primary acceptor' ready (close)",
+ cmd => fun(#{prim_acc := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, prim_acc, close)
+ end},
+ #{desc => "await 'secondary acceptor 1' ready (accept closed)",
+ cmd => fun(#{sec_acc1 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, sec_acc1, accept_closed)
+ end},
+ #{desc => "await 'secondary acceptor 2' ready (accept closed)",
+ cmd => fun(#{sec_acc2 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, sec_acc2, accept_closed)
+ end},
+ #{desc => "await 'secondary acceptor 3' ready (accept closed)",
+ cmd => fun(#{sec_acc3 := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, sec_acc3, accept_closed)
+ end},
+
+
+ %% Terminations
+ #{desc => "order 'secondary acceptor 3' to terminate",
+ cmd => fun(#{sec_acc3 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await 'secondary acceptor 3' termination",
+ cmd => fun(#{sec_acc3 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ {ok, maps:remove(sec_acc3, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order 'secondary acceptor 2' to terminate",
+ cmd => fun(#{sec_acc2 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await 'secondary acceptor 2' termination",
+ cmd => fun(#{sec_acc2 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ {ok, maps:remove(sec_acc2, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order 'secondary acceptor 1' to terminate",
+ cmd => fun(#{sec_acc1 := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await 'secondary acceptor 1' termination",
+ cmd => fun(#{sec_acc1 := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ {ok, maps:remove(sec_acc1, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order 'primary acceptor' to terminate",
+ cmd => fun(#{prim_acc := Pid} = _State) ->
+ ?SEV_ANNOUNCE_TERMINATE(Pid),
+ ok
+ end},
+ #{desc => "await 'primary acceptor' termination",
+ cmd => fun(#{prim_acc := Pid} = State) ->
+ case ?SEV_AWAIT_TERMINATION(Pid) of
+ ok ->
+ {ok, maps:remove(prim_acc, State)};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+
+ %% *** We are done ***
+ ?SEV_FINISH_NORMAL
+ ],
+
+
+ i("start 'primary acceptor' evaluator"),
+ PrimAccInitState = InitState,
+ PrimAcc = ?SEV_START("prim-acceptor", PrimAcceptorSeq, PrimAccInitState),
+
+ i("start 'secondary acceptor 1' evaluator"),
+ SecAccInitState = #{},
+ SecAcc1 = ?SEV_START("sec-acceptor-1", SecAcceptorSeq, SecAccInitState),
+
+ i("start 'secondary acceptor 2' evaluator"),
+ SecAcc2 = ?SEV_START("sec-acceptor-2", SecAcceptorSeq, SecAccInitState),
+
+ i("start 'secondary acceptor 3' evaluator"),
+ SecAcc3 = ?SEV_START("sec-acceptor-3", SecAcceptorSeq, SecAccInitState),
+
+ i("start 'tester' evaluator"),
+ TesterInitState = #{prim_acc => PrimAcc#ev.pid,
+ sec_acc1 => SecAcc1#ev.pid,
+ sec_acc2 => SecAcc2#ev.pid,
+ sec_acc3 => SecAcc3#ev.pid},
+ Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
+
+ i("await evaluator"),
+ ok = ?SEV_AWAIT_FINISH([PrimAcc, SecAcc1, SecAcc2, SecAcc3, Tester]).
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This test case is intended to test what happens when a socket is
%% remotely closed while the process is calling the recv function.
@@ -4421,7 +4844,7 @@ sc_rc_receive_response_tcp(InitState) ->
ok
end},
- %% The actual test (we expect three connections)
+ %% The actual test
#{desc => "await continue (accept all three connections)",
cmd => fun(#{tester := Tester} = _State) ->
?SEV_ANNOUNCE_CONTINUE(Tester, tester, accept)
@@ -5048,32 +5471,6 @@ sc_rc_receive_response_tcp(InitState) ->
Tester]).
-start_node(Host, NodeName) ->
- UniqueNodeName = f("~w_~w", [NodeName, erlang:unique_integer([positive])]),
- case do_start_node(Host, UniqueNodeName) of
- {ok, _} = OK ->
- OK;
- {error, Reason, _} ->
- {error, Reason}
- end.
-
-do_start_node(Host, NodeName) when is_list(NodeName) ->
- do_start_node(Host, list_to_atom(NodeName));
-do_start_node(Host, NodeName) when is_atom(NodeName) ->
- Dir = filename:dirname(code:which(?MODULE)),
- Flags = "-pa " ++ Dir,
- Opts = [{monitor_master, true}, {erl_flags, Flags}],
- ct_slave:start(Host, NodeName, Opts).
-
-
-stop_node(Node) ->
- case ct_slave:stop(Node) of
- {ok, _} ->
- ok;
- {error, _} = ERROR ->
- ERROR
- end.
-
local_host() ->
try net_adm:localhost() of
Host when is_list(Host) ->
@@ -5275,57 +5672,52 @@ sc_rc_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 accept function.
-%% We test what happens with a non-controlling_process also, since we
-%% git the setup anyway.
+%% 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 IPv4.
-sc_lc_acceptor_response_tcp4(suite) ->
+traffic_send_and_recv_chunks_tcp4(suite) ->
[];
-sc_lc_acceptor_response_tcp4(doc) ->
+traffic_send_and_recv_chunks_tcp4(doc) ->
[];
-sc_lc_acceptor_response_tcp4(_Config) when is_list(_Config) ->
- tc_try(sc_lc_acceptor_response_tcp4,
+traffic_send_and_recv_chunks_tcp4(_Config) when is_list(_Config) ->
+ tc_try(traffic_send_and_recv_chunks_tcp4,
fun() ->
- ?TT(?SECS(10)),
- InitState = #{domain => inet,
- type => stream,
- protocol => tcp},
- ok = sc_lc_acceptor_response_tcp(InitState)
+ ?TT(?SECS(30)),
+ InitState = #{domain => inet},
+ ok = traffic_send_and_recv_chunks_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.
+%% 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 IPv6.
-sc_lc_acceptor_response_tcp6(suite) ->
+traffic_send_and_recv_chunks_tcp6(suite) ->
[];
-sc_lc_acceptor_response_tcp6(doc) ->
+traffic_send_and_recv_chunks_tcp6(doc) ->
[];
-sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) ->
- tc_try(sc_lc_acceptor_response_tcp6,
+traffic_send_and_recv_chunks_tcp6(_Config) when is_list(_Config) ->
+ tc_try(traffic_send_and_recv_chunks_tcp6,
fun() ->
not_yet_implemented(),
- ?TT(?SECS(10)),
- InitState = #{domain => inet,
- type => stream,
- protocol => tcp},
- ok = sc_lc_acceptor_response_tcp(InitState)
+ ?TT(?SECS(30)),
+ InitState = #{domain => inet6},
+ ok = traffic_send_and_recv_chunks_tcp(InitState)
end).
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-sc_lc_acceptor_response_tcp(InitState) ->
- PrimAcceptorSeq =
+traffic_send_and_recv_chunks_tcp(InitState) ->
+ ServerSeq =
[
%% *** Wait for start order part ***
- #{desc => "await start (from tester)",
+ #{desc => "await start",
cmd => fun(State) ->
Tester = ?SEV_AWAIT_START(),
{ok, State#{tester => Tester}}
@@ -5341,87 +5733,213 @@ sc_lc_acceptor_response_tcp(InitState) ->
cmd => fun(#{domain := Domain} = State) ->
LAddr = which_local_addr(Domain),
LSA = #{family => Domain, addr => LAddr},
- {ok, State#{lsa => LSA}}
+ {ok, State#{local_sa => LSA}}
end},
- #{desc => "create (listen) socket",
- cmd => fun(#{domain := Domain,
- type := Type,
- protocol := Proto} = State) ->
- case socket:open(Domain, Type, Proto) of
+ #{desc => "create listen socket",
+ cmd => fun(#{domain := Domain} = State) ->
+ case socket:open(Domain, stream, tcp) of
{ok, Sock} ->
- {ok, State#{sock => Sock}};
+ {ok, State#{lsock => Sock}};
{error, _} = ERROR ->
ERROR
end
end},
#{desc => "bind to local address",
- cmd => fun(#{sock := Sock, lsa := LSA} = _State) ->
- case socket:bind(Sock, LSA) of
- {ok, _Port} ->
- ok;
+ cmd => fun(#{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(#{sock := Sock}) ->
- socket:listen(Sock)
+ cmd => fun(#{lsock := LSock}) ->
+ socket:listen(LSock)
end},
#{desc => "announce ready (init)",
- cmd => fun(#{tester := Tester, sock := Sock} = _State) ->
- ?SEV_ANNOUNCE_READY(Tester, init, Sock),
+ cmd => fun(#{tester := Tester, local_sa := LSA, lport := Port}) ->
+ ServerSA = LSA#{port => Port},
+ ?SEV_ANNOUNCE_READY(Tester, init, ServerSA),
ok
end},
-
+
%% The actual test
#{desc => "await continue (accept)",
- cmd => fun(#{tester := Tester} = State) ->
- case ?SEV_AWAIT_CONTINUE(Tester, tester, accept) of
- {ok, Timeout} ->
- {ok, State#{timeout => Timeout}};
- {error, _} = ERROR ->
- ERROR
- end
+ cmd => fun(#{tester := Tester} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
end},
- #{desc => "await connection",
- cmd => fun(#{sock := Sock, timeout := Timeout} = _State) ->
- case socket:accept(Sock, Timeout) of
- {error, timeout} ->
- ok;
+ #{desc => "accept",
+ cmd => fun(#{lsock := LSock} = State) ->
+ case socket:accept(LSock) of
{ok, Sock} ->
- ?SEV_EPRINT("unexpected success"),
- (catch socket:close(Sock)),
- {error, unexpected_success};
+ {ok, State#{csock => Sock}};
{error, _} = ERROR ->
ERROR
end
end},
- #{desc => "announce ready (accept timeout)",
+ #{desc => "announce ready (accept)",
cmd => fun(#{tester := Tester}) ->
- ?SEV_ANNOUNCE_READY(Tester, accept_timeout),
+ ?SEV_ANNOUNCE_READY(Tester, accept),
ok
end},
- #{desc => "await continue (close)",
+
+ #{desc => "await continue (recv-many-small)",
cmd => fun(#{tester := Tester} = _State) ->
- ok = ?SEV_AWAIT_CONTINUE(Tester, tester, close)
+ ?SEV_AWAIT_CONTINUE(Tester, tester, recv_many_small)
end},
- #{desc => "close socket",
- cmd => fun(#{sock := Sock} = State) ->
- case socket:close(Sock) of
- ok ->
- {ok, maps:remove(sock, State)};
+ #{desc => "recv chunk 1",
+ cmd => fun(#{csock := Sock} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 1 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)]}};
{error, _} = ERROR ->
ERROR
end
end},
- #{desc => "announce ready (close)",
- cmd => fun(#{tester := Tester}) ->
- ?SEV_ANNOUNCE_READY(Tester, close),
- ok
+ #{desc => "recv chunk 2",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 2 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv chunk 3",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 3 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv chunk 4",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 4 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv chunk 5",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 5 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv chunk 6",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 6 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv chunk 7",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 7 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv chunk 8",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 8 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv chunk 9",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 9 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv chunk 10",
+ cmd => fun(#{csock := Sock,
+ chunks := Chunks} = State) ->
+ case socket:recv(Sock, 100) of
+ {ok, Chunk} ->
+ ?SEV_IPRINT("recv of chunk 10 of ~p bytes",
+ [size(Chunk)]),
+ {ok, State#{chunks => [b2l(Chunk)|Chunks]}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (recv-many-small)",
+ cmd => fun(#{tester := Tester,
+ chunks := Chunks} = State) ->
+ Data = lists:flatten(lists:reverse(Chunks)),
+ ?SEV_ANNOUNCE_READY(Tester, recv_many_small, Data),
+ {ok, maps:remove(chunks, State)}
end},
- % Termination
- #{desc => "await terminate",
+ #{desc => "await continue (recv-one-big)",
+ cmd => fun(#{tester := Tester} = State) ->
+ case ?SEV_AWAIT_CONTINUE(Tester, tester, recv_one_big) of
+ {ok, Size} ->
+ {ok, State#{size => Size}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "recv (one big)",
+ cmd => fun(#{tester := Tester, csock := Sock, size := Size} = _State) ->
+ %% ok = socket:setopt(Sock, otp, debug, true),
+ case socket:recv(Sock, Size) of
+ {ok, Data} ->
+ %% ok = socket:setopt(Sock, otp, debug, false),
+ ?SEV_ANNOUNCE_READY(Tester,
+ recv_one_big,
+ b2l(Data)),
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "await terminate (from tester)",
cmd => fun(#{tester := Tester} = State) ->
case ?SEV_AWAIT_TERMINATE(Tester, tester) of
ok ->
@@ -5429,61 +5947,419 @@ sc_lc_acceptor_response_tcp(InitState) ->
{error, _} = ERROR ->
ERROR
end
- 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(#{lsock := Sock} = State) ->
+ (catch socket:close(Sock)),
+ {ok, maps:remove(lsock, State)}
+ end},
%% *** We are done ***
?SEV_FINISH_NORMAL
],
- SecAcceptorSeq =
+ ClientSeq =
[
- %% *** Init part ***
+ %% *** Wait for start order part ***
#{desc => "await start",
cmd => fun(State) ->
- {Tester, Sock} = ?SEV_AWAIT_START(),
- {ok, State#{tester => Tester, sock => Sock}}
+ {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 => "create node",
+ cmd => fun(#{host := Host} = State) ->
+ case start_node(Host, client) of
+ {ok, Node} ->
+ ?SEV_IPRINT("(remote) client node ~p started",
+ [Node]),
+ {ok, State#{node => Node}};
+ {error, Reason, _} ->
+ {error, Reason}
+ end
+ end},
+ #{desc => "monitor client node",
+ cmd => fun(#{node := Node} = _State) ->
+ true = erlang:monitor_node(Node, true),
+ ok
+ end},
+ #{desc => "start remote client",
+ cmd => fun(#{node := Node} = State) ->
+ Pid = traffic_snr_tcp_client_start(Node),
+ ?SEV_IPRINT("client ~p started", [Pid]),
+ {ok, State#{rclient => Pid}}
+ end},
+ #{desc => "monitor remote client",
+ cmd => fun(#{rclient := Pid}) ->
+ _MRef = erlang:monitor(process, Pid),
+ ok
+ end},
+ #{desc => "order remote client to start",
+ cmd => fun(#{rclient := Client, server_sa := ServerSA}) ->
+ ?SEV_ANNOUNCE_START(Client, ServerSA),
+ ok
+ end},
+ #{desc => "await remote client ready",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, rclient, init,
+ [{tester, Tester}])
+ end},
#{desc => "announce ready (init)",
cmd => fun(#{tester := Tester}) ->
- ?SEV_ANNOUNCE_READY(Tester, init)
+ ?SEV_ANNOUNCE_READY(Tester, init),
+ ok
end},
%% The actual test
- #{desc => "await continue (accept)",
- cmd => fun(#{tester := Tester} = _State) ->
- ok = ?SEV_AWAIT_CONTINUE(Tester, tester, accept)
+ #{desc => "await continue (connect)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ ?SEV_AWAIT_CONTINUE(Tester, tester, connect,
+ [{rclient, Client}]),
+ ok
end},
- #{desc => "accept",
- cmd => fun(#{sock := Sock} = State) ->
- case socket:accept(Sock) of
- {error, closed} ->
- {ok, maps:remove(sock, State)};
- {ok, _} ->
- {error, unexpected_success};
+ #{desc => "order remote client to continue (connect)",
+ cmd => fun(#{rclient := Client}) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, connect),
+ ok
+ end},
+ #{desc => "await client process ready (connect)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, rclient, connect,
+ [{tester, Tester}])
+ end},
+ #{desc => "announce ready (connect)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, connect),
+ ok
+ end},
+
+ #{desc => "await continue (send-one-big)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = State) ->
+ case ?SEV_AWAIT_CONTINUE(Tester, tester,
+ send_one_big,
+ [{rclient, Client}]) of
+ {ok, Data} ->
+ {ok, State#{data => Data}};
{error, _} = ERROR ->
ERROR
end
end},
- #{desc => "announce ready (accept closed)",
+ #{desc => "order remote client to continue (send)",
+ cmd => fun(#{rclient := Client, data := Data}) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Data),
+ ok
+ end},
+ #{desc => "await client process ready (send)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (send-one-big)",
cmd => fun(#{tester := Tester}) ->
- ?SEV_ANNOUNCE_READY(Tester, accept_closed)
+ ?SEV_ANNOUNCE_READY(Tester, send_one_big),
+ ok
+ end},
+
+ #{desc => "await continue (send-many-small)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = State) ->
+ case ?SEV_AWAIT_CONTINUE(Tester, tester,
+ send_many_small,
+ [{rclient, Client}]) of
+ {ok, Data} ->
+ {ok, State#{data => Data}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 1)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 1: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 1)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 2)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 2: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 2)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 3)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 3: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 3)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 4)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 4: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 4)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 5)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 5: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 5)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 6)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 6: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 6)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 7)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 7: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 7)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 8)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 8: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 8)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 9)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, RestData} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 9: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, State#{data => RestData}}
+ end},
+ #{desc => "await client process ready (send chunk 9)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send chunk 10)",
+ cmd => fun(#{rclient := Client,
+ data := Data} = State) ->
+ {Chunk, []} = lists:split(100, Data),
+ %% ?SEV_IPRINT("order send of chunk 10: "
+ %% "~n Size: ~p"
+ %% "~n ~p", [length(Chunk), Chunk]),
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, Chunk),
+ {ok, maps:remove(data, State)}
+ end},
+ #{desc => "await client process ready (send chunk 10)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "order remote client to continue (send stop)",
+ cmd => fun(#{rclient := Client} = State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Client, send, stop),
+ {ok, maps:remove(data, State)}
+ end},
+ #{desc => "await client process ready (send stop)",
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = _State) ->
+ case ?SEV_AWAIT_READY(Client, rclient, send,
+ [{tester, Tester}]) of
+ {ok, Result} ->
+ Result;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+ #{desc => "announce ready (send-many-small)",
+ cmd => fun(#{tester := Tester}) ->
+ ?SEV_ANNOUNCE_READY(Tester, send_many_small),
+ ok
end},
%% Termination
#{desc => "await terminate (from tester)",
- cmd => fun(#{tester := Tester} = State) ->
- case ?SEV_AWAIT_TERMINATE(Tester, tester) of
+ cmd => fun(#{tester := Tester,
+ rclient := Client} = State) ->
+ case ?SEV_AWAIT_TERMINATE(Tester, tester,
+ [{rclient, Client}]) of
ok ->
{ok, maps:remove(tester, State)};
{error, _} = ERROR ->
ERROR
end
end},
+ #{desc => "kill remote client",
+ cmd => fun(#{rclient := Client}) ->
+ ?SEV_ANNOUNCE_TERMINATE(Client),
+ ok
+ end},
+ #{desc => "await remote client termination",
+ cmd => fun(#{rclient := Client} = State) ->
+ ?SEV_AWAIT_TERMINATION(Client),
+ State1 = maps:remove(rclient, State),
+ {ok, State1}
+ end},
+ #{desc => "stop client node",
+ cmd => fun(#{node := Node} = _State) ->
+ stop_node(Node)
+ end},
+ #{desc => "await client node termination",
+ cmd => fun(#{node := Node} = State) ->
+ receive
+ {nodedown, Node} ->
+ {ok, maps:remove(node, State)}
+ end
+ end},
%% *** We are done ***
?SEV_FINISH_NORMAL
@@ -5492,183 +6368,167 @@ sc_lc_acceptor_response_tcp(InitState) ->
TesterSeq =
[
%% *** Init part ***
- #{desc => "monitor 'primary acceptor'",
- cmd => fun(#{prim_acc := Pid} = _State) ->
- _MRef = erlang:monitor(process, Pid),
- ok
- end},
- #{desc => "monitor 'secondary acceptor 1'",
- cmd => fun(#{sec_acc1 := Pid} = _State) ->
- _MRef = erlang:monitor(process, Pid),
- ok
- end},
- #{desc => "monitor secondary acceptor 2",
- cmd => fun(#{sec_acc2 := Pid} = _State) ->
+ #{desc => "monitor server",
+ cmd => fun(#{server := Pid} = _State) ->
_MRef = erlang:monitor(process, Pid),
ok
end},
- #{desc => "monitor secondary acceptor 3",
- cmd => fun(#{sec_acc3 := Pid} = _State) ->
+ #{desc => "monitor client",
+ cmd => fun(#{client := Pid} = _State) ->
_MRef = erlang:monitor(process, Pid),
ok
end},
- %% Start the primary server
- #{desc => "order 'primary acceptor' start",
- cmd => fun(#{prim_acc := Pid} = _State) ->
+ %% Start the server
+ #{desc => "order server start",
+ cmd => fun(#{server := Pid} = _State) ->
?SEV_ANNOUNCE_START(Pid),
ok
end},
- #{desc => "await 'primary acceptor' ready (init)",
- cmd => fun(#{prim_acc := Pid} = State) ->
- {ok, Sock} = ?SEV_AWAIT_READY(Pid, prim_acc, init),
- {ok, State#{sock => Sock}}
- end},
-
- %% Start the secondary acceptor 1
- #{desc => "order 'secondary acceptor 1' start",
- cmd => fun(#{sec_acc1 := Pid, sock := Sock} = _State) ->
- ?SEV_ANNOUNCE_START(Pid, Sock),
- ok
- end},
- #{desc => "await 'secondary acceptor 1' ready (init)",
- cmd => fun(#{sec_acc1 := Pid} = _State) ->
- ok = ?SEV_AWAIT_READY(Pid, sec_acc1, init)
- end},
-
- %% Start the secondary acceptor 2
- #{desc => "order 'secondary acceptor 2' start",
- cmd => fun(#{sec_acc2 := Pid, sock := Sock} = _State) ->
- ?SEV_ANNOUNCE_START(Pid, Sock),
- ok
- end},
- #{desc => "await 'secondary acceptor 2' ready (init)",
- cmd => fun(#{sec_acc2 := Pid} = _State) ->
- ok = ?SEV_AWAIT_READY(Pid, sec_acc2, init)
+ #{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 secondary acceptor 3
- #{desc => "order 'secondary acceptor 3' start",
- cmd => fun(#{sec_acc3 := Pid, sock := Sock} = _State) ->
- ?SEV_ANNOUNCE_START(Pid, Sock),
+ %% Start the client
+ #{desc => "order client start",
+ cmd => fun(#{client := Pid,
+ server_sa := ServerSA} = _State) ->
+ ?SEV_ANNOUNCE_START(Pid, ServerSA),
ok
end},
- #{desc => "await 'secondary acceptor 3' ready (init)",
- cmd => fun(#{sec_acc3 := Pid} = _State) ->
- ok = ?SEV_AWAIT_READY(Pid, sec_acc3, init)
+ #{desc => "await client ready (init)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ok = ?SEV_AWAIT_READY(Pid, client, init)
end},
-
-
+
%% The actual test
- %% Make all the seondary servers continue, with an infinit recvfrom
- %% and then the prim-server with a timed recvfrom.
- %% After the prim server notifies us (about the timeout) we order it
- %% to close the socket, which should cause the all the secondary
- %% server to return with error-closed.
-
- #{desc => "order 'secondary acceptor 1' to continue (accept)",
- cmd => fun(#{sec_acc1 := Pid} = _State) ->
- ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
- ok
- end},
- ?SEV_SLEEP(?SECS(1)),
- #{desc => "order 'secondary acceptor 2' to continue (accept)",
- cmd => fun(#{sec_acc2 := Pid} = _State) ->
- ?SEV_ANNOUNCE_CONTINUE(Pid, accept),
- ok
- end},
- ?SEV_SLEEP(?SECS(1)),
- #{desc => "order 'secondary acceptor 3' to continue (accept)",
- cmd => fun(#{sec_acc3 := Pid} = _State) ->
+ #{desc => "order server continue (accept)",
+ cmd => fun(#{server := Pid} = _State) ->
?SEV_ANNOUNCE_CONTINUE(Pid, accept),
ok
end},
?SEV_SLEEP(?SECS(1)),
- #{desc => "order 'primary acceptor' to continue",
- cmd => fun(#{prim_acc := Pid} = _State) ->
- ?SEV_ANNOUNCE_CONTINUE(Pid, accept, ?SECS(5)),
+ #{desc => "order client continue (connect)",
+ cmd => fun(#{client := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, connect),
ok
end},
- #{desc => "await 'primary acceptor' ready (accept timeout)",
- cmd => fun(#{prim_acc := Pid} = _State) ->
- ok = ?SEV_AWAIT_READY(Pid, prim_acc, accept_timeout)
- end},
- #{desc => "order 'primary acceptor' to continue (close)",
- cmd => fun(#{prim_acc := Pid} = _State) ->
- ?SEV_ANNOUNCE_CONTINUE(Pid, close),
+ #{desc => "await server ready (accept)",
+ cmd => fun(#{server := Server,
+ client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Server, server, accept,
+ [{client, Client}]),
ok
end},
- #{desc => "await 'primary acceptor' ready (close)",
- cmd => fun(#{prim_acc := Pid} = _State) ->
- ok = ?SEV_AWAIT_READY(Pid, prim_acc, close)
- end},
- #{desc => "await 'secondary acceptor 1' ready (accept closed)",
- cmd => fun(#{sec_acc1 := Pid} = _State) ->
- ok = ?SEV_AWAIT_READY(Pid, sec_acc1, accept_closed)
- end},
- #{desc => "await 'secondary acceptor 2' ready (accept closed)",
- cmd => fun(#{sec_acc2 := Pid} = _State) ->
- ok = ?SEV_AWAIT_READY(Pid, sec_acc2, accept_closed)
+ #{desc => "await client ready (connect)",
+ cmd => fun(#{server := Server,
+ client := Client} = _State) ->
+ ?SEV_AWAIT_READY(Client, client, connect,
+ [{server, Server}])
end},
- #{desc => "await 'secondary acceptor 3' ready (accept closed)",
- cmd => fun(#{sec_acc3 := Pid} = _State) ->
- ok = ?SEV_AWAIT_READY(Pid, sec_acc3, accept_closed)
+
+ #{desc => "generate data",
+ cmd => fun(State) ->
+ D1 = lists:seq(1,250),
+ D2 = lists:duplicate(4, D1),
+ D3 = lists:flatten(D2),
+ {ok, State#{data => D3}}
end},
-
- %% Terminations
- #{desc => "order 'secondary acceptor 3' to terminate",
- cmd => fun(#{sec_acc3 := Pid} = _State) ->
- ?SEV_ANNOUNCE_TERMINATE(Pid),
+ %% (client) Send one big and (server) recv may small
+ #{desc => "order server continue (recv-many-small)",
+ cmd => fun(#{server := Pid} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv_many_small),
ok
end},
- #{desc => "await 'secondary acceptor 3' termination",
- cmd => fun(#{sec_acc3 := Pid} = State) ->
- case ?SEV_AWAIT_TERMINATION(Pid) of
- ok ->
- {ok, maps:remove(sec_acc3, State)};
+ ?SEV_SLEEP(?SECS(1)),
+ #{desc => "order client continue (send-one-big)",
+ cmd => fun(#{client := Pid, data := Data} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_one_big, Data),
+ ok
+ end},
+ #{desc => "await client ready (send-one-big)",
+ cmd => fun(#{server := Server,
+ client := Client} = _State) ->
+ ok = ?SEV_AWAIT_READY(Client, client, send_one_big,
+ [{server, Server}])
+ end},
+ #{desc => "await server ready (recv-many-small)",
+ cmd => fun(#{server := Server,
+ client := Client,
+ data := Data} = _State) ->
+ case ?SEV_AWAIT_READY(Server, server, recv_many_small,
+ [{client, Client}]) of
+ {ok, Data} ->
+ ok;
+ {ok, OtherData} ->
+ {error, {mismatched_data, Data, OtherData}};
{error, _} = ERROR ->
ERROR
end
end},
- #{desc => "order 'secondary acceptor 2' to terminate",
- cmd => fun(#{sec_acc2 := Pid} = _State) ->
- ?SEV_ANNOUNCE_TERMINATE(Pid),
+
+ #{desc => "order server continue (recv-one-big)",
+ cmd => fun(#{server := Pid, data := Data} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, recv_one_big, length(Data)),
ok
end},
- #{desc => "await 'secondary acceptor 2' termination",
- cmd => fun(#{sec_acc2 := Pid} = State) ->
- case ?SEV_AWAIT_TERMINATION(Pid) of
- ok ->
- {ok, maps:remove(sec_acc2, State)};
+ ?SEV_SLEEP(?SECS(1)),
+ #{desc => "order client continue (send-many-small)",
+ cmd => fun(#{client := Pid, data := Data} = _State) ->
+ ?SEV_ANNOUNCE_CONTINUE(Pid, send_many_small, Data),
+ ok
+ end},
+ #{desc => "await client ready (send-many-small)",
+ cmd => fun(#{server := Server,
+ client := Client} = _State) ->
+ ok = ?SEV_AWAIT_READY(Client, client, send_many_small,
+ [{server, Server}])
+ end},
+ #{desc => "await server ready (recv-one-big)",
+ cmd => fun(#{server := Server,
+ client := Client,
+ data := Data} = State) ->
+ case ?SEV_AWAIT_READY(Server, server, recv_one_big,
+ [{client, Client}]) of
+ {ok, Data} ->
+ {ok, maps:remove(data, State)};
+ {ok, OtherData} ->
+ {error, {mismatched_data, Data, OtherData}};
{error, _} = ERROR ->
ERROR
end
end},
- #{desc => "order 'secondary acceptor 1' to terminate",
- cmd => fun(#{sec_acc1 := Pid} = _State) ->
+
+ %% Terminations
+ #{desc => "order client to terminate",
+ cmd => fun(#{client := Pid} = _State) ->
?SEV_ANNOUNCE_TERMINATE(Pid),
ok
end},
- #{desc => "await 'secondary acceptor 1' termination",
- cmd => fun(#{sec_acc1 := Pid} = State) ->
+ #{desc => "await client termination",
+ cmd => fun(#{client := Pid} = State) ->
case ?SEV_AWAIT_TERMINATION(Pid) of
ok ->
- {ok, maps:remove(sec_acc1, State)};
+ State1 = maps:remove(client, State),
+ {ok, State1};
{error, _} = ERROR ->
ERROR
end
end},
- #{desc => "order 'primary acceptor' to terminate",
- cmd => fun(#{prim_acc := Pid} = _State) ->
+ #{desc => "order server to terminate",
+ cmd => fun(#{server := Pid} = _State) ->
?SEV_ANNOUNCE_TERMINATE(Pid),
ok
end},
- #{desc => "await 'primary acceptor' termination",
- cmd => fun(#{prim_acc := Pid} = State) ->
+ #{desc => "await server termination",
+ cmd => fun(#{server := Pid} = State) ->
case ?SEV_AWAIT_TERMINATION(Pid) of
ok ->
- {ok, maps:remove(prim_acc, State)};
+ State1 = maps:remove(server, State),
+ {ok, State1};
{error, _} = ERROR ->
ERROR
end
@@ -5679,31 +6539,128 @@ sc_lc_acceptor_response_tcp(InitState) ->
?SEV_FINISH_NORMAL
],
+ i("start server evaluator"),
+ ServerInitState = InitState,
+ Server = ?SEV_START("server", ServerSeq, ServerInitState),
- i("start 'primary acceptor' evaluator"),
- PrimAccInitState = InitState,
- PrimAcc = ?SEV_START("prim-acceptor", PrimAcceptorSeq, PrimAccInitState),
-
- i("start 'secondary acceptor 1' evaluator"),
- SecAccInitState = #{},
- SecAcc1 = ?SEV_START("sec-acceptor-1", SecAcceptorSeq, SecAccInitState),
-
- i("start 'secondary acceptor 2' evaluator"),
- SecAcc2 = ?SEV_START("sec-acceptor-2", SecAcceptorSeq, SecAccInitState),
-
- i("start 'secondary acceptor 3' evaluator"),
- SecAcc3 = ?SEV_START("sec-acceptor-3", SecAcceptorSeq, SecAccInitState),
+ i("start client evaluator(s)"),
+ ClientInitState = InitState#{host => local_host()},
+ Client = ?SEV_START("client", ClientSeq, ClientInitState),
i("start 'tester' evaluator"),
- TesterInitState = #{prim_acc => PrimAcc#ev.pid,
- sec_acc1 => SecAcc1#ev.pid,
- sec_acc2 => SecAcc2#ev.pid,
- sec_acc3 => SecAcc3#ev.pid},
+ TesterInitState = #{server => Server#ev.pid,
+ client => Client#ev.pid},
Tester = ?SEV_START("tester", TesterSeq, TesterInitState),
i("await evaluator"),
- ok = ?SEV_AWAIT_FINISH([PrimAcc, SecAcc1, SecAcc2, SecAcc3, Tester]).
+ ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+
+
+
+traffic_snr_tcp_client_start(Node) ->
+ Self = self(),
+ GL = group_leader(),
+ Fun = fun() -> traffic_snr_tcp_client(Self, GL) end,
+ erlang:spawn(Node, Fun).
+
+traffic_snr_tcp_client(Parent, GL) ->
+ {Sock, ServerSA} = traffic_snr_tcp_client_init(Parent, GL),
+ 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),
+ exit(Reason).
+
+
+traffic_snr_tcp_client_send_loop(Parent, Sock) ->
+ case ?SEV_AWAIT_CONTINUE(Parent, parent, send) of
+ {ok, stop} -> % Breakes the loop
+ ?SEV_ANNOUNCE_READY(Parent, send, ok),
+ ok;
+ {ok, Data} ->
+ case socket:send(Sock, Data) of
+ ok ->
+ ?SEV_ANNOUNCE_READY(Parent, send, ok),
+ traffic_snr_tcp_client_send_loop(Parent, Sock);
+ {error, Reason} = ERROR ->
+ ?SEV_ANNOUNCE_READY(Parent, send, ERROR),
+ exit({send, Reason})
+ end;
+ {error, Reason} ->
+ exit({await_continue, Reason})
+ end.
+
+traffic_snr_tcp_client_init(Parent, GL) ->
+ i("traffic_snr_tcp_client_init -> entry"),
+ _MRef = erlang:monitor(process, Parent),
+ group_leader(self(), GL),
+ ServerSA = 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}.
+
+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) ->
+ i("traffic_snr_tcp_client_create -> entry"),
+ case socket:open(Domain, stream, tcp) of
+ {ok, Sock} ->
+ Sock;
+ {error, Reason} ->
+ exit({open_failed, Reason})
+ end.
+
+traffic_snr_tcp_client_bind(Sock, Domain) ->
+ i("traffic_snr_tcp_client_bind -> entry"),
+ LAddr = which_local_addr(Domain),
+ LSA = #{family => Domain,
+ addr => LAddr},
+ case socket:bind(Sock, LSA) of
+ {ok, _} ->
+ ok;
+ {error, Reason} ->
+ exit({bind, Reason})
+ end.
+
+traffic_snr_tcp_client_announce_ready(Parent, Slogan) ->
+ ?SEV_ANNOUNCE_READY(Parent, Slogan).
+
+traffic_snr_tcp_client_await_continue(Parent, Slogan) ->
+ i("traffic_snr_tcp_client_await_continue -> entry"),
+ ?SEV_AWAIT_CONTINUE(Parent, parent, Slogan).
+
+traffic_snr_tcp_client_connect(Sock, ServerSA) ->
+ i("traffic_snr_tcp_client_connect -> entry"),
+ case socket:connect(Sock, ServerSA) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ exit({connect, Reason})
+ end.
+
+traffic_snr_tcp_client_close(Sock) ->
+ i("traffic_snr_tcp_client_close -> entry"),
+ case socket:close(Sock) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ exit({close, Reason})
+ end.
+
+traffic_snr_tcp_client_await_terminate(Parent) ->
+ i("traffic_snr_tcp_client_await_terminate -> entry"),
+ case ?SEV_AWAIT_TERMINATE(Parent, parent) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ Reason
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5740,6 +6697,36 @@ which_addr2(Domain, [_|IFO]) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+start_node(Host, NodeName) ->
+ UniqueNodeName = f("~w_~w", [NodeName, erlang:unique_integer([positive])]),
+ case do_start_node(Host, UniqueNodeName) of
+ {ok, _} = OK ->
+ OK;
+ {error, Reason, _} ->
+ {error, Reason}
+ end.
+
+do_start_node(Host, NodeName) when is_list(NodeName) ->
+ do_start_node(Host, list_to_atom(NodeName));
+do_start_node(Host, NodeName) when is_atom(NodeName) ->
+ Dir = filename:dirname(code:which(?MODULE)),
+ Flags = "-pa " ++ Dir,
+ Opts = [{monitor_master, true}, {erl_flags, Flags}],
+ ct_slave:start(Host, NodeName, Opts).
+
+
+stop_node(Node) ->
+ case ct_slave:stop(Node) of
+ {ok, _} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
sock_open(Domain, Type, Proto) ->
try socket:open(Domain, Type, Proto) of
{ok, Socket} ->
@@ -5936,6 +6923,9 @@ tc_which_name() ->
l2a(S) when is_list(S) ->
list_to_atom(S).
+b2l(B) when is_binary(B) ->
+ binary_to_list(B).
+
f(F, A) ->
lists:flatten(io_lib:format(F, A)).
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index a0bf156263..480f86334c 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index acf5e18cec..5ebc2074e0 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -1716,10 +1716,14 @@ do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
(is_integer(Timeout) andalso (Timeout > 0)) ->
TS = timestamp(Timeout),
RecvRef = make_ref(),
+ %% p("do_recv -> try read with"
+ %% "~n Length: ~p", [Length]),
case nif_recv(SockRef, RecvRef, Length, EFlags) of
{ok, true = _Complete, Bin} when (size(Acc) =:= 0) ->
+ %% p("do_recv -> complete success: ~w", [size(Bin)]),
{ok, Bin};
{ok, true = _Complete, Bin} ->
+ %% p("do_recv -> completed success: ~w (~w)", [size(Bin), size(Acc)]),
{ok, <<Acc/binary, Bin/binary>>};
%% It depends on the amount of bytes we tried to read:
@@ -1728,6 +1732,7 @@ do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
%% > 0 - We got a part of the message and we will be notified
%% when there is more to read (a select message)
{ok, false = _Complete, Bin} when (Length =:= 0) ->
+ %% p("do_recv -> partial success: ~w", [size(Bin)]),
do_recv(SockRef, RecvRef,
Length, EFlags,
<<Acc/binary, Bin/binary>>,
@@ -1737,6 +1742,8 @@ do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
%% We got the first chunk of it.
%% We will be notified (select message) when there
%% is more to read.
+ %% p("do_recv -> partial success(~w): ~w"
+ %% "~n ~p", [Length, size(Bin), Bin]),
NewTimeout = next_timeout(TS, Timeout),
receive
{select, SockRef, RecvRef, ready_input} ->
@@ -1756,6 +1763,8 @@ do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
{ok, false = _Completed, Bin} ->
%% We got a chunk of it!
+ %% p("do_recv -> partial success(~w): ~w (~w)",
+ %% [Length, size(Bin), size(Acc)]),
NewTimeout = next_timeout(TS, Timeout),
receive
{select, SockRef, RecvRef, ready_input} ->
@@ -1780,6 +1789,7 @@ do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
{error, eagain} ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
+ %% p("do_recv -> eagain(~w): ~w", [Length, size(Acc)]),
NewTimeout = next_timeout(TS, Timeout),
receive
{select, SockRef, RecvRef, ready_input} ->
@@ -3473,6 +3483,7 @@ tdiff(T1, T2) ->
%% p(undefined, F, A) ->
%% p("***", F, A);
%% p(SName, F, A) ->
+%% io:format(user,"[~s,~p] " ++ F ++ "~n", [SName, self()|A]),
%% io:format("[~s,~p] " ++ F ++ "~n", [SName, self()|A]).