diff options
Diffstat (limited to 'lib/kernel/test/gen_tcp_api_SUITE.erl')
-rw-r--r-- | lib/kernel/test/gen_tcp_api_SUITE.erl | 176 |
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. |