aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test/inet_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test/inet_SUITE.erl')
-rw-r--r--lib/kernel/test/inet_SUITE.erl735
1 files changed, 735 insertions, 0 deletions
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
new file mode 100644
index 0000000000..cf33e8b27f
--- /dev/null
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -0,0 +1,735 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(inet_SUITE).
+
+-include("test_server.hrl").
+-include_lib("kernel/include/inet.hrl").
+-include_lib("kernel/src/inet_dns.hrl").
+
+-export([all/1, t_gethostbyaddr/1, t_getaddr/1, t_gethostbyname/1,
+ t_gethostbyaddr_v6/1, t_getaddr_v6/1, t_gethostbyname_v6/1,
+ ipv4_to_ipv6/1, host_and_addr/1, parse/1, t_gethostnative/1,
+ gethostnative_parallell/1, cname_loop/1,
+ gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1]).
+
+-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1,
+ kill_gethost/0, parallell_gethost/0]).
+-export([init_per_testcase/2, end_per_testcase/2]).
+
+
+all(suite) ->
+ [t_gethostbyaddr, t_gethostbyname, t_getaddr,
+ t_gethostbyaddr_v6, t_gethostbyname_v6, t_getaddr_v6,
+ ipv4_to_ipv6, host_and_addr, parse,t_gethostnative,
+ gethostnative_parallell, cname_loop,
+ gethostnative_debug_level,gethostnative_soft_restart,
+ getif].
+
+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).
+
+
+t_gethostbyaddr(doc) -> "Test the inet:gethostbyaddr/1 function.";
+t_gethostbyaddr(Config) when is_list(Config) ->
+ ?line {Name,FullName,IPStr,IP,Aliases,_,_} = ?config(test_host_ipv4_only, Config),
+ ?line {ok,HEnt} = inet:gethostbyaddr(IPStr),
+ ?line {ok,HEnt} = inet:gethostbyaddr(IP),
+ ?line {error,Error} = inet:gethostbyaddr(Name),
+ ?line ok = io:format("Failure reason: ~p: ~s",
+ [error,inet:format_error(Error)]),
+ ?line HEnt_ = HEnt#hostent{h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [IP]},
+ ?line HEnt_ = HEnt,
+ case {os:type(),os:version()} of
+ {{unix,freebsd},{5,0,0}} ->
+ %% The alias list seems to be buggy in FreeBSD 5.0.0.
+ ?line check_elems([{HEnt#hostent.h_name,[Name,FullName]}]),
+ io:format("Buggy alias list: ~p", [HEnt#hostent.h_aliases]),
+ ok;
+ _ ->
+ ?line check_elems([{HEnt#hostent.h_name,[Name,FullName]},
+ {HEnt#hostent.h_aliases,[[],Aliases]}])
+ end,
+
+ ?line {_DName, _DFullName, DIPStr, DIP, _, _, _} =
+ ?config(test_dummy_host, Config),
+ ?line {error,nxdomain} = inet:gethostbyaddr(DIPStr),
+ ?line {error,nxdomain} = inet:gethostbyaddr(DIP),
+ ok.
+
+t_gethostbyaddr_v6(doc) -> "Test the inet:gethostbyaddr/1 inet6 function.";
+t_gethostbyaddr_v6(Config) when is_list(Config) ->
+ ?line {Name6, FullName6, IPStr6, IP6, Aliases6} =
+ ?config(test_host_ipv6_only, Config),
+
+ ?line case inet:gethostbyaddr(IPStr6) of
+ %% Even if IPv6 is not supported, the native resolver may succeed
+ %% looking up the host. DNS lookup will probably fail.
+ {error,nxdomain} ->
+ {skip, "IPv6 test fails! IPv6 not supported on this host!?"};
+ {ok,HEnt6} ->
+ ?line {ok,HEnt6} = inet:gethostbyaddr(IP6),
+ ?line {error,Error6} = inet:gethostbyaddr(Name6),
+ ?line ok = io:format("Failure reason: ~p: ~s",
+ [Error6, inet:format_error(Error6)]),
+ ?line HEnt6_ = HEnt6#hostent{h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [IP6]},
+ ?line HEnt6_ = HEnt6,
+ ?line check_elems([{HEnt6#hostent.h_name,[Name6,FullName6]},
+ {HEnt6#hostent.h_aliases,[[],Aliases6]}]),
+
+ ?line {_DName6, _DFullName6, DIPStr6, DIP6, _} =
+ ?config(test_dummy_ipv6_host, Config),
+ ?line {error,nxdomain} = inet:gethostbyaddr(DIPStr6),
+ ?line {error,nxdomain} = inet:gethostbyaddr(DIP6),
+ ok
+ end.
+
+t_gethostbyname(doc) -> "Test the inet:gethostbyname/1 function.";
+t_gethostbyname(suite) -> [];
+t_gethostbyname(Config) when is_list(Config) ->
+ ?line {Name,FullName,IPStr,IP,Aliases,IP_46_Str,_} =
+ ?config(test_host_ipv4_only, Config),
+ ?line {ok,_} = inet:gethostbyname(IPStr),
+ ?line {ok,HEnt} = inet:gethostbyname(Name),
+ ?line {ok,HEnt} = inet:gethostbyname(list_to_atom(Name)),
+ ?line HEnt_ = HEnt#hostent{h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [IP]},
+ ?line HEnt_ = HEnt,
+ ?line check_elems([{HEnt#hostent.h_name,[Name,FullName]},
+ {HEnt#hostent.h_aliases,[[],Aliases]}]),
+
+ ?line {ok,HEntF} = inet:gethostbyname(FullName),
+ ?line HEntF_ = HEntF#hostent{h_name = FullName,
+ h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [IP]},
+ ?line HEntF_ = HEntF,
+ ?line check_elems([{HEnt#hostent.h_aliases,[[],Aliases]}]),
+
+ ?line {DName, _DFullName, _DIPStr, _DIP, _, _, _} =
+ ?config(test_dummy_host, Config),
+ ?line {error,nxdomain} = inet:gethostbyname(DName),
+ ?line {error,nxdomain} = inet:gethostbyname(IP_46_Str).
+
+t_gethostbyname_v6(doc) -> "Test the inet:gethostbyname/1 inet6 function.";
+t_gethostbyname_v6(suite) -> [];
+t_gethostbyname_v6(Config) when is_list(Config) ->
+ ?line {Name, _, _, _,Aliases,IP_46_Str,IP_46} =
+ ?config(test_host_ipv4_only, Config),
+
+ case {inet:gethostbyname(IP_46_Str, inet6),
+ inet:gethostbyname(Name, inet6)} of
+ {{ok,HEnt46},{ok,_}} ->
+ ?line HEnt46_ = HEnt46#hostent{h_name = IP_46_Str,
+ h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [IP_46]},
+ ?line HEnt46_ = HEnt46,
+ ?line check_elems([{HEnt46#hostent.h_aliases,[[],Aliases]}]),
+
+ ?line {Name6, FullName6, IPStr6, IP6, Aliases6} =
+ ?config(test_host_ipv6_only, Config),
+ ?line {ok,_} = inet:gethostbyname(IPStr6, inet6),
+ ?line {ok,HEnt6} = inet:gethostbyname(Name6, inet6),
+ ?line {ok,HEnt6} = inet:gethostbyname(list_to_atom(Name6), inet6),
+ ?line case HEnt6#hostent.h_addr_list of
+ [IP6] -> % ipv6 ok
+ ?line HEnt6_ = HEnt6#hostent{h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [IP6]},
+ ?line HEnt6_ = HEnt6,
+ ?line check_elems([{HEnt6#hostent.h_name,[Name6,FullName6]},
+ {HEnt6#hostent.h_aliases,[[],Aliases6]}]);
+ _ -> % ipv4 compatible addr
+ ?line {ok,HEnt4} = inet:gethostbyname(Name6, inet),
+ ?line [IP4] = HEnt4#hostent.h_addr_list,
+ ?line {ok,IP46_2} =
+ inet_parse:ipv6_address("::ffff:"++inet_parse:ntoa(IP4)),
+ ?line HEnt6_ = HEnt6#hostent{h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [IP46_2]},
+ ?line HEnt6_ = HEnt6,
+ ?line check_elems([{HEnt6#hostent.h_name,[Name6,FullName6]}])
+ end,
+
+ ?line {ok,HEntF6} = inet:gethostbyname(FullName6, inet6),
+ ?line case HEntF6#hostent.h_addr_list of
+ [IP6] -> % ipv6 ok
+ ?line HEntF6_ = HEntF6#hostent{h_name = FullName6,
+ h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [IP6]},
+ ?line HEntF6_ = HEntF6,
+ ?line check_elems([{HEntF6#hostent.h_aliases,[[],Aliases6]}]);
+ _ -> % ipv4 compatible addr
+ ?line {ok,HEntF4} = inet:gethostbyname(FullName6, inet),
+ ?line [IPF4] = HEntF4#hostent.h_addr_list,
+ ?line {ok,IPF46_2} =
+ inet_parse:ipv6_address("::ffff:"++inet_parse:ntoa(IPF4)),
+ ?line HEntF6_ = HEntF6#hostent{h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [IPF46_2]},
+ ?line HEntF6_ = HEntF6,
+ ?line check_elems([{HEntF6#hostent.h_name,[Name6,FullName6]}])
+ end,
+
+ ?line {DName6, _DFullName6, _DIPStr6, _DIP6, _} =
+ ?config(test_dummy_ipv6_host, Config),
+ ?line {error,nxdomain} = inet:gethostbyname(DName6, inet6),
+ ok;
+ {_,_} ->
+ {skip, "IPv6 is not supported on this host"}
+ end.
+
+check_elems([{Val,Tests} | Elems]) ->
+ check_elem(Val, Tests, Tests),
+ check_elems(Elems);
+check_elems([]) -> ok.
+
+check_elem(Val, [Val|_], _) -> ok;
+check_elem(Val, [_|Tests], Tests0) ->
+ check_elem(Val, Tests, Tests0);
+check_elem(Val, [], Tests0) ->
+ ?t:fail({no_match,Val,Tests0}).
+
+
+t_getaddr(doc) -> "Test the inet:getaddr/2 function.";
+t_getaddr(suite) -> [];
+t_getaddr(Config) when is_list(Config) ->
+ ?line {Name,FullName,IPStr,IP,_,IP_46_Str,IP46} =
+ ?config(test_host_ipv4_only, Config),
+ ?line {ok,IP} = inet:getaddr(list_to_atom(Name), inet),
+ ?line {ok,IP} = inet:getaddr(Name, inet),
+ ?line {ok,IP} = inet:getaddr(FullName, inet),
+ ?line {ok,IP} = inet:getaddr(IP, inet),
+ ?line {ok,IP} = inet:getaddr(IPStr, inet),
+ ?line {error,nxdomain} = inet:getaddr(IP_46_Str, inet),
+ ?line {error,eafnosupport} = inet:getaddr(IP46, inet),
+
+ ?line {DName, DFullName, DIPStr, DIP, _, _, _} = ?config(test_dummy_host, Config),
+ ?line {error,nxdomain} = inet:getaddr(DName, inet),
+ ?line {error,nxdomain} = inet:getaddr(DFullName, inet),
+ ?line {ok,DIP} = inet:getaddr(DIPStr, inet),
+ ?line {ok,DIP} = inet:getaddr(DIP, inet).
+
+t_getaddr_v6(doc) -> "Test the inet:getaddr/2 function.";
+t_getaddr_v6(suite) -> [];
+t_getaddr_v6(Config) when is_list(Config) ->
+ ?line {Name,FullName,IPStr,_IP,_,IP_46_Str,IP46} =
+ ?config(test_host_ipv4_only, Config),
+ case {inet:getaddr(IP_46_Str, inet6),inet:getaddr(Name, inet6)} of
+ {{ok,IP46},{ok,_}} ->
+ %% Since we suceeded in parsing an IPv6 address string and
+ %% look up the name, this computer fully supports IPv6.
+ ?line {ok,IP46} = inet:getaddr(IP46, inet6),
+ ?line {ok,IP46} = inet:getaddr(Name, inet6),
+ ?line {ok,IP46} = inet:getaddr(FullName, inet6),
+ ?line IP4toIP6 = inet:getaddr(IPStr, inet6),
+ ?line case IP4toIP6 of
+ {ok,IP46} -> % only native can do this
+ ?line true = lists:member(native,
+ inet_db:res_option(lookup));
+ {error,nxdomain} ->
+ ok
+ end,
+ ?line {Name6, FullName6, IPStr6, IP6, _} =
+ ?config(test_host_ipv6_only, Config),
+ ?line {ok,_} = inet:getaddr(list_to_atom(Name6), inet6),
+ ?line {ok,_} = inet:getaddr(Name6, inet6),
+ ?line {ok,_} = inet:getaddr(FullName6, inet6),
+ ?line {ok,IP6} = inet:getaddr(IP6, inet6),
+ ?line {ok,IP6} = inet:getaddr(IPStr6, inet6),
+
+ ?line {DName6, DFullName6, DIPStr6, DIP6, _} =
+ ?config(test_dummy_ipv6_host, Config),
+ ?line {error,nxdomain} = inet:getaddr(DName6, inet6),
+ ?line {error,nxdomain} = inet:getaddr(DFullName6, inet6),
+ ?line {ok,DIP6} = inet:getaddr(DIPStr6, inet6),
+ ?line {ok,DIP6} = inet:getaddr(DIP6, inet6),
+ ok;
+ {_,_} ->
+ {skip, "IPv6 is not supported on this host"}
+ end.
+
+ipv4_to_ipv6(doc) -> "Test if IPv4 address is converted to IPv6 address.";
+ipv4_to_ipv6(suite) -> [];
+ipv4_to_ipv6(Config) when is_list(Config) ->
+ %% Test what happens if an IPv4 address is looked up in an IPv6 context.
+ %% If the native resolver succeeds to look it up, an IPv4 compatible
+ %% address should be returned. If no IPv6 support on this host, an
+ %% error should beturned.
+ ?line {_Name,_FullName,IPStr,_IP,Aliases,IP_46_Str,IP_46} =
+ ?config(test_host_ipv4_only, Config),
+ ?line IP4to6Res =
+ case inet:getaddr(IPStr, inet6) of
+ {ok,IP_46} ->
+ io:format("IPv4->IPv6: success~n"),
+ true;
+ E = {error,nxdomain} ->
+ io:format("IPv4->IPv6: nxdomain~n"),
+ E;
+ E = {error,eafnosupport} ->
+ io:format("IPv6->IPv4: eafnosupport~n"),
+ E;
+ Other ->
+ ?line ?t:fail({ipv4_to_ipv6_lookup_failed,Other})
+ end,
+ ?line case {IP4to6Res,inet:gethostbyname(IPStr, inet6)} of
+ {true,{ok,HEnt}} ->
+ ?line true = lists:member(native, inet_db:res_option(lookup)),
+ ?line HEnt_ = HEnt#hostent{h_addrtype = inet6,
+ h_length = 16,
+ h_addr_list = [IP_46]},
+ ?line HEnt_ = HEnt,
+ ?line check_elems([{HEnt#hostent.h_name,[IP_46_Str,IPStr]},
+ {HEnt#hostent.h_aliases,[[],Aliases]}]);
+ {_,IP4to6Res} -> ok
+ end,
+ ok.
+
+host_and_addr(doc) -> ["Test looking up hosts and addresses. Use 'ypcat hosts' ",
+ "or the local eqivalent to find all hosts."];
+host_and_addr(suite) -> [];
+host_and_addr(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:minutes(5)),
+
+ ?line lists:foreach(fun try_host/1, get_hosts(Config)),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+try_host({Ip0, Host}) ->
+ ?line {ok,Ip} = inet:getaddr(Ip0, inet),
+ ?line {ok,{hostent, _, _, inet, _, Ips1}} = inet:gethostbyaddr(Ip),
+ ?line {ok,{hostent, _, _, inet, _, _Ips2}} = inet:gethostbyname(Host),
+ ?line true = lists:member(Ip, Ips1),
+ ok.
+
+%% Get all hosts from the system using 'ypcat hosts' or the local
+%% equvivalent.
+
+get_hosts(Config) ->
+ case os:type() of
+ {unix, _} ->
+ List = lists:map(fun(X) ->
+ atom_to_list(X)++" "
+ end, ?config(test_hosts, Config)),
+ Cmd = "ypmatch "++List++" hosts.byname",
+ HostFile = os:cmd(Cmd),
+ get_hosts(HostFile, [], [], []);
+ _ ->
+ ?config(hardcoded_hosts, Config)
+ end.
+
+get_ipv6_hosts(Config) ->
+ case os:type() of
+ {unix, _} ->
+ List = lists:map(fun(X) ->
+ atom_to_list(X)++" "
+ end, ?config(test_hosts, Config)),
+ Cmd = "ypmatch "++List++" ipnodes.byname",
+ HostFile = os:cmd(Cmd),
+ get_hosts(HostFile, [], [], []);
+ _ ->
+ ?config(hardcoded_ipv6_hosts, Config)
+ end.
+
+get_hosts([$\t|Rest], Cur, Ip, Result) when Ip /= [] ->
+ get_hosts(Rest, Cur, Ip, Result);
+get_hosts([$\t|Rest], Cur, _Ip, Result) ->
+ get_hosts(Rest, [], lists:reverse(Cur), Result);
+get_hosts([$\r|Rest], Cur, Ip, Result) ->
+ get_hosts(Rest, Cur, Ip, Result);
+get_hosts([$\n|Rest], Cur, Ip, Result) ->
+ [First|_] = string:tokens(lists:reverse(Cur), " "),
+ Ips = string:tokens(Ip, ","),
+ Hosts = [{I, First} || I <- Ips],
+ get_hosts(Rest, [], [], Hosts++Result);
+get_hosts([C|Rest], Cur, Ip, Result) ->
+ get_hosts(Rest, [C|Cur], Ip, Result);
+get_hosts([], _, _, Result) ->
+ Result.
+
+parse(suite) -> [parse_hosts];
+parse(doc) -> ["Test that parsing of the hosts file or equivalent works,",
+ "and that erroneous lines are skipped"].
+parse_hosts(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir,Config),
+ ?line HostFile = filename:join(DataDir, "hosts"),
+ ?line inet_parse:hosts(HostFile),
+ ?line HostFileErr1 = filename:join(DataDir, "hosts_err1"),
+ ?line inet_parse:hosts(HostFileErr1),
+ ?line Resolv = filename:join(DataDir,"resolv.conf"),
+ ?line inet_parse:resolv(Resolv),
+ ?line ResolvErr1 = filename:join(DataDir,"resolv.conf.err1"),
+ ?line inet_parse:resolv(ResolvErr1).
+
+t_gethostnative(suite) ->[];
+t_gethostnative(doc) ->[];
+t_gethostnative(Config) when is_list(Config) ->
+%% this will result in 26 bytes sent which causes problem in Windows
+%% if the port-program has not assured stdin to be read in BINARY mode
+%% OTP-2555
+ case os:type() of
+ vxworks ->
+ {skipped, "VxWorks has no native gethostbyname()"};
+ _ ->
+ ?line case inet_gethost_native:gethostbyname(
+ "a23456789012345678901234") of
+ {error,notfound} ->
+ ?line ok;
+ {error,no_data} ->
+ ?line ok
+ end
+ end.
+
+gethostnative_parallell(suite) ->
+ [];
+gethostnative_parallell(doc) ->
+ ["Check that the emulator survives crashes in gethost_native"];
+gethostnative_parallell(Config) when is_list(Config) ->
+ ?line {ok,Hostname} = inet:gethostname(),
+ ?line {ok,_} = inet:gethostbyname(Hostname),
+ case whereis(inet_gethost_native) of
+ Pid when is_pid(Pid) ->
+ ?line do_gethostnative_parallell();
+ _ ->
+ ?line {skipped, "Not running native gethostbyname"}
+ end.
+
+do_gethostnative_parallell() ->
+ ?line PA = filename:dirname(code:which(?MODULE)),
+ ?line {ok,Node} = ?t:start_node(gethost_parallell, slave,
+ [{args, "-pa " ++ PA}]),
+ ?line ok = rpc:call(Node, ?MODULE, parallell_gethost, []),
+ ?line receive after 10000 -> ok end,
+ ?line pong = net_adm:ping(Node),
+ ?line ?t:stop_node(Node),
+ ok.
+
+parallell_gethost() ->
+ {ok,Hostname} = inet:gethostname(),
+ process_flag(trap_exit,true),
+ parallell_gethost_loop(10, Hostname).
+
+parallell_gethost_loop(0, _) -> ok;
+parallell_gethost_loop(N, Hostname) ->
+ case whereis(inet_gethost_native) of
+ Pid when is_pid(Pid) ->
+ true = exit(Pid,kill);
+ _ ->
+ ok
+ end,
+
+ L = spawn_gethosters(Hostname, 10),
+ release_gethosters(L),
+ collect_gethosters(10),
+ parallell_gethost_loop(N-1, Hostname).
+
+spawn_gethosters(_, 0) ->
+ [];
+spawn_gethosters(Hostname, N) ->
+ Collector = self(),
+ [spawn(fun() ->
+ receive
+ go ->
+ case (catch inet:gethostbyname(Hostname)) of
+ {ok,_} ->
+ Collector ! ok;
+ Else ->
+ Collector ! {error,Else}
+ end
+ end
+ end) |
+ spawn_gethosters(Hostname, N-1)].
+
+release_gethosters([]) ->
+ ok;
+release_gethosters([H|T]) ->
+ H ! go,
+ release_gethosters(T).
+
+collect_gethosters(0) ->
+ ok;
+collect_gethosters(N) ->
+ receive
+ ok ->
+ collect_gethosters(N-1);
+ Else ->
+ {failed, {unexpected, Else}}
+ after 2000 ->
+ {failed, {missing, N}}
+ end.
+
+kill_gethost() ->
+ kill_gethost(20).
+
+kill_gethost(0) ->
+ ok;
+kill_gethost(N) ->
+ put(kill_gethost_n,N),
+ Pid = wait_for_gethost(10),
+ true = exit(Pid,kill),
+ wait_for_dead_gethost(10),
+ kill_gethost(N-1).
+
+wait_for_dead_gethost(0) ->
+ exit({not_dead,inet_gethost_native});
+wait_for_dead_gethost(N) ->
+ case whereis(inet_gethost_native) of
+ Pid when is_pid(Pid) ->
+ receive after 1000 ->
+ ok
+ end,
+ wait_for_dead_gethost(N-1);
+ undefined ->
+ ok
+ end.
+
+wait_for_gethost(0) ->
+ exit(gethost_not_found);
+wait_for_gethost(N) ->
+ {ok,Hostname} = inet:gethostname(),
+ case (catch inet:gethostbyname(Hostname)) of
+ {ok,_} ->
+ ok;
+ Otherwise ->
+ %% This is what I call an exit tuple :)
+ exit({inet,gethostbyname, returned, Otherwise, 'when',
+ 'N','=',N,'and','hostname','=',Hostname,'and',
+ kill_gethost_n,'=',get(kill_gethost_n)})
+ end,
+ case whereis(inet_gethost_native) of
+ Pid when is_pid(Pid) ->
+ Pid;
+ _ ->
+ receive
+ after 1000 ->
+ ok
+ end,
+ wait_for_gethost(N-1)
+ end.
+
+cname_loop(suite) ->
+ [];
+cname_loop(doc) ->
+ ["Check that the resolver handles a CNAME loop"];
+cname_loop(Config) when is_list(Config) ->
+ %% getbyname (hostent_by_domain)
+ ?line ok = inet_db:add_rr("mydomain.com", in, ?S_CNAME, ttl, "mydomain.com"),
+ ?line {error,nxdomain} = inet_db:getbyname("mydomain.com", ?S_A),
+ ?line ok = inet_db:del_rr("mydomain.com", in, ?S_CNAME, "mydomain.com"),
+ %% res_hostent_by_domain
+ RR = #dns_rr{domain = "mydomain.com",
+ class = in,
+ type = ?S_CNAME,
+ data = "mydomain.com"},
+ Rec = #dns_rec{anlist = [RR]},
+ ?line {error,nxdomain} = inet_db:res_hostent_by_domain("mydomain.com", ?S_A, Rec),
+ ok.
+
+
+
+%% These must be run in the whole suite since they need
+%% the host list and require inet_gethost_native to be started.
+%%
+-record(gethostnative_control, {control_seq,
+ control_interval=100,
+ lookup_delay=10,
+ lookup_count=300,
+ lookup_processes=20}).
+
+gethostnative_soft_restart(suite) ->
+ [];
+gethostnative_soft_restart(doc) ->
+ ["Check that no name lookups fails during soft restart "
+ "of inet_gethost_native"];
+gethostnative_soft_restart(Config) when is_list(Config) ->
+ ?line gethostnative_control(Config,
+ #gethostnative_control{
+ control_seq=[soft_restart]}).
+
+gethostnative_debug_level(suite) ->
+ [];
+gethostnative_debug_level(doc) ->
+ ["Check that no name lookups fails during debug level change "
+ "of inet_gethost_native"];
+gethostnative_debug_level(Config) when is_list(Config) ->
+ ?line gethostnative_control(Config,
+ #gethostnative_control{
+ control_seq=[{debug_level,1},
+ {debug_level,0}]}).
+
+gethostnative_control(Config, Optrec) ->
+ ?line case inet_db:res_option(lookup) of
+ [native] ->
+ case whereis(inet_gethost_native) of
+ Pid when is_pid(Pid) ->
+ ?line gethostnative_control_1(Config, Optrec);
+ _ ->
+ ?line {skipped, "Not running native gethostbyname"}
+ end;
+ _ ->
+ ?line {skipped, "Native not only lookup metod"}
+ end.
+
+gethostnative_control_1(Config,
+ #gethostnative_control{
+ control_seq=Seq,
+ control_interval=Interval,
+ lookup_delay=Delay,
+ lookup_count=Cnt,
+ lookup_processes=N}) ->
+ ?line {ok, Hostname} = inet:gethostname(),
+ ?line {ok, _} = inet:gethostbyname(Hostname),
+ ?line Hosts =
+ [Hostname|[H || {_,H} <- get_hosts(Config)]
+ ++[H++D || H <- ["www.","www1.","www2.",""],
+ D <- ["erlang.org","erlang.se"]]
+ ++[H++"cslab.ericsson.net" || H <- ["morgoth.","hades.","styx."]]],
+ %% Spawn some processes to do parallel lookups while
+ %% I repeatedly do inet_gethost_native:control/1.
+ ?line TrapExit = process_flag(trap_exit, true),
+ ?line gethostnative_control_2([undefined], Interval, Delay, Cnt, N, Hosts),
+ ?line test_server:format(
+ "First intermission: now starting control sequence ~w\n",
+ [Seq]),
+ ?line erlang:display(first_intermission),
+ ?line gethostnative_control_2(Seq, Interval, Delay, Cnt, N, Hosts),
+ ?line erlang:display(second_intermission),
+ ?line test_server:format(
+ "Second intermission: now stopping control sequence ~w\n",
+ [Seq]),
+ ?line gethostnative_control_2([undefined], Interval, Delay, Cnt, N, Hosts),
+ ?line true = process_flag(trap_exit, TrapExit),
+ ?line ok.
+
+gethostnative_control_2(Seq, Interval, Delay, Cnt, N, Hosts) ->
+ ?line Tag = make_ref(),
+ ?line Parent = self(),
+ ?line Lookupers =
+ [spawn_link(
+ fun () ->
+ random:seed(),
+ lookup_loop(Hosts, Delay, Tag, Parent, Cnt, Hosts)
+ end)
+ || _ <- lists:seq(1, N)],
+ control_loop(Seq, Interval, Tag, Lookupers, Seq),
+ gethostnative_control_3(Tag, ok).
+
+gethostnative_control_3(Tag, Reason) ->
+ receive
+ {Tag,Error} ->
+ ?line gethostnative_control_3(Tag, Error)
+ after 0 ->
+ Reason
+ end.
+
+control_loop([], _Interval, _Tag, [], _Seq) ->
+ ok;
+control_loop([], Interval, Tag, Lookupers, Seq) ->
+ control_loop(Seq, Interval, Tag, Lookupers, Seq);
+control_loop([Op|Ops], Interval, Tag, Lookupers, Seq) ->
+ control_loop(Ops, Interval, Tag,
+ control_loop_1(Op, Interval, Tag, Lookupers),
+ Seq).
+
+control_loop_1(Op, Interval, Tag, Lookupers) ->
+ ?line
+ receive
+ {'EXIT',Pid,Reason} ->
+ ?line case Reason of
+ Tag -> % Done
+ ?line control_loop_1
+ (Op, Interval, Tag,
+ lists:delete(Pid, Lookupers));
+ _ ->
+ ?line io:format("Lookuper ~p died: ~p",
+ [Pid,Reason]),
+ ?line test_server:fail("Lookuper died")
+ end
+ after Interval ->
+ ?line if Op =/= undefined ->
+ ?line ok = inet_gethost_native:control(Op);
+ true ->
+ ?line ok
+ end,
+ ?line Lookupers
+ end.
+
+lookup_loop(_, _Delay, Tag, _Parent, 0, _Hosts) ->
+ exit(Tag);
+lookup_loop([], Delay, Tag, Parent, Cnt, Hosts) ->
+ lookup_loop(Hosts, Delay, Tag, Parent, Cnt, Hosts);
+lookup_loop([H|Hs], Delay, Tag, Parent, Cnt, Hosts) ->
+ case inet:gethostbyname(H) of
+ {ok,_Hent} -> ok;
+ {error,nxdomain} -> ok;
+ Error ->
+ ?line io:format("Name lookup error for ~p for ~p: ~p",
+ [self(),H,Error]),
+ Parent ! {Tag,Error}
+ end,
+ receive
+ after random:uniform(Delay) ->
+ lookup_loop(Hs, Delay, Tag, Parent, Cnt-1, Hosts)
+ end.
+
+
+
+getif(suite) ->
+ [];
+getif(doc) ->
+ ["Tests basic functionality of getiflist, getif, and ifget"];
+getif(Config) when is_list(Config) ->
+ ?line {ok,Hostname} = inet:gethostname(),
+ ?line {ok,Address} = inet:getaddr(Hostname, inet),
+ ?line {ok,Loopback} = inet:getaddr("localhost", inet),
+ ?line {ok,Interfaces} = inet:getiflist(),
+ ?line Addresses =
+ lists:sort(
+ lists:foldl(
+ fun (I, Acc) ->
+ case inet:ifget(I, [addr]) of
+ {ok,[{addr,A}]} -> [A|Acc];
+ {ok,[]} -> Acc
+ end
+ end, [], Interfaces)),
+ ?line {ok,Getif} = inet:getif(),
+ ?line Addresses = lists:sort([A || {A,_,_} <- Getif]),
+ ?line true = ip_member(Address, Addresses),
+ ?line true = ip_member(Loopback, Addresses),
+ ?line ok.
+
+%% Works just like lists:member/2, except that any {127,_,_,_} tuple
+%% matches any other {127,_,_,_}. We do this to handle Linux systems
+%% that use (for instance) 127.0.1.1 as the IP address for the hostname.
+
+ip_member({127,_,_,_}, [{127,_,_,_}|_]) -> true;
+ip_member(K, [K|_]) -> true;
+ip_member(K, [_|T]) -> ip_member(K, T);
+ip_member(_, []) -> false.