aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-09-26 15:02:53 +0200
committerMicael Karlberg <[email protected]>2018-09-27 12:44:16 +0200
commit18305496c064c8d9d32448a6425bdd39eaa20c7f (patch)
tree8c29fc4f039d0821fe65a9932be2d42976b7ede4 /lib/kernel
parentcd6afd8df61eb33aa2b51d4a0315fa8903135465 (diff)
downloadotp-18305496c064c8d9d32448a6425bdd39eaa20c7f.tar.gz
otp-18305496c064c8d9d32448a6425bdd39eaa20c7f.tar.bz2
otp-18305496c064c8d9d32448a6425bdd39eaa20c7f.zip
[socket-nif|test] Add operation timeout test cases
Add a number of *basic* operation (connect, accept, send and recv). All of which are not yet implemented (skipped with 'not-yet-implemented'). All of these are basic and only local (both sides on the same host). OTP-14831
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/test/socket_SUITE.erl777
1 files changed, 735 insertions, 42 deletions
diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl
index 1bf12693fe..e4f9d2c8b2 100644
--- a/lib/kernel/test/socket_SUITE.erl
+++ b/lib/kernel/test/socket_SUITE.erl
@@ -25,6 +25,8 @@
%% Suite exports
-export([suite/0, all/0, groups/0]).
+-export([init_per_suite/1, end_per_suite/1,
+ init_per_testcase/2, end_per_testcase/2]).
%% Test cases
-export([
@@ -34,7 +36,29 @@
api_b_sendto_and_recvfrom_udp4/1,
api_b_sendmsg_and_recvmsg_udp4/1,
api_b_send_and_recv_tcp4/1,
- api_b_sendmsg_and_recvmsg_tcp4/1
+ api_b_sendmsg_and_recvmsg_tcp4/1,
+
+ %% Operation Timeout
+ to_connect_tcp4/1,
+ to_connect_tcp6/1,
+ to_accept_tcp4/1,
+ to_accept_tcp6/1,
+ to_send_tcp4/1,
+ to_send_tcp6/1,
+ to_sendto_udp4/1,
+ to_sendto_udp6/1,
+ to_sendmsg_tcp4/1,
+ to_sendmsg_tcp6/1,
+ to_recv_udp4/1,
+ to_recv_udp6/1,
+ to_recv_tcp4/1,
+ to_recv_tcp6/1,
+ to_recvfrom_udp4/1,
+ to_recvfrom_udp6/1,
+ to_recvmsg_udp4/1,
+ to_recvmsg_udp6/1,
+ to_recvmsg_tcp4/1,
+ to_recvmsg_tcp6/1
%% Tickets
]).
@@ -64,18 +88,21 @@ all() ->
].
groups() ->
- [{api, [], api_cases()},
- {api_basic, [], api_basic_cases()}
+ [{api, [], api_cases()},
+ {api_basic, [], api_basic_cases()},
+ {op_with_timeout, [], op_with_timeout_cases()}
%% {tickets, [], ticket_cases()}
].
api_cases() ->
[
- {group, api_basic}
+ {group, api_basic},
+ {group, op_with_timeout}
].
api_basic_cases() ->
- [api_b_open_and_close_udp4,
+ [
+ api_b_open_and_close_udp4,
api_b_open_and_close_tcp4,
api_b_sendto_and_recvfrom_udp4,
api_b_sendmsg_and_recvmsg_udp4,
@@ -83,6 +110,31 @@ api_basic_cases() ->
api_b_sendmsg_and_recvmsg_tcp4
].
+op_with_timeout_cases() ->
+ [
+ to_connect_tcp4,
+ to_connect_tcp6,
+ to_accept_tcp4,
+ to_accept_tcp6,
+ to_send_tcp4,
+ to_send_tcp6,
+ to_sendto_udp4,
+ to_sendto_udp6,
+ to_sendmsg_tcp4,
+ to_sendmsg_tcp6,
+ to_recv_udp4,
+ to_recv_udp6,
+ to_recv_tcp4,
+ to_recv_tcp6,
+ to_recvfrom_udp4,
+ to_recvfrom_udp6,
+ to_recvmsg_udp4,
+ to_recvmsg_udp6,
+ to_recvmsg_tcp4,
+ to_recvmsg_tcp6
+ ].
+
+
%% ticket_cases() ->
%% [].
@@ -90,6 +142,22 @@ api_basic_cases() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_) ->
+ ok.
+
+init_per_testcase(_TC, Config) ->
+ Config.
+
+end_per_testcase(_TC, Config) ->
+ Config.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
%% Basically open (create) and close an IPv4 UDP (dgram) socket.
%% With some extra checks...
api_b_open_and_close_udp4(suite) ->
@@ -154,6 +222,8 @@ api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) ->
tc_end().
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
%% Basically send and receive on an IPv4 UDP (dgram) socket
%% using sendmsg and recvmsg.
api_b_sendmsg_and_recvmsg_udp4(suite) ->
@@ -183,42 +253,19 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) ->
tc_end().
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
api_b_send_and_recv_udp(Domain, Send, Recv) ->
- SockSrc = case socket:open(Domain, dgram, udp) of
- {ok, S1} ->
- S1;
- {error, OR1} ->
- ?FAIL({open, src, OR1})
- end,
- LAddr = which_local_addr(Domain),
- LSA = #{family => Domain, addr => LAddr},
- case socket:bind(SockSrc, LSA) of
- {ok, _} ->
- ok;
- {error, BR1} ->
- ?FAIL({bind, src, BR1})
- end,
- SockDst = case socket:open(Domain, dgram, udp) of
- {ok, S2} ->
- S2;
- {error, OR2} ->
- ?FAIL({open, dst, OR2})
- end,
- case socket:bind(SockDst, LSA) of
- {ok, _} ->
- ok;
- {error, BR2} ->
- ?FAIL({bind, dst, BR2})
- end,
- Dst = case socket:sockname(SockDst) of
- {ok, SA} ->
- SA;
- {ok, SNR} ->
- ?FAIL({sockname, dst, SNR})
- end,
- ok = Send(SockSrc, ?BASIC_REQ, Dst),
+ SockSrc = sock_open(Domain, dgram, udp),
+ LAddr = which_local_addr(Domain),
+ LSA = #{family => Domain, addr => LAddr},
+ sock_bind(SockSrc, LSA),
+ SockDst = sock_open(Domain, dgram, udp),
+ sock_bind(SockDst, LSA),
+ Dst = sock_sockname(SockDst),
+ ok = Send(SockSrc, ?BASIC_REQ, Dst),
{ok, {Src, ?BASIC_REQ}} = Recv(SockDst),
- ok = Send(SockDst, ?BASIC_REP, Src),
+ ok = Send(SockDst, ?BASIC_REP, Src),
{ok, {Dst, ?BASIC_REP}} = Recv(SockSrc),
socket:close(SockSrc),
socket:close(SockDst),
@@ -246,6 +293,8 @@ api_b_send_and_recv_tcp4(_Config) when is_list(_Config) ->
tc_end().
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
%% Basically send and receive using the msg functions (sendmsg and recvmsg)
%% on an IPv4 TCP (stream) socket.
api_b_sendmsg_and_recvmsg_tcp4(suite) ->
@@ -271,6 +320,8 @@ api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) ->
tc_end().
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
api_b_send_and_recv_tcp(Domain, Send, Recv) ->
process_flag(trap_exit, true),
LAddr = which_local_addr(Domain),
@@ -381,6 +432,528 @@ api_b_send_and_recv_tcp(Domain, Send, Recv) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the connect timeout option
+%% on an IPv4 TCP (stream) socket.
+to_connect_tcp4(suite) ->
+ [];
+to_connect_tcp4(doc) ->
+ [];
+to_connect_tcp4(_Config) when is_list(_Config) ->
+ tc_begin(to_connect_tcp4),
+ ok = to_connect_tcp(inet),
+ tc_end().
+ %% not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the connect timeout option
+%% on an IPv6 TCP (stream) socket.
+to_connect_tcp6(suite) ->
+ [];
+to_connect_tcp6(doc) ->
+ [];
+to_connect_tcp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_connect_tcp6),
+ %% ok = to_connect_tcp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+to_connect_tcp(Domain) ->
+ process_flag(trap_exit, true),
+ p("init"),
+ Client = self(),
+ LocalAddr = which_local_addr(Domain),
+ LocalSA = #{family => Domain, addr => LocalAddr},
+ ServerName = f("~s:server", [get_tc_name()]),
+ Server = spawn_link(fun() ->
+ set_tc_name(ServerName),
+ p("open"),
+ LSock = sock_open(Domain, stream, tcp),
+ p("bind"),
+ ServerLPort = sock_bind(LSock, LocalSA),
+ p("listen on ~w", [ServerLPort]),
+ sock_listen(LSock, 1),
+ p("inform client"),
+ Client ! {self(), ServerLPort},
+ p("await termination command"),
+ receive
+ die ->
+ p("terminating"),
+ exit(normal)
+ end
+ end),
+
+ p("await server port"),
+ ServerLPort =
+ receive
+ {Server, Port} ->
+ Port
+ end,
+ p("open(s)"),
+ CSock1 = sock_open(Domain, stream, tcp),
+ CSock2 = sock_open(Domain, stream, tcp),
+ CSock3 = sock_open(Domain, stream, tcp),
+ p("bind(s)"),
+ _ClientPort1 = sock_bind(CSock1, LocalSA),
+ _ClientPort2 = sock_bind(CSock2, LocalSA),
+ _ClientPort3 = sock_bind(CSock3, LocalSA),
+ ServerSA = LocalSA#{port => ServerLPort},
+ to_connect_tcp_await_timeout([CSock1, CSock2, CSock3], ServerSA),
+ p("terminate server"),
+ Server ! die,
+ receive
+ {'EXIT', Server, _} ->
+ p("server terminated"),
+ ok
+ end,
+ ok.
+
+
+to_connect_tcp_await_timeout(Socks, ServerSA) ->
+ to_connect_tcp_await_timeout(Socks, ServerSA, 1).
+
+to_connect_tcp_await_timeout([], _ServerSA, _ID) ->
+ ?FAIL(unexpected_success);
+to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) ->
+ p("~w: try connect", [ID]),
+ case socket:connect(Sock, ServerSA, 5000) of
+ {error, timeout} ->
+ p("expected timeout (~w)", [ID]),
+ ok;
+ {error, Reason} ->
+ p("failed connecting: ~p", [Reason]),
+ ?FAIL({recv, Reason});
+ ok ->
+ p("unexpected success (~w) - try next", [ID]),
+ to_connect_tcp_await_timeout(Socks, ServerSA, ID+1)
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the accept timeout option
+%% on an IPv4 TCP (stream) socket.
+to_accept_tcp4(suite) ->
+ [];
+to_accept_tcp4(doc) ->
+ [];
+to_accept_tcp4(_Config) when is_list(_Config) ->
+ %% tc_begin(to_accept_tcp4),
+ %% ok = to_accept_tcp(inet),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the accept timeout option
+%% on an IPv6 TCP (stream) socket.
+to_accept_tcp6(suite) ->
+ [];
+to_accept_tcp6(doc) ->
+ [];
+to_accept_tcp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_accept_tcp6),
+ %% ok = to_accept_tcp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the send timeout option
+%% on an IPv4 TCP (stream) socket.
+to_send_tcp4(suite) ->
+ [];
+to_send_tcp4(doc) ->
+ [];
+to_send_tcp4(_Config) when is_list(_Config) ->
+ %% tc_begin(to_send_tcp4),
+ %% ok = to_send_tcp(inet),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the send timeout option
+%% on an IPv6 TCP (stream) socket.
+to_send_tcp6(suite) ->
+ [];
+to_send_tcp6(doc) ->
+ [];
+to_send_tcp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_send_tcp6),
+ %% ok = to_send_tcp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the sendto timeout option
+%% on an IPv4 UDP (dgram) socket.
+to_sendto_udp4(suite) ->
+ [];
+to_sendto_udp4(doc) ->
+ [];
+to_sendto_udp4(_Config) when is_list(_Config) ->
+ %% tc_begin(to_sendto_udp4),
+ %% ok = to_sendto_udp(inet),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the sendto timeout option
+%% on an IPv6 UDP (dgram) socket.
+to_sendto_udp6(suite) ->
+ [];
+to_sendto_udp6(doc) ->
+ [];
+to_sendto_udp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_sendto_udp6),
+ %% ok = to_sendto_udp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the sendmsg timeout option
+%% on an IPv4 TCP (stream) socket.
+to_sendmsg_tcp4(suite) ->
+ [];
+to_sendmsg_tcp4(doc) ->
+ [];
+to_sendmsg_tcp4(_Config) when is_list(_Config) ->
+ %% tc_begin(to_sendmsg_tcp4),
+ %% ok = to_sendmsg_tcp(inet),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the sendmsg timeout option
+%% on an IPv6 TCP (stream) socket.
+to_sendmsg_tcp6(suite) ->
+ [];
+to_sendmsg_tcp6(doc) ->
+ [];
+to_sendmsg_tcp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_sendmsg_tcp6),
+ %% ok = to_sendmsg_tcp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recv timeout option
+%% on an IPv4 UDP (dgram) socket. To test this we must connect
+%% the socket.
+to_recv_udp4(suite) ->
+ [];
+to_recv_udp4(doc) ->
+ [];
+to_recv_udp4(_Config) when is_list(_Config) ->
+ %% tc_begin(to_recv_udp4),
+ %% ok = to_recv_udp(inet),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recv timeout option
+%% on an IPv6 UDP (dgram) socket. To test this we must connect
+%% the socket.
+to_recv_udp6(suite) ->
+ [];
+to_recv_udp6(doc) ->
+ [];
+to_recv_udp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_recv_udp6),
+ %% ok = to_recv_udp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recv timeout option
+%% on an IPv4 TCP (stream) socket.
+to_recv_tcp4(suite) ->
+ [];
+to_recv_tcp4(doc) ->
+ [];
+to_recv_tcp4(_Config) when is_list(_Config) ->
+ tc_begin(to_recv_tcp4),
+ ok = to_recv_tcp(inet),
+ tc_end().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recv timeout option
+%% on an IPv6 TCP (stream) socket.
+to_recv_tcp6(suite) ->
+ [];
+to_recv_tcp6(doc) ->
+ [];
+to_recv_tcp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_recv_tcp6),
+ %% ok = to_recv_tcp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+to_recv_tcp(Domain) ->
+ process_flag(trap_exit, true),
+ p("server -> open"),
+ LSock = sock_open(Domain, stream, tcp),
+ LocalAddr = which_local_addr(Domain),
+ LocalSA = #{family => Domain, addr => LocalAddr},
+ p("server -> bind"),
+ ServerLPort = sock_bind(LSock, LocalSA),
+ p("server(~w) -> listen", [ServerLPort]),
+ sock_listen(LSock),
+ ClientName = f("~s:client", [get_tc_name()]),
+ Client = spawn_link(fun() ->
+ set_tc_name(ClientName),
+ p("open"),
+ CSock = sock_open(Domain, stream, tcp),
+ p("bind"),
+ ClientPort = sock_bind(CSock, LocalSA),
+ p("[~w] connect to ~w",
+ [ClientPort, ServerLPort]),
+ sock_connect(CSock, LocalSA#{port => ServerLPort}),
+ p("await termination command"),
+ receive
+ die ->
+ p("terminating"),
+ exit(normal)
+ end
+ end),
+ p("server -> accept on ~w", [ServerLPort]),
+ Sock = sock_accept(LSock),
+ p("server -> recv"),
+ %% The zero (0) represents "give me everything you have"
+ case socket:recv(Sock, 0, 5000) of
+ {error, timeout} ->
+ p("server -> expected timeout"),
+ ok;
+ {ok, _Data} ->
+ ?FAIL(unexpected_success);
+ {error, Reason} ->
+ ?FAIL({recv, Reason})
+ end,
+ Client ! die,
+ receive
+ {'EXIT', Client, _} ->
+ ok
+ end,
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recvfrom timeout option
+%% on an IPv4 UDP (dgram) socket.
+to_recvfrom_udp4(suite) ->
+ [];
+to_recvfrom_udp4(doc) ->
+ [];
+to_recvfrom_udp4(_Config) when is_list(_Config) ->
+ tc_begin(to_recvfrom_udp4),
+ ok = to_recvfrom_udp(inet),
+ tc_end().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recvfrom timeout option
+%% on an IPv6 UDP (dgram) socket.
+to_recvfrom_udp6(suite) ->
+ [];
+to_recvfrom_udp6(doc) ->
+ [];
+to_recvfrom_udp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_recvfrom_udp6),
+ %% ok = to_recvfrom_udp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+to_recvfrom_udp(Domain) ->
+ process_flag(trap_exit, true),
+ p("init"),
+ LocalAddr = which_local_addr(Domain),
+ LocalSA = #{family => Domain, addr => LocalAddr},
+ p("open"),
+ Sock = sock_open(Domain, dgram, udp),
+ p("bind"),
+ _Port = sock_bind(Sock, LocalSA),
+ p("recv"),
+ case socket:recvfrom(Sock, 0, 5000) of
+ {error, timeout} ->
+ p("expected timeout"),
+ ok;
+ {ok, _SrcData} ->
+ ?FAIL(unexpected_success);
+ {error, Reason} ->
+ ?FAIL({recv, Reason})
+ end,
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recvmsg timeout option
+%% on an IPv4 UDP (dgram) socket.
+to_recvmsg_udp4(suite) ->
+ [];
+to_recvmsg_udp4(doc) ->
+ [];
+to_recvmsg_udp4(_Config) when is_list(_Config) ->
+ %% not_yet_implemented().
+ tc_begin(to_recvmsg_udp4),
+ ok = to_recvmsg_udp(inet),
+ tc_end().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recvmsg timeout option
+%% on an IPv6 UDP (dgram) socket.
+to_recvmsg_udp6(suite) ->
+ [];
+to_recvmsg_udp6(doc) ->
+ [];
+to_recvmsg_udp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_recvmsg_udp6),
+ %% ok = to_recvmsg_udp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+to_recvmsg_udp(Domain) ->
+ process_flag(trap_exit, true),
+ p("init"),
+ LocalAddr = which_local_addr(Domain),
+ LocalSA = #{family => Domain, addr => LocalAddr},
+ p("open"),
+ Sock = sock_open(Domain, dgram, udp),
+ p("bind"),
+ _Port = sock_bind(Sock, LocalSA),
+ p("recv"),
+ case socket:recvmsg(Sock, 5000) of
+ {error, timeout} ->
+ p("expected timeout"),
+ ok;
+ {ok, _MsgHdr} ->
+ ?FAIL(unexpected_success);
+ {error, Reason} ->
+ ?FAIL({recv, Reason})
+ end,
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recvmsg timeout option
+%% on an IPv4 TCP (stream) socket.
+to_recvmsg_tcp4(suite) ->
+ [];
+to_recvmsg_tcp4(doc) ->
+ [];
+to_recvmsg_tcp4(_Config) when is_list(_Config) ->
+ tc_begin(to_recvmsg_tcp4),
+ ok = to_recvmsg_tcp(inet),
+ tc_end().
+ %% not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is intended to test the recvmsg timeout option
+%% on an IPv6 TCP (stream) socket.
+to_recvmsg_tcp6(suite) ->
+ [];
+to_recvmsg_tcp6(doc) ->
+ [];
+to_recvmsg_tcp6(_Config) when is_list(_Config) ->
+ %% tc_begin(to_recvmsg_tcp6),
+ %% ok = to_recvmsg_tcp(inet6),
+ %% tc_end().
+ not_yet_implemented().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+to_recvmsg_tcp(Domain) ->
+ process_flag(trap_exit, true),
+ p("server -> open"),
+ LSock = sock_open(Domain, stream, tcp),
+ LocalAddr = which_local_addr(Domain),
+ LocalSA = #{family => Domain, addr => LocalAddr},
+ p("server -> bind"),
+ ServerLPort = sock_bind(LSock, LocalSA),
+ p("server(~w) -> listen", [ServerLPort]),
+ sock_listen(LSock),
+ ClientName = f("~s:client", [get_tc_name()]),
+ Client = spawn_link(fun() ->
+ set_tc_name(ClientName),
+ p("open"),
+ CSock = sock_open(Domain, stream, tcp),
+ p("bind"),
+ ClientPort = sock_bind(CSock, LocalSA),
+ p("[~w] connect to ~w",
+ [ClientPort, ServerLPort]),
+ sock_connect(CSock, LocalSA#{port => ServerLPort}),
+ p("await termination command"),
+ receive
+ die ->
+ p("terminating"),
+ exit(normal)
+ end
+ end),
+ p("server -> accept on ~w", [ServerLPort]),
+ Sock = sock_accept(LSock),
+ p("server -> recv"),
+ %% The zero (0) represents "give me everything you have"
+ case socket:recvmsg(Sock, 5000) of
+ {error, timeout} ->
+ p("server -> expected timeout"),
+ ok;
+ {ok, _Data} ->
+ ?FAIL(unexpected_success);
+ {error, Reason} ->
+ ?FAIL({recv, Reason})
+ end,
+ Client ! die,
+ receive
+ {'EXIT', Client, _} ->
+ ok
+ end,
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This gets the local address (not 127.0...)
@@ -411,16 +984,136 @@ which_addr2(Domain, [_|IFO]) ->
which_addr2(Domain, IFO).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sock_open(Domain, Type, Proto) ->
+ try socket:open(Domain, Type, Proto) of
+ {ok, Socket} ->
+ Socket;
+ {error, Reason} ->
+ ?FAIL({open, Reason})
+ catch
+ C:E:S ->
+ ?FAIL({open, C, E, S})
+ end.
+
+
+sock_bind(Sock, SockAddr) ->
+ try socket:bind(Sock, SockAddr) of
+ {ok, Port} ->
+ Port;
+ {error, Reason} ->
+ p("sock_bind -> error: ~p", [Reason]),
+ ?FAIL({bind, Reason})
+ catch
+ C:E:S ->
+ p("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 ->
+ ok;
+ {error, Reason} ->
+ ?FAIL({connect, Reason})
+ catch
+ C:E:S ->
+ ?FAIL({connect, C, E, S})
+ end.
+
+sock_sockname(Sock) ->
+ try socket:sockname(Sock) of
+ {ok, SockAddr} ->
+ SockAddr;
+ {error, Reason} ->
+ ?FAIL({sockname, Reason})
+ catch
+ C:E:S ->
+ ?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} ->
+ p("sock_accept -> error: ~p", [Reason]),
+ ?FAIL({accept, Reason})
+ catch
+ C:E:S ->
+ p("sock_accept -> failed: ~p, ~p, ~p", [C, E, S]),
+ ?FAIL({accept, C, E, S})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+not_yet_implemented() ->
+ {skip, "not yet implemented"}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+set_tc_name(N) when is_atom(N) ->
+ set_tc_name(atom_to_list(N));
+set_tc_name(N) when is_list(N) ->
+ put(tc_name, N).
+
+get_tc_name() ->
+ get(tc_name).
+
tc_begin(TC) ->
- put(tc_name, TC),
- p("begin").
+ set_tc_name(TC),
+ p("begin ***").
tc_end() ->
+ p("done ***"),
ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
+
p(F) ->
p(F, []).
p(F, A) ->
- io:format(user, "*** ~w " ++ F ++ "~n", [get(tc_name)|A]).
+ TcName =
+ case get(tc_name) of
+ undefined ->
+ "";
+ Name when is_list(Name) ->
+ Name
+ end,
+ i("*** ~s[~p] " ++ F, [TcName,self()|A]).
+
+
+%% i(F) ->
+%% i(F, []).
+i(F, A) ->
+ io:format(user, F ++ "~n", A).