diff options
Diffstat (limited to 'lib/kernel/test/gen_tcp_api_SUITE.erl')
-rw-r--r-- | lib/kernel/test/gen_tcp_api_SUITE.erl | 617 |
1 files changed, 438 insertions, 179 deletions
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index 962471c20c..1be016444f 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,21 +34,34 @@ t_recv_timeout/1, t_recv_eof/1, t_recv_delim/1, t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1, t_shutdown_async/1, - t_fdopen/1, t_fdconnect/1, t_implicit_inet6/1]). + t_fdopen/1, t_fdconnect/1, t_implicit_inet6/1, + t_local_basic/1, t_local_unbound/1, t_local_fdopen/1, + t_local_fdopen_listen/1, t_local_fdopen_listen_unbound/1, + t_local_fdopen_connect/1, t_local_fdopen_connect_unbound/1, + t_local_abstract/1, t_accept_inet6_tclass/1]). -export([getsockfd/0,closesockfd/1]). -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. all() -> [{group, t_accept}, {group, t_connect}, {group, t_recv}, t_shutdown_write, t_shutdown_both, t_shutdown_error, - t_shutdown_async, t_fdopen, t_fdconnect, t_implicit_inet6]. + t_shutdown_async, t_fdopen, t_fdconnect, t_implicit_inet6, + t_accept_inet6_tclass, + {group, t_local}]. groups() -> [{t_accept, [], [t_accept_timeout]}, {t_connect, [], [t_connect_timeout, t_connect_bad]}, - {t_recv, [], [t_recv_timeout, t_recv_eof, t_recv_delim]}]. + {t_recv, [], [t_recv_timeout, t_recv_eof, t_recv_delim]}, + {t_local, [], + [t_local_basic, t_local_unbound, t_local_fdopen, + t_local_fdopen_listen, t_local_fdopen_listen_unbound, + t_local_fdopen_connect, t_local_fdopen_connect_unbound, + t_local_abstract]}]. @@ -58,81 +71,93 @@ init_per_suite(Config) -> end_per_suite(_Config) -> ok. +init_per_group(t_local, Config) -> + case gen_tcp:connect({local,<<"/">>}, 0, []) of + {error,eafnosupport} -> + {skip, "AF_LOCAL not supported"}; + {error,_} -> + Config + end; init_per_group(_GroupName, Config) -> Config. -end_per_group(_,_Config) -> +end_per_group(t_local, _Config) -> + delete_local_filenames(); +end_per_group(_, _Config) -> ok. + +init_per_testcase(Func, Config) + when Func =:= undefined -> % Insert your testcase name here + dbg:tracer(), + dbg:p(self(), c), + dbg:tpl(prim_inet, cx), + dbg:tpl(local_tcp, cx), + dbg:tpl(inet, cx), + dbg:tpl(gen_tcp, cx), + Config; init_per_testcase(_Func, Config) -> - Dog = test_server:timetrap(test_server:seconds(60)), - [{watchdog, Dog}|Config]. -end_per_testcase(_Func, Config) -> - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog). + Config. + +end_per_testcase(_Func, _Config) -> + dbg:stop(). %%% gen_tcp:accept/1,2 -t_accept_timeout(doc) -> "Test that gen_tcp:accept/2 (with timeout) works."; -t_accept_timeout(suite) -> []; +%% Test that gen_tcp:accept/2 (with timeout) works. t_accept_timeout(Config) when is_list(Config) -> - ?line {ok, L} = gen_tcp:listen(0, []), - ?line timeout({gen_tcp, accept, [L, 200]}, 0.2, 1.0). + {ok, L} = gen_tcp:listen(0, []), + timeout({gen_tcp, accept, [L, 200]}, 0.2, 1.0). %%% gen_tcp:connect/X -t_connect_timeout(doc) -> "Test that gen_tcp:connect/4 (with timeout) works."; +%% Test that gen_tcp:connect/4 (with timeout) works. t_connect_timeout(Config) when is_list(Config) -> - %%?line BadAddr = {134,138,177,16}, - %%?line TcpPort = 80, - ?line {ok, BadAddr} = unused_ip(), - ?line TcpPort = 45638, - ?line ok = io:format("Connecting to ~p, port ~p", [BadAddr, TcpPort]), - ?line connect_timeout({gen_tcp,connect,[BadAddr,TcpPort,[],200]}, 0.2, 5.0). - -t_connect_bad(doc) -> - ["Test that gen_tcp:connect/3 handles non-existings hosts, and other ", - "invalid things."]; -t_connect_bad(suite) -> []; + %%BadAddr = {134,138,177,16}, + %%TcpPort = 80, + {ok, BadAddr} = unused_ip(), + TcpPort = 45638, + ok = io:format("Connecting to ~p, port ~p", [BadAddr, TcpPort]), + connect_timeout({gen_tcp,connect,[BadAddr,TcpPort,[],200]}, 0.2, 5.0). + +%% Test that gen_tcp:connect/3 handles non-existings hosts, and other +%% invalid things. t_connect_bad(Config) when is_list(Config) -> - ?line NonExistingPort = 45638, % Not in use, I hope. - ?line {error, Reason1} = gen_tcp:connect(localhost, NonExistingPort, []), - ?line io:format("Error for connection attempt to port not in use: ~p", - [Reason1]), - - ?line {error, Reason2} = gen_tcp:connect("non-existing-host-xxx", 7, []), - ?line io:format("Error for connection attempt to non-existing host: ~p", - [Reason2]), + NonExistingPort = 45638, % Not in use, I hope. + {error, Reason1} = gen_tcp:connect(localhost, NonExistingPort, []), + io:format("Error for connection attempt to port not in use: ~p", + [Reason1]), + + {error, Reason2} = gen_tcp:connect("non-existing-host-xxx", 7, []), + io:format("Error for connection attempt to non-existing host: ~p", + [Reason2]), ok. %%% gen_tcp:recv/X -t_recv_timeout(doc) -> "Test that gen_tcp:recv/3 (with timeout works)."; -t_recv_timeout(suite) -> []; +%% Test that gen_tcp:recv/3 (with timeout works). t_recv_timeout(Config) when is_list(Config) -> - ?line {ok, L} = gen_tcp:listen(0, []), - ?line {ok, Port} = inet:port(L), - ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), - ?line {ok, _A} = gen_tcp:accept(L), - ?line timeout({gen_tcp, recv, [Client, 0, 200]}, 0.2, 5.0). - -t_recv_eof(doc) -> "Test that end of file on a socket is reported correctly."; -t_recv_eof(suite) -> []; + {ok, L} = gen_tcp:listen(0, []), + {ok, Port} = inet:port(L), + {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), + {ok, _A} = gen_tcp:accept(L), + timeout({gen_tcp, recv, [Client, 0, 200]}, 0.2, 5.0). + +%% Test that end of file on a socket is reported correctly. t_recv_eof(Config) when is_list(Config) -> - ?line {ok, L} = gen_tcp:listen(0, []), - ?line {ok, Port} = inet:port(L), - ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), - ?line {ok, A} = gen_tcp:accept(L), - ?line ok = gen_tcp:close(A), - ?line {error, closed} = gen_tcp:recv(Client, 0), + {ok, L} = gen_tcp:listen(0, []), + {ok, Port} = inet:port(L), + {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), + {ok, A} = gen_tcp:accept(L), + ok = gen_tcp:close(A), + {error, closed} = gen_tcp:recv(Client, 0), ok. -t_recv_delim(doc) -> "Test using message delimiter $X"; -t_recv_delim(suite) -> []; +%% Test using message delimiter $X. t_recv_delim(Config) when is_list(Config) -> {ok, L} = gen_tcp:listen(0, []), {ok, Port} = inet:port(L), @@ -140,8 +165,8 @@ t_recv_delim(Config) when is_list(Config) -> {ok, Client} = gen_tcp:connect(localhost, Port, Opts), {ok, A} = gen_tcp:accept(L), ok = gen_tcp:send(A, "abcXefgX"), - {ok, "abcX"} = gen_tcp:recv(Client, 0, 0), - {ok, "efgX"} = gen_tcp:recv(Client, 0, 0), + {ok, "abcX"} = gen_tcp:recv(Client, 0, 200), + {ok, "efgX"} = gen_tcp:recv(Client, 0, 200), ok = gen_tcp:close(Client), ok = gen_tcp:close(A), ok. @@ -149,96 +174,96 @@ t_recv_delim(Config) when is_list(Config) -> %%% gen_tcp:shutdown/2 t_shutdown_write(Config) when is_list(Config) -> - ?line {ok, L} = gen_tcp:listen(0, []), - ?line {ok, Port} = inet:port(L), - ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), - ?line {ok, A} = gen_tcp:accept(L), - ?line ok = gen_tcp:shutdown(A, write), - ?line {error, closed} = gen_tcp:recv(Client, 0), + {ok, L} = gen_tcp:listen(0, []), + {ok, Port} = inet:port(L), + {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), + {ok, A} = gen_tcp:accept(L), + ok = gen_tcp:shutdown(A, write), + {error, closed} = gen_tcp:recv(Client, 0), ok. t_shutdown_both(Config) when is_list(Config) -> - ?line {ok, L} = gen_tcp:listen(0, []), - ?line {ok, Port} = inet:port(L), - ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), - ?line {ok, A} = gen_tcp:accept(L), - ?line ok = gen_tcp:shutdown(A, read_write), - ?line {error, closed} = gen_tcp:recv(Client, 0), + {ok, L} = gen_tcp:listen(0, []), + {ok, Port} = inet:port(L), + {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), + {ok, A} = gen_tcp:accept(L), + ok = gen_tcp:shutdown(A, read_write), + {error, closed} = gen_tcp:recv(Client, 0), ok. t_shutdown_error(Config) when is_list(Config) -> - ?line {ok, L} = gen_tcp:listen(0, []), - ?line {error, enotconn} = gen_tcp:shutdown(L, read_write), - ?line ok = gen_tcp:close(L), - ?line {error, closed} = gen_tcp:shutdown(L, read_write), + {ok, L} = gen_tcp:listen(0, []), + {error, enotconn} = gen_tcp:shutdown(L, read_write), + ok = gen_tcp:close(L), + {error, closed} = gen_tcp:shutdown(L, read_write), ok. t_shutdown_async(Config) when is_list(Config) -> - ?line {OS, _} = os:type(), - ?line {ok, L} = gen_tcp:listen(0, [{sndbuf, 4096}]), - ?line {ok, Port} = inet:port(L), - ?line {ok, Client} = gen_tcp:connect(localhost, Port, - [{recbuf, 4096}, - {active, false}]), - ?line {ok, S} = gen_tcp:accept(L), - ?line PayloadSize = 1024 * 1024, - ?line Payload = lists:duplicate(PayloadSize, $.), - ?line ok = gen_tcp:send(S, Payload), - ?line 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 -> ?t:fail({unexpected, T}) - end, - - ?line ok = gen_tcp:shutdown(S, write), - ?line {ok, Buf} = gen_tcp:recv(Client, PayloadSize), - ?line {error, closed} = gen_tcp:recv(Client, 0), - ?line case length(Buf) of - PayloadSize -> ok; - Sz -> ?t:fail({payload_size, - {expected, PayloadSize}, - {received, Sz}}) - end. + {OS, _} = os:type(), + {ok, L} = gen_tcp:listen(0, [{sndbuf, 4096}]), + {ok, Port} = inet:port(L), + {ok, Client} = gen_tcp:connect(localhost, Port, + [{recbuf, 4096}, + {active, false}]), + {ok, S} = gen_tcp:accept(L), + PayloadSize = 1024 * 1024, + Payload = lists:duplicate(PayloadSize, $.), + ok = gen_tcp:send(S, Payload), + 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, + + ok = gen_tcp:shutdown(S, write), + {ok, Buf} = gen_tcp:recv(Client, PayloadSize), + {error, closed} = gen_tcp:recv(Client, 0), + case length(Buf) of + PayloadSize -> ok; + Sz -> ct:fail({payload_size, + {expected, PayloadSize}, + {received, Sz}}) + end. %%% gen_tcp:fdopen/2 t_fdopen(Config) when is_list(Config) -> - ?line Question = "Aaaa... Long time ago in a small town in Germany,", - ?line Question1 = list_to_binary(Question), - ?line Question2 = [<<"Aaaa">>, "... ", $L, <<>>, $o, "ng time ago ", - ["in ", [], <<"a small town">>, [" in Germany,", <<>>]]], - ?line Question1 = iolist_to_binary(Question2), - ?line Answer = "there was a shoemaker, Schumacher was his name.", - ?line {ok, L} = gen_tcp:listen(0, [{active, false}]), - ?line {ok, Port} = inet:port(L), - ?line {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), - ?line {ok, A} = gen_tcp:accept(L), - ?line {ok, FD} = prim_inet:getfd(A), - ?line {ok, Server} = gen_tcp:fdopen(FD, []), - ?line ok = gen_tcp:send(Client, Question), - ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), - ?line ok = gen_tcp:send(Client, Question1), - ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), - ?line ok = gen_tcp:send(Client, Question2), - ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), - ?line ok = gen_tcp:send(Server, Answer), - ?line {ok, Answer} = gen_tcp:recv(Client, length(Answer), 2000), - ?line ok = gen_tcp:close(Client), - ?line {error,closed} = gen_tcp:recv(A, 1, 2000), - ?line ok = gen_tcp:close(Server), - ?line ok = gen_tcp:close(A), - ?line ok = gen_tcp:close(L), + Question = "Aaaa... Long time ago in a small town in Germany,", + Question1 = list_to_binary(Question), + Question2 = [<<"Aaaa">>, "... ", $L, <<>>, $o, "ng time ago ", + ["in ", [], <<"a small town">>, [" in Germany,", <<>>]]], + Question1 = iolist_to_binary(Question2), + Answer = "there was a shoemaker, Schumacher was his name.", + {ok, L} = gen_tcp:listen(0, [{active, false}]), + {ok, Port} = inet:port(L), + {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]), + {ok, A} = gen_tcp:accept(L), + {ok, FD} = prim_inet:getfd(A), + {ok, Server} = gen_tcp:fdopen(FD, []), + ok = gen_tcp:send(Client, Question), + {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), + ok = gen_tcp:send(Client, Question1), + {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), + ok = gen_tcp:send(Client, Question2), + {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), + ok = gen_tcp:send(Server, Answer), + {ok, Answer} = gen_tcp:recv(Client, length(Answer), 2000), + ok = gen_tcp:close(Client), + {error,closed} = gen_tcp:recv(A, 1, 2000), + ok = gen_tcp:close(Server), + ok = gen_tcp:close(A), + ok = gen_tcp:close(L), ok. t_fdconnect(Config) when is_list(Config) -> Question = "Aaaa... Long time ago in a small town in Germany,", Question1 = list_to_binary(Question), Question2 = [<<"Aaaa">>, "... ", $L, <<>>, $o, "ng time ago ", - ["in ", [], <<"a small town">>, [" in Germany,", <<>>]]], + ["in ", [], <<"a small town">>, [" in Germany,", <<>>]]], Question1 = iolist_to_binary(Question2), Answer = "there was a shoemaker, Schumacher was his name.", - Path = ?config(data_dir, Config), + Path = proplists:get_value(data_dir, Config), Lib = "gen_tcp_api_SUITE", ok = erlang:load_nif(filename:join(Path,Lib), []), {ok, L} = gen_tcp:listen(0, [{active, false}]), @@ -266,53 +291,253 @@ t_fdconnect(Config) when is_list(Config) -> %%% implicit inet6 option to api functions t_implicit_inet6(Config) when is_list(Config) -> - ?line Host = ok(inet:gethostname()), - ?line - case inet:getaddr(Host, inet6) of - {ok,Addr} -> - ?line t_implicit_inet6(Host, Addr); - {error,Reason} -> - {skip, - "Can not look up IPv6 address: " - ++atom_to_list(Reason)} - end. + Host = ok(inet:gethostname()), + case inet:getaddr(Host, inet6) of + {ok,Addr} -> + t_implicit_inet6(Host, Addr); + {error,Reason} -> + {skip, + "Can not look up IPv6 address: " + ++atom_to_list(Reason)} + end. t_implicit_inet6(Host, Addr) -> - ?line - case gen_tcp:listen(0, [inet6]) of - {ok,S1} -> - ?line Loopback = {0,0,0,0,0,0,0,1}, - ?line io:format("~s ~p~n", ["::1",Loopback]), - ?line implicit_inet6(S1, Loopback), - ?line ok = gen_tcp:close(S1), - %% - ?line Localhost = "localhost", - ?line Localaddr = ok(inet:getaddr(Localhost, inet6)), - ?line io:format("~s ~p~n", [Localhost,Localaddr]), - ?line S2 = ok(gen_tcp:listen(0, [{ip,Localaddr}])), - ?line implicit_inet6(S2, Localaddr), - ?line ok = gen_tcp:close(S2), - %% - ?line io:format("~s ~p~n", [Host,Addr]), - ?line S3 = ok(gen_tcp:listen(0, [{ifaddr,Addr}])), - ?line implicit_inet6(S3, Addr), - ?line ok = gen_tcp:close(S3); - {error,_} -> - {skip,"IPv6 not supported"} - end. + Loopback = {0,0,0,0,0,0,0,1}, + case gen_tcp:listen(0, [inet6, {ip,Loopback}]) of + {ok,S1} -> + io:format("~s ~p~n", ["::1",Loopback]), + implicit_inet6(S1, Loopback), + ok = gen_tcp:close(S1), + %% + Localaddr = ok(get_localaddr()), + S2 = ok(gen_tcp:listen(0, [{ip,Localaddr}])), + implicit_inet6(S2, Localaddr), + ok = gen_tcp:close(S2), + %% + io:format("~s ~p~n", [Host,Addr]), + S3 = ok(gen_tcp:listen(0, [{ifaddr,Addr}])), + implicit_inet6(S3, Addr), + ok = gen_tcp:close(S3); + {error,_} -> + {skip,"IPv6 not supported"} + end. implicit_inet6(S, Addr) -> - ?line P = ok(inet:port(S)), - ?line S2 = ok(gen_tcp:connect(Addr, P, [])), - ?line P2 = ok(inet:port(S2)), - ?line S1 = ok(gen_tcp:accept(S)), - ?line P1 = P = ok(inet:port(S1)), - ?line {Addr,P2} = ok(inet:peername(S1)), - ?line {Addr,P1} = ok(inet:peername(S2)), - ?line {Addr,P1} = ok(inet:sockname(S1)), - ?line {Addr,P2} = ok(inet:sockname(S2)), - ?line ok = gen_tcp:close(S2), - ?line ok = gen_tcp:close(S1). + P = ok(inet:port(S)), + S2 = ok(gen_tcp:connect(Addr, P, [])), + P2 = ok(inet:port(S2)), + S1 = ok(gen_tcp:accept(S)), + P1 = P = ok(inet:port(S1)), + {Addr,P2} = ok(inet:peername(S1)), + {Addr,P1} = ok(inet:peername(S2)), + {Addr,P1} = ok(inet:sockname(S1)), + {Addr,P2} = ok(inet:sockname(S2)), + ok = gen_tcp:close(S2), + ok = gen_tcp:close(S1). + + + +t_local_basic(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + CFile = local_filename(client), + CAddr = {local,bin_filename(CFile)}, + _ = file:delete(SFile), + _ = file:delete(CFile), + %% + L = + ok( + gen_tcp:listen(0, [{ifaddr,{local,SFile}},{active,false}])), + C = + ok( + gen_tcp:connect( + {local,SFile}, 0, [{ifaddr,{local,CFile}},{active,false}])), + S = ok(gen_tcp:accept(L)), + SAddr = ok(inet:sockname(L)), + {error,enotconn} = inet:peername(L), + local_handshake(S, SAddr, C, CAddr), + ok = gen_tcp:close(L), + ok = gen_tcp:close(S), + ok = gen_tcp:close(C), + %% + ok = file:delete(SFile), + ok = file:delete(CFile), + ok. + +t_local_unbound(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + _ = file:delete(SFile), + %% + L = ok(gen_tcp:listen(0, [{ifaddr,SAddr},{active,false}])), + C = ok(gen_tcp:connect(SAddr, 0, [{active,false}])), + S = ok(gen_tcp:accept(L)), + SAddr = ok(inet:sockname(L)), + {error,enotconn} = inet:peername(L), + local_handshake(S, SAddr, C, {local,<<>>}), + ok = gen_tcp:close(L), + ok = gen_tcp:close(S), + ok = gen_tcp:close(C), + ok = file:delete(SFile), + ok. + +t_local_fdopen(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + _ = file:delete(SFile), + %% + L = ok(gen_tcp:listen(0, [{ifaddr,SAddr},{active,false}])), + C0 = ok(gen_tcp:connect(SAddr, 0, [{active,false}])), + Fd = ok(prim_inet:getfd(C0)), + ok = prim_inet:ignorefd(C0, true), + C = ok(gen_tcp:fdopen(Fd, [local])), + S = ok(gen_tcp:accept(L)), + SAddr = ok(inet:sockname(L)), + {error,enotconn} = inet:peername(L), + local_handshake(S, SAddr, C, {local,<<>>}), + ok = gen_tcp:close(L), + ok = gen_tcp:close(S), + ok = gen_tcp:close(C), + ok = gen_tcp:close(C0), + ok = file:delete(SFile), + ok. + +t_local_fdopen_listen(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + _ = file:delete(SFile), + L0 = ok(gen_tcp:listen(0, [{ifaddr,SAddr},{active,false}])), + Fd = ok(prim_inet:getfd(L0)), + L = ok(gen_tcp:listen(0, [{fd,Fd},local,{active,false}])), + C = ok(gen_tcp:connect(SAddr, 0, [{active,false}])), + S = ok(gen_tcp:accept(L)), + SAddr = ok(inet:sockname(L)), + {error,enotconn} = inet:peername(L), + local_handshake(S, SAddr, C, {local,<<>>}), + ok = gen_tcp:close(L), + ok = gen_tcp:close(L0), + ok = gen_tcp:close(S), + ok = gen_tcp:close(C), + ok = file:delete(SFile), + ok. + +t_local_fdopen_listen_unbound(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + _ = file:delete(SFile), + P = ok(prim_inet:open(tcp, local, stream)), + Fd = ok(prim_inet:getfd(P)), + L = + ok(gen_tcp:listen( + 0, [{fd,Fd},{ifaddr,SAddr},{active,false}])), + C = ok(gen_tcp:connect(SAddr, 0, [{active,false}])), + S = ok(gen_tcp:accept(L)), + SAddr = ok(inet:sockname(L)), + {error,enotconn} = inet:peername(L), + local_handshake(S, SAddr, C, {local,<<>>}), + ok = gen_tcp:close(L), + ok = gen_tcp:close(P), + ok = gen_tcp:close(S), + ok = gen_tcp:close(C), + ok = file:delete(SFile), + ok. + +t_local_fdopen_connect(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + CFile = local_filename(client), + CAddr = {local,bin_filename(CFile)}, + _ = file:delete(SFile), + _ = file:delete(CFile), + L = ok(gen_tcp:listen(0, [{ifaddr,SAddr},{active,false}])), + P = ok(prim_inet:open(tcp, local, stream)), + Fd = ok(prim_inet:getfd(P)), + C = + ok(gen_tcp:connect( + SAddr, 0, [{fd,Fd},{ifaddr,CAddr},{active,false}])), + S = ok(gen_tcp:accept(L)), + SAddr = ok(inet:sockname(L)), + {error,enotconn} = inet:peername(L), + local_handshake(S, SAddr, C, CAddr), + ok = gen_tcp:close(L), + ok = gen_tcp:close(S), + ok = gen_tcp:close(C), + ok = gen_tcp:close(P), + ok = file:delete(SFile), + ok. + +t_local_fdopen_connect_unbound(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + _ = file:delete(SFile), + L = ok(gen_tcp:listen(0, [{ifaddr,SAddr},{active,false}])), + P = ok(prim_inet:open(tcp, local, stream)), + Fd = ok(prim_inet:getfd(P)), + C = ok(gen_tcp:connect(SAddr, 0, [{fd,Fd},{active,false}])), + S = ok(gen_tcp:accept(L)), + SAddr = ok(inet:sockname(L)), + {error,enotconn} = inet:peername(L), + local_handshake(S, SAddr, C, {local,<<>>}), + ok = gen_tcp:close(L), + ok = gen_tcp:close(S), + ok = gen_tcp:close(C), + ok = gen_tcp:close(P), + ok = file:delete(SFile), + ok. + +t_local_abstract(_Config) -> + case os:type() of + {unix,linux} -> + AbstAddr = {local,<<>>}, + L = + ok(gen_tcp:listen( + 0, [{ifaddr,AbstAddr},{active,false}])), + {local,_} = SAddr = ok(inet:sockname(L)), + C = + ok(gen_tcp:connect( + SAddr, 0, [{ifaddr,AbstAddr},{active,false}])), + {local,_} = CAddr = ok(inet:sockname(C)), + S = ok(gen_tcp:accept(L)), + {error,enotconn} = inet:peername(L), + local_handshake(S, SAddr, C, CAddr), + ok = gen_tcp:close(L), + ok = gen_tcp:close(S), + ok = gen_tcp:close(C), + ok; + _ -> + {skip,"AF_LOCAL Abstract Addresses only supported on Linux"} + end. + + +local_handshake(S, SAddr, C, CAddr) -> + SData = "9876543210", + CData = "0123456789", + SAddr = ok(inet:sockname(S)), + CAddr = ok(inet:sockname(C)), + CAddr = ok(inet:peername(S)), + SAddr = ok(inet:peername(C)), + ok = gen_tcp:send(C, CData), + ok = gen_tcp:send(S, SData), + CData = ok(gen_tcp:recv(S, length(CData))), + SData = ok(gen_tcp:recv(C, length(SData))), + ok. + +t_accept_inet6_tclass(Config) when is_list(Config) -> + TClassOpt = {tclass,8#56 bsl 2}, % Expedited forwarding + Loopback = {0,0,0,0,0,0,0,1}, + case gen_tcp:listen(0, [inet6, {ip, Loopback}, TClassOpt]) of + {ok,L} -> + LPort = ok(inet:port(L)), + Sa = ok(gen_tcp:connect(Loopback, LPort, [])), + Sb = ok(gen_tcp:accept(L)), + [TClassOpt] = ok(inet:getopts(Sb, [tclass])), + ok = gen_tcp:close(Sb), + ok = gen_tcp:close(Sa), + ok = gen_tcp:close(L), + ok; + {error,_} -> + {skip,"IPv6 TCLASS not supported"} + end. %%% Utilities @@ -323,13 +548,13 @@ implicit_inet6(S, Addr) -> timeout({M,F,A}, Lower, Upper) -> case test_server:timecall(M, F, A) of {Time, Result} when Time < Lower -> - test_server:fail({too_short_time, Time, Result}); + ct:fail({too_short_time, Time, Result}); {Time, Result} when Time > Upper -> - test_server:fail({too_long_time, Time, Result}); + ct:fail({too_long_time, Time, Result}); {_, {error, timeout}} -> ok; {_, Result} -> - test_server:fail({unexpected_result, Result}) + ct:fail({unexpected_result, Result}) end. connect_timeout({M,F,A}, Lower, Upper) -> @@ -344,28 +569,28 @@ connect_timeout({M,F,A}, Lower, Upper) -> Pinfo = erlang:port_info(Socket), Db = inet_db:lookup_socket(Socket), Peer = inet:peername(Socket), - test_server:fail({too_short_time, Time, - [Result,Pinfo,Db,Peer]}); + ct:fail({too_short_time, Time, + [Result,Pinfo,Db,Peer]}); _ -> - test_server:fail({too_short_time, Time, Result}) + ct:fail({too_short_time, Time, Result}) end; {Time, Result} when Time > Upper -> - test_server:fail({too_long_time, Time, Result}); + ct:fail({too_long_time, Time, Result}); {_, {error, timeout}} -> ok; {_, Result} -> - test_server:fail({unexpected_result, Result}) + ct:fail({unexpected_result, Result}) end. %% Try to obtain an unused IP address in the local network. unused_ip() -> - ?line {ok, Host} = inet:gethostname(), - ?line {ok, Hent} = inet:gethostbyname(Host), - ?line #hostent{h_addr_list=[{A, B, C, _D}|_]} = Hent, + {ok, Host} = inet:gethostname(), + {ok, Hent} = inet:gethostbyname(Host), + #hostent{h_addr_list=[{A, B, C, _D}|_]} = Hent, %% Note: In our net, addresses below 16 are reserved for routers and %% other strange creatures. - ?line IP = unused_ip(A, B, C, 16), + IP = unused_ip(A, B, C, 16), io:format("we = ~p, unused_ip = ~p~n", [Hent, IP]), IP. @@ -376,8 +601,42 @@ unused_ip(A, B, C, D) -> {error, _} -> {ok, {A, B, C, D}} end. -ok({ok,V}) -> V. +ok({ok,V}) -> V; +ok(NotOk) -> + try throw(not_ok) + catch + throw:Thrown:Stacktrace -> + erlang:raise( + error, {Thrown, NotOk}, tl(Stacktrace)) + end. +get_localaddr() -> + get_localaddr(["localhost", "localhost6", "ip6-localhost"]). + +get_localaddr([]) -> + {error, localaddr_not_found}; +get_localaddr([Localhost|Ls]) -> + case inet:getaddr(Localhost, inet6) of + {ok, LocalAddr} -> + io:format("~s ~p~n", [Localhost, LocalAddr]), + {ok, LocalAddr}; + _ -> + get_localaddr(Ls) + end. getsockfd() -> undefined. closesockfd(_FD) -> undefined. + +local_filename(Tag) -> + "/tmp/" ?MODULE_STRING "_" ++ os:getpid() ++ "_" ++ atom_to_list(Tag). + +bin_filename(String) -> + unicode:characters_to_binary(String, file:native_name_encoding()). + +delete_local_filenames() -> + _ = + [file:delete(F) || + F <- + filelib:wildcard( + "/tmp/" ?MODULE_STRING "_" ++ os:getpid() ++ "_*")], + ok. |