summaryrefslogtreecommitdiff
path: root/lib/kernel/test/gen_tcp_api_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test/gen_tcp_api_SUITE.erl')
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl176
1 files changed, 154 insertions, 22 deletions
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 900196d26f..9e92919bf0 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -326,12 +326,15 @@ t_accept_timeout(Config) when is_list(Config) ->
%% Test that gen_tcp:connect/4 (with timeout) works.
t_connect_timeout(Config) when is_list(Config) ->
+ ?TC_TRY(t_connect_timeout, fun() -> do_connect_timeout(Config) end).
+
+do_connect_timeout(Config)->
%%BadAddr = {134,138,177,16},
%%TcpPort = 80,
{ok, BadAddr} = unused_ip(),
TcpPort = 45638,
ok = ?P("Connecting to ~p, port ~p", [BadAddr, TcpPort]),
- connect_timeout({gen_tcp,connect,[BadAddr,TcpPort,?INET_BACKEND_OPTS(Config),200]}, 0.2, 5.0).
+ connect_timeout({gen_tcp,connect, [BadAddr,TcpPort, ?INET_BACKEND_OPTS(Config),200]}, 0.2, 5.0).
%% Test that gen_tcp:connect/3 handles non-existings hosts, and other
%% invalid things.
@@ -376,17 +379,29 @@ t_recv_eof(Config) when is_list(Config) ->
%% Test using message delimiter $X.
t_recv_delim(Config) when is_list(Config) ->
+ ?TC_TRY(t_recv_delim, fun() -> do_recv_delim(Config) end).
+
+do_recv_delim(Config) ->
+ ?P("init"),
{ok, L} = gen_tcp:listen(0, ?INET_BACKEND_OPTS(Config)),
{ok, Port} = inet:port(L),
Opts = ?INET_BACKEND_OPTS(Config) ++
[{active,false}, {packet,line}, {line_delimiter,$X}],
{ok, Client} = gen_tcp:connect(localhost, Port, Opts),
{ok, A} = gen_tcp:accept(L),
+ ?P("send the data"),
ok = gen_tcp:send(A, "abcXefgX"),
- {ok, "abcX"} = gen_tcp:recv(Client, 0, 200),
- {ok, "efgX"} = gen_tcp:recv(Client, 0, 200),
+ %% Why do we need a timeout?
+ %% Sure, normally there would be no delay,
+ %% but this testcase has nothing to do with timeouts?
+ ?P("read the first chunk"),
+ {ok, "abcX"} = gen_tcp:recv(Client, 0), %, 200),
+ ?P("read the first chunk"),
+ {ok, "efgX"} = gen_tcp:recv(Client, 0), %, 200),
+ ?P("cleanup"),
ok = gen_tcp:close(Client),
ok = gen_tcp:close(A),
+ ?P("done"),
ok.
%%% gen_tcp:shutdown/2
@@ -414,36 +429,60 @@ t_shutdown_both(Config) when is_list(Config) ->
ok.
t_shutdown_error(Config) when is_list(Config) ->
+ ?TC_TRY(t_shutdown_error, fun() -> do_shutdown_error(Config) end).
+
+do_shutdown_error(Config) ->
+ ?P("create listen socket"),
{ok, L} = gen_tcp:listen(0, ?INET_BACKEND_OPTS(Config)),
+ ?P("shutdown socket (with How = read_write)"),
{error, enotconn} = gen_tcp:shutdown(L, read_write),
+ ?P("close socket"),
ok = gen_tcp:close(L),
+ ?P("shutdown socket again (with How = read_write)"),
{error, closed} = gen_tcp:shutdown(L, read_write),
+ ?P("done"),
ok.
t_shutdown_async(Config) when is_list(Config) ->
+ ?TC_TRY(t_shutdown_async, fun() -> do_shutdown_async(Config) end).
+
+do_shutdown_async(Config) ->
{OS, _} = os:type(),
+ ?P("create listen socket"),
{ok, L} = gen_tcp:listen(0, ?INET_BACKEND_OPTS(Config) ++ [{sndbuf, 4096}]),
{ok, Port} = inet:port(L),
+ ?P("connect"),
{ok, Client} = gen_tcp:connect(localhost, Port,
?INET_BACKEND_OPTS(Config) ++
[{recbuf, 4096},
{active, false}]),
+ ?P("accept connection"),
{ok, S} = gen_tcp:accept(L),
+ ?P("create payload"),
PayloadSize = 1024 * 1024,
Payload = lists:duplicate(PayloadSize, $.),
+ ?P("send payload"),
ok = gen_tcp:send(S, Payload),
+ ?P("verify queue size"),
case erlang:port_info(S, queue_size) of
{queue_size, N} when N > 0 -> ok;
{queue_size, 0} when OS =:= win32 -> ok;
{queue_size, 0} = T -> ct:fail({unexpected, T})
end,
+ ?P("shutdown(write) accepted socket"),
ok = gen_tcp:shutdown(S, write),
+ ?P("recv from connected socket"),
{ok, Buf} = gen_tcp:recv(Client, PayloadSize),
+ ?P("recv(0) from connected socket (expect closed)"),
{error, closed} = gen_tcp:recv(Client, 0),
+ ?P("verify recv data"),
case length(Buf) of
- PayloadSize -> ok;
- Sz -> ct:fail({payload_size,
+ PayloadSize -> ?P("done"), ok;
+ Sz -> ?P("ERROR: "
+ "~n extected: ~p"
+ "~n received: ~p", [PayloadSize, Sz]),
+ ct:fail({payload_size,
{expected, PayloadSize},
{received, Sz}})
end.
@@ -505,26 +544,32 @@ do_t_fdconnect(Config) ->
Path = proplists:get_value(data_dir, Config),
Lib = "gen_tcp_api_SUITE",
?P("try load util nif lib"),
- case erlang:load_nif(filename:join(Path,Lib), []) of
+ case erlang:load_nif(filename:join(Path, Lib), []) of
ok ->
ok;
+ {error, {reload, ReasonStr}} ->
+ ?P("already loaded: "
+ "~n ~s", [ReasonStr]),
+ ok;
{error, Reason} ->
?P("UNEXPECTED - failed loading util nif lib: "
"~n ~p", [Reason]),
?SKIPT("failed loading util nif lib")
end,
?P("try create listen socket"),
- L = case gen_tcp:listen(0, ?INET_BACKEND_OPTS(Config) ++ [{active, false}]) of
+ L = case gen_tcp:listen(0,
+ ?INET_BACKEND_OPTS(Config) ++ [{active, false}]) of
{ok, LSock} ->
LSock;
{error, eaddrnotavail = LReason} ->
?SKIPT(listen_failed_str(LReason))
end,
{ok, Port} = inet:port(L),
- ?P("try create file descriptor (fd)"),
+ ?P("try create file descriptor"),
FD = gen_tcp_api_SUITE:getsockfd(),
- ?P("try connect to using file descriptor (~w)", [FD]),
- Client = case gen_tcp:connect(localhost, Port, ?INET_BACKEND_OPTS(Config) ++
+ ?P("try connect using file descriptor (~w)", [FD]),
+ Client = case gen_tcp:connect(localhost, Port,
+ ?INET_BACKEND_OPTS(Config) ++
[{fd, FD},
{port, 20002},
{active, false}]) of
@@ -698,46 +743,91 @@ t_local_basic(Config) ->
t_local_unbound(Config) ->
+ ?TC_TRY(t_local_unbound, fun() -> do_local_unbound(Config) end).
+
+do_local_unbound(Config) ->
+ ?P("create local (server) filename"),
SFile = local_filename(server),
SAddr = {local,bin_filename(SFile)},
_ = file:delete(SFile),
%%
InetBackendOpts = ?INET_BACKEND_OPTS(Config),
+ ?P("create listen socket with ifaddr ~p", [SAddr]),
L = ok(gen_tcp:listen(0, InetBackendOpts ++
[{ifaddr,SAddr},{active,false}])),
+ ?P("listen socket created: ~p"
+ "~n => try connect", [L]),
C = ok(gen_tcp:connect(SAddr, 0,
InetBackendOpts ++ [{active,false}])),
+ ?P("connected: ~p"
+ "~n => try accept", [C]),
S = ok(gen_tcp:accept(L)),
+ ?P("accepted: ~p"
+ "~n => sockname", [S]),
SAddr = ok(inet:sockname(L)),
- {error,enotconn} = inet:peername(L),
+ ?P("sockname: ~p"
+ "~n => peername (expect enotconn)", [SAddr]),
+ {error, enotconn} = inet:peername(L),
+ ?P("try local handshake"),
local_handshake(S, SAddr, C, {local,<<>>}),
+ ?P("close listen socket"),
ok = gen_tcp:close(L),
+ ?P("close accepted socket"),
ok = gen_tcp:close(S),
+ ?P("close connected socket"),
ok = gen_tcp:close(C),
+ ?P("delete (local) file"),
ok = file:delete(SFile),
+ ?P("done"),
ok.
t_local_fdopen(Config) ->
+ ?TC_TRY(t_local_fdopen, fun() -> do_local_fdopen(Config) end).
+
+do_local_fdopen(Config) ->
+ ?P("create local (server) filename"),
SFile = local_filename(server),
SAddr = {local,bin_filename(SFile)},
_ = file:delete(SFile),
%%
InetBackendOpts = ?INET_BACKEND_OPTS(Config),
+ ?P("create listen socket with ifaddr ~p", [SAddr]),
L = ok(gen_tcp:listen(0, InetBackendOpts ++ [{ifaddr,SAddr},{active,false}])),
+ ?P("listen socket created: ~p"
+ "~n => try connect", [L]),
C0 = ok(gen_tcp:connect(SAddr, 0, InetBackendOpts ++ [{active,false}])),
+ ?P("connected: ~p"
+ "~n => get fd", [C0]),
Fd = ok(prim_inet:getfd(C0)),
+ ?P("FD: ~p"
+ "~n => ignore fd", [Fd]),
ok = prim_inet:ignorefd(C0, true),
+ ?P("ignored fd:"
+ "~n => try fdopen (local)"),
C = ok(gen_tcp:fdopen(Fd, [local])),
+ ?P("fd open: ~p"
+ "~n => try accept", [C]),
S = ok(gen_tcp:accept(L)),
+ ?P("accepted: ~p"
+ "~n => sockname", [S]),
SAddr = ok(inet:sockname(L)),
+ ?P("sockname: ~p"
+ "~n => peername (expect enotconn)", [SAddr]),
{error,enotconn} = inet:peername(L),
+ ?P("try local handshake"),
local_handshake(S, SAddr, C, {local,<<>>}),
+ ?P("close listen socket"),
ok = gen_tcp:close(L),
+ ?P("close accepted socket"),
ok = gen_tcp:close(S),
+ ?P("close connected socket (final)"),
ok = gen_tcp:close(C),
+ ?P("close connected socket (pre)"),
ok = gen_tcp:close(C0),
+ ?P("delete (local) file"),
ok = file:delete(SFile),
+ ?P("done"),
ok.
t_local_fdopen_listen(Config) ->
@@ -829,27 +919,48 @@ t_local_fdopen_connect_unbound(Config) ->
ok.
t_local_abstract(Config) ->
+ ?TC_TRY(t_local_abstract, fun() -> do_local_abstract(Config) end).
+
+do_local_abstract(Config) ->
+ ?P("only run on linux"),
case os:type() of
- {unix,linux} ->
+ {unix, linux} ->
AbstAddr = {local,<<>>},
InetBackendOpts = ?INET_BACKEND_OPTS(Config),
+ ?P("create listen socket"),
L =
ok(gen_tcp:listen(
0, InetBackendOpts ++ [{ifaddr,AbstAddr},{active,false}])),
- {local,_} = SAddr = ok(inet:sockname(L)),
+ ?P("listen socket created: ~p"
+ "~n => sockname", [L]),
+ {local, _} = SAddr = ok(inet:sockname(L)),
+ ?P("(listen socket) sockname verified"
+ "~n => try connect"),
C =
ok(gen_tcp:connect(
SAddr, 0,
InetBackendOpts ++ [{ifaddr,AbstAddr},{active,false}])),
+ ?P("connected: ~p"
+ "~n => sockname", [C]),
{local,_} = CAddr = ok(inet:sockname(C)),
+ ?P("(connected socket) sockname verified"
+ "~n => try accept"),
S = ok(gen_tcp:accept(L)),
+ ?P("accepted: ~p"
+ "~n => peername (expect enotconn)", [S]),
{error,enotconn} = inet:peername(L),
+ ?P("try local handshake"),
local_handshake(S, SAddr, C, CAddr),
+ ?P("close listen socket"),
ok = gen_tcp:close(L),
+ ?P("close accepted socket"),
ok = gen_tcp:close(S),
+ ?P("close connected socket"),
ok = gen_tcp:close(C),
+ ?P("done"),
ok;
_ ->
+ ?P("skip (unless linux)"),
{skip,"AF_LOCAL Abstract Addresses only supported on Linux"}
end.
@@ -868,19 +979,36 @@ local_handshake(S, SAddr, C, CAddr) ->
ok.
t_accept_inet6_tclass(Config) when is_list(Config) ->
+ ?TC_TRY(t_accept_inet6_tclass, fun() -> do_accept_inet6_tclass(Config) end).
+
+do_accept_inet6_tclass(Config) ->
TClassOpt = {tclass,8#56 bsl 2}, % Expedited forwarding
Loopback = {0,0,0,0,0,0,0,1},
+ ?P("create listen socket with tclass: ~p", [TClassOpt]),
case gen_tcp:listen(0, ?INET_BACKEND_OPTS(Config) ++ [inet6, {ip, Loopback}, TClassOpt]) of
- {ok,L} ->
+ {ok, L} ->
+ ?P("listen socket created: "
+ "~n ~p", [L]),
LPort = ok(inet:port(L)),
+ ?P("try to connect to port ~p", [LPort]),
Sa = ok(gen_tcp:connect(Loopback, LPort, ?INET_BACKEND_OPTS(Config))),
+ ?P("connected: ~p"
+ "~n => accept connection", [Sa]),
Sb = ok(gen_tcp:accept(L)),
+ ?P("accepted: ~p"
+ "~n => getopts (tclass)", [Sb]),
[TClassOpt] = ok(inet:getopts(Sb, [tclass])),
+ ?P("tclass verified => close accepted socket"),
ok = gen_tcp:close(Sb),
+ ?P("close connected socket"),
ok = gen_tcp:close(Sa),
+ ?P("close listen socket"),
ok = gen_tcp:close(L),
+ ?P("done"),
ok;
- {error,_} ->
+ {error, _Reason} ->
+ ?P("ERROR: Failed create listen socket"
+ "~n ~p", [_Reason]),
{skip,"IPv6 TCLASS not supported"}
end.
@@ -940,6 +1068,8 @@ connect_timeout({M,F,A}, Lower, Upper) ->
{skip, "Not tested -- got error " ++ atom_to_list(E)};
{error, enetunreach = E} ->
{skip, "Not tested -- got error " ++ atom_to_list(E)};
+ {error, ehostunreach = E} ->
+ {skip, "Not tested -- got error " ++ atom_to_list(E)};
{ok, Socket} -> % What the...
Pinfo = erlang:port_info(Socket),
Db = inet_db:lookup_socket(Socket),
@@ -971,18 +1101,20 @@ unused_ip() ->
%% This is not supported on all platforms (yet), so...
try net:getifaddrs() of
{ok, IfAddrs} ->
- io:format("we = ~p,"
- "unused_ip = ~p"
- " ~p"
- "~n", [Hent, IP, IfAddrs]);
+ ?P("~n we = ~p"
+ "~n unused_ip = ~p"
+ "~n ~p", [Hent, IP, IfAddrs]);
{error, _} ->
- io:format("we = ~p, unused_ip = ~p~n", [Hent, IP])
+ ?P("~n we: ~p"
+ "~n unused_ip: ~p", [Hent, IP])
catch
_:_:_ ->
- io:format("we = ~p, unused_ip = ~p~n", [Hent, IP])
+ ?P("~n we: ~p"
+ "~n unused_ip: ~p", [Hent, IP])
end;
true ->
- io:format("we = ~p, unused_ip = ~p~n", [Hent, IP])
+ ?P("~n we: ~p"
+ "~n unused_ip: ~p", [Hent, IP])
end,
IP.