aboutsummaryrefslogtreecommitdiffstats
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.erl617
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.