diff options
Diffstat (limited to 'lib')
26 files changed, 986 insertions, 369 deletions
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index de41178a17..3a8011e28b 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2007</year><year>2009</year> + <year>2007</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -13,12 +13,12 @@ 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. - + </legalnotice> <title>gen_sctp</title> @@ -170,10 +170,19 @@ <p>Establishes a new association for the socket <c>Socket</c>, with the peer (SCTP server socket) given by <c>Addr</c> and <c>Port</c>. The <c>Timeout</c>, - is expressed in milliseconds.</p> - <p>A socket can be associated with multiple peers. - <marker id="record-sctp_assoc_change"></marker> + is expressed in milliseconds. A socket can be associated with multiple peers.</p> + <p><b>WARNING:</b>Using a value of <c>Timeout</c> less than + the maximum time taken by the OS to establish an association (around 4.5 minutes + if the default values from RFC 4960 are used) can result in + inconsistent or incorrect return values. This is especially + relevant for associations sharing the same <c>Socket</c> + (i.e. source address and port) since the controlling process + blocks until <c>connect/*</c> returns. + <seealso marker="#connect_init/4">connect_init/*</seealso> + provides an alternative not subject to this limitation.</p> + + <p><marker id="record-sctp_assoc_change"></marker> The result of <c>connect/*</c> is an <c>#sctp_assoc_change{}</c> event which contains, in particular, the new <seealso marker="#type-assoc_id">Association ID:</seealso></p> @@ -233,6 +242,45 @@ </desc> </func> <func> + <name>connect_init(Socket, Addr, Port, Opts) -> ok | {error, posix()}</name> + <fsummary>Same as <c>connect_init(Socket, Addr, Port, Opts, infinity)</c>.</fsummary> + <desc> + <p>Same as <c>connect_init(Socket, Addr, Port, Opts, infinity)</c>.</p> + </desc> + </func> + <func> + <name>connect_init(Socket, Addr, Port, [Opt], Timeout) -> ok | {error, posix()}</name> + <fsummary>Initiate a new association for the socket <c>Socket</c>, with a peer (SCTP server socket)</fsummary> + <type> + <v>Socket = sctp_socket()</v> + <v>Addr = ip_address() | Host</v> + <v>Port = port_number()</v> + <v>Opt = sctp_option()</v> + <v>Timeout = timeout()</v> + <v>Host = atom() | string()</v> + </type> + <desc> + <p>Initiates a new association for the socket <c>Socket</c>, + with the peer (SCTP server socket) given by + <c>Addr</c> and <c>Port</c>.</p> + <p>The fundamental difference between this API + and <c>connect/*</c> is that the return value is that of the + underlying OS connect(2) system call. If <c>ok</c> is returned + then the result of the association establishement is received + by the calling process as + an <seealso marker="#record-sctp_assoc_change"> + #sctp_assoc_change{}</seealso> + event. The calling process must be prepared to receive this, or + poll for it using <c>recv/*</c> depending on the value of the + active option.</p> + <p>The parameters are as described + in <seealso marker="#connect/5">connect/*</seealso>, with the + exception of the <c>Timeout</c> value.</p> + <p>The timer associated with <c>Timeout</c> only supervises + IP resolution of <c>Addr</c></p> + </desc> + </func> + <func> <name>controlling_process(sctp_socket(), pid()) -> ok</name> <fsummary>Assign a new controlling process pid to the socket</fsummary> <desc> @@ -1058,6 +1106,65 @@ gen_sctp:close(S). </pre> <p></p> </item> + <item> + <p>A very simple Erlang SCTP Client which uses the + connect_init API.</p> + <pre> +-module(ex3). + +-export([client/4]). +-include_lib("kernel/include/inet.hrl"). +-include_lib("kernel/include/inet_sctp.hrl"). + +client(Peer1, Port1, Peer2, Port2) + when is_tuple(Peer1), is_integer(Port1), is_tuple(Peer2), is_integer(Port2) -> + {ok,S} = gen_sctp:open(), + SctpInitMsgOpt = {sctp_initmsg,#sctp_initmsg{num_ostreams=5}}, + ActiveOpt = {active, true}, + Opts = [SctpInitMsgOpt, ActiveOpt], + ok = gen_sctp:connect(S, Peer1, Port1, Opts), + ok = gen_sctp:connect(S, Peer2, Port2, Opts), + io:format("Connections initiated~n", []), + client_loop(S, Peer1, Port1, undefined, Peer2, Port2, undefined). + +client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2) -> + receive + {sctp, S, Peer1, Port1, {_Anc, SAC}} + when is_record(SAC, sctp_assoc_change), AssocId1 == undefined -> + io:format("Association 1 connect result: ~p. AssocId: ~p~n", + [SAC#sctp_assoc_change.state, + SAC#sctp_assoc_change.assoc_id]), + client_loop(S, Peer1, Port1, SAC#sctp_assoc_change.assoc_id, + Peer2, Port2, AssocId2); + + {sctp, S, Peer2, Port2, {_Anc, SAC}} + when is_record(SAC, sctp_assoc_change), AssocId2 == undefined -> + io:format("Association 2 connect result: ~p. AssocId: ~p~n", + [SAC#sctp_assoc_change.state, SAC#sctp_assoc_change.assoc_id]), + client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, + SAC#sctp_assoc_change.assoc_id); + + {sctp, S, Peer1, Port1, Data} -> + io:format("Association 1: received ~p~n", [Data]), + client_loop(S, Peer1, Port1, AssocId1, + Peer2, Port2, AssocId2); + + {sctp, S, Peer2, Port2, Data} -> + io:format("Association 2: received ~p~n", [Data]), + client_loop(S, Peer1, Port1, AssocId1, + Peer2, Port2, AssocId2); + + Other -> + io:format("Other ~p~n", [Other]), + client_loop(S, Peer1, Port1, AssocId1, + Peer2, Port2, AssocId2) + + after 5000 -> + ok + end. +</pre> + <p></p> + </item> </list> </section> diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 89d893f8c1..ffe58ae7a9 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -465,7 +465,8 @@ search([{Dir, File} | Tail]) -> build([]) -> []; build([Dir|Tail]) -> - Files = filter(objfile_extension(), Dir, file:list_dir(Dir)), + Files = filter(objfile_extension(), Dir, + erl_prim_loader:list_dir(Dir)), [decorate(Files, Dir) | build(Tail)]. decorate([], _) -> []; diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index fcd1d1564a..5a31e3976f 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. 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% %% @@ -27,7 +27,7 @@ -include("inet_sctp.hrl"). -export([open/0,open/1,open/2,close/1]). --export([listen/2,connect/4,connect/5]). +-export([listen/2,connect/4,connect/5,connect_init/4,connect_init/5]). -export([eof/2,abort/2]). -export([send/3,send/4,recv/1,recv/2]). -export([error_string/1]). @@ -80,7 +80,26 @@ listen(S, Flag) -> connect(S, Addr, Port, Opts) -> connect(S, Addr, Port, Opts, infinity). -connect(S, Addr, Port, Opts, Timeout) when is_port(S), is_list(Opts) -> +connect(S, Addr, Port, Opts, Timeout) -> + case do_connect(S, Addr, Port, Opts, Timeout, true) of + badarg -> + erlang:error(badarg, [S,Addr,Port,Opts,Timeout]); + Result -> + Result + end. + +connect_init(S, Addr, Port, Opts) -> + connect_init(S, Addr, Port, Opts, infinity). + +connect_init(S, Addr, Port, Opts, Timeout) -> + case do_connect(S, Addr, Port, Opts, Timeout, false) of + badarg -> + erlang:error(badarg, [S,Addr,Port,Opts,Timeout]); + Result -> + Result + end. + +do_connect(S, Addr, Port, Opts, Timeout, ConnWait) when is_port(S), is_list(Opts) -> case inet_db:lookup_socket(S) of {ok,Mod} -> case Mod:getserv(Port) of @@ -89,21 +108,26 @@ connect(S, Addr, Port, Opts, Timeout) when is_port(S), is_list(Opts) -> Timer -> try Mod:getaddr(Addr, Timer) of {ok,IP} -> - Mod:connect(S, IP, Port, Opts, Timer); + ConnectTimer = if ConnWait == false -> + nowait; + true -> + Timer + end, + Mod:connect(S, IP, Port, Opts, ConnectTimer); Error -> Error after inet:stop_timer(Timer) end catch error:badarg -> - erlang:error(badarg, [S,Addr,Port,Opts,Timeout]) + badarg end; Error -> Error end; Error -> Error end; -connect(S, Addr, Port, Opts, Timeout) -> - erlang:error(badarg, [S,Addr,Port,Opts,Timeout]). +do_connect(_S, _Addr, _Port, _Opts, _Timeout, _ConnWait) -> + badarg. diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index 42eab67478..f289b8110d 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -96,14 +96,6 @@ load_hipe_modules() -> %% code:load_file/1) and the atom `no_native' on failure. load_native_code(Mod, Bin) when is_atom(Mod), is_binary(Bin) -> - erlang:system_flag(multi_scheduling, block), - try - load_native_code_nosmp(Mod, Bin) - after - erlang:system_flag(multi_scheduling, unblock) - end. - -load_native_code_nosmp(Mod, Bin) -> Architecture = erlang:system_info(hipe_architecture), try chunk_name(Architecture) of ChunkTag -> @@ -111,10 +103,15 @@ load_native_code_nosmp(Mod, Bin) -> case code:get_chunk(Bin, ChunkTag) of undefined -> no_native; NativeCode when is_binary(NativeCode) -> - OldReferencesToPatch = patch_to_emu_step1(Mod), - case load_module(Mod, NativeCode, Bin, OldReferencesToPatch) of - bad_crc -> no_native; - Result -> Result + erlang:system_flag(multi_scheduling, block), + try + OldReferencesToPatch = patch_to_emu_step1(Mod), + case load_module(Mod, NativeCode, Bin, OldReferencesToPatch) of + bad_crc -> no_native; + Result -> Result + end + after + erlang:system_flag(multi_scheduling, unblock) end end catch @@ -128,17 +125,18 @@ load_native_code_nosmp(Mod, Bin) -> -spec post_beam_load(atom()) -> 'ok'. post_beam_load(Mod) when is_atom(Mod) -> - erlang:system_flag(multi_scheduling, block), - try - post_beam_load_nosmp(Mod) - after - erlang:system_flag(multi_scheduling, unblock) - end. - -post_beam_load_nosmp(Mod) -> Architecture = erlang:system_info(hipe_architecture), - try chunk_name(Architecture) of _ChunkTag -> patch_to_emu(Mod) - catch _:_ -> ok + try chunk_name(Architecture) of + _ChunkTag -> + erlang:system_flag(multi_scheduling, block), + try + patch_to_emu(Mod) + after + erlang:system_flag(multi_scheduling, unblock) + end + catch + _:_ -> + ok end. %%======================================================================== diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index b86aa1839e..eb503235d8 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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). @@ -45,6 +45,7 @@ %% resolve -export([gethostbyname/1, gethostbyname/2, gethostbyname/3, gethostbyname_tm/3]). +-export([gethostbyname_string/2, gethostbyname_self/2]). -export([gethostbyaddr/1, gethostbyaddr/2, gethostbyaddr_tm/2]). @@ -411,7 +412,17 @@ gethostbyname(Name,Family,Timeout) -> Res. gethostbyname_tm(Name,Family,Timer) -> - gethostbyname_tm(Name,Family,Timer,inet_db:res_option(lookup)). + Opts0 = inet_db:res_option(lookup), + Opts = + case (lists:member(native, Opts0) orelse + lists:member(string, Opts0) orelse + lists:member(nostring, Opts0)) of + true -> + Opts0; + false -> + [string|Opts0] + end, + gethostbyname_tm(Name, Family, Timer, Opts). -spec gethostbyaddr(Address :: string() | ip_address()) -> @@ -850,75 +861,61 @@ getaddrs_tm(Address, Family, Timer) -> %% %% gethostbyname with option search %% -gethostbyname_tm(Name, Type, Timer, [dns | Opts]) -> - Res = inet_res:gethostbyname_tm(Name, Type, Timer), - case Res of - {ok,_} -> Res; - {error,timeout} -> Res; - {error,formerr} -> {error,einval}; - {error,_} -> gethostbyname_tm(Name,Type,Timer,Opts) - end; -gethostbyname_tm(Name, Type, Timer, [file | Opts]) -> - case inet_hosts:gethostbyname(Name, Type) of - {error,formerr} -> {error,einval}; - {error,_} -> gethostbyname_tm(Name,Type,Timer,Opts); - Result -> Result - end; -gethostbyname_tm(Name, Type, Timer, [yp | Opts]) -> +gethostbyname_tm(Name, Type, Timer, [string|_]=Opts) -> + Result = gethostbyname_string(Name, Type), + gethostbyname_tm(Name, Type, Timer, Opts, Result); +gethostbyname_tm(Name, Type, Timer, [dns|_]=Opts) -> + Result = inet_res:gethostbyname_tm(Name, Type, Timer), + gethostbyname_tm(Name, Type, Timer, Opts, Result); +gethostbyname_tm(Name, Type, Timer, [file|_]=Opts) -> + Result = inet_hosts:gethostbyname(Name, Type), + gethostbyname_tm(Name, Type, Timer, Opts, Result); +gethostbyname_tm(Name, Type, Timer, [yp|_]=Opts) -> gethostbyname_tm_native(Name, Type, Timer, Opts); -gethostbyname_tm(Name, Type, Timer, [nis | Opts]) -> +gethostbyname_tm(Name, Type, Timer, [nis|_]=Opts) -> gethostbyname_tm_native(Name, Type, Timer, Opts); -gethostbyname_tm(Name, Type, Timer, [nisplus | Opts]) -> +gethostbyname_tm(Name, Type, Timer, [nisplus|_]=Opts) -> gethostbyname_tm_native(Name, Type, Timer, Opts); -gethostbyname_tm(Name, Type, Timer, [wins | Opts]) -> +gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) -> gethostbyname_tm_native(Name, Type, Timer, Opts); -gethostbyname_tm(Name, Type, Timer, [native | Opts]) -> +gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) -> gethostbyname_tm_native(Name, Type, Timer, Opts); -gethostbyname_tm(_, _, _, [no_default|_]) -> - %% If the native resolver has failed, we should not bother - %% to try to be smarter and parse the IP address here. - {error,nxdomain}; -gethostbyname_tm(Name, Type, Timer, [_ | Opts]) -> +gethostbyname_tm(Name, Type, Timer, [_|_]=Opts) -> gethostbyname_tm(Name, Type, Timer, Opts); -%% Last resort - parse the hostname as address -gethostbyname_tm(Name, inet, _Timer, []) -> - case inet_parse:ipv4_address(Name) of - {ok,IP4} -> - {ok,make_hostent(Name, [IP4], [], inet)}; - _ -> - gethostbyname_self(Name) - end; -gethostbyname_tm(Name, inet6, _Timer, []) -> - case inet_parse:ipv6_address(Name) of - {ok,IP6} -> - {ok,make_hostent(Name, [IP6], [], inet6)}; - _ -> - %% Even if Name is a valid IPv4 address, we can't - %% assume it's correct to return it on a IPv6 - %% format ( {0,0,0,0,0,16#ffff,?u16(A,B),?u16(C,D)} ). - %% This host might not support IPv6. - gethostbyname_self(Name) +%% Make sure we always can look up our own hostname. +gethostbyname_tm(Name, Type, Timer, []) -> + Result = gethostbyname_self(Name, Type), + gethostbyname_tm(Name, Type, Timer, [], Result). + +gethostbyname_tm(Name, Type, Timer, Opts, Result) -> + case Result of + {ok,_} -> + Result; + {error,formerr} -> + {error,einval}; + {error,_} when Opts =:= [] -> + {error,nxdomain}; + {error,_} -> + gethostbyname_tm(Name, Type, Timer, tl(Opts)) end. gethostbyname_tm_native(Name, Type, Timer, Opts) -> %% Fixme: add (global) timeout to gethost_native - case inet_gethost_native:gethostbyname(Name, Type) of - {error,formerr} -> {error,einval}; - {error,timeout} -> {error,timeout}; - {error,_} -> gethostbyname_tm(Name, Type, Timer, Opts++[no_default]); - Result -> Result - end. + Result = inet_gethost_native:gethostbyname(Name, Type), + gethostbyname_tm(Name, Type, Timer, Opts, Result). -%% Make sure we always can look up our own hostname. -gethostbyname_self(Name) -> - Type = case inet_db:res_option(inet6) of - true -> inet6; - false -> inet - end, + + +gethostbyname_self(Name, Type) when is_atom(Name) -> + gethostbyname_self(atom_to_list(Name), Type); +gethostbyname_self(Name, Type) + when is_list(Name), Type =:= inet; + is_list(Name), Type =:= inet6 -> case inet_db:gethostname() of Name -> - {ok,make_hostent(Name, [translate_ip(loopback, Type)], - [], Type)}; + {ok,make_hostent(Name, + [translate_ip(loopback, Type)], + [], Type)}; Self -> case inet_db:res_option(domain) of "" -> {error,nxdomain}; @@ -931,7 +928,31 @@ gethostbyname_self(Name) -> _ -> {error,nxdomain} end end - end. + end; +gethostbyname_self(_, _) -> + {error,formerr}. + +gethostbyname_string(Name, Type) when is_atom(Name) -> + gethostbyname_string(atom_to_list(Name), Type); +gethostbyname_string(Name, Type) + when is_list(Name), Type =:= inet; + is_list(Name), Type =:= inet6 -> + case + case Type of + inet -> + inet_parse:ipv4_address(Name); + inet6 -> + %% XXX should we really translate IPv4 addresses here + %% even if we do not know if this host can do IPv6? + inet_parse:ipv6_address(Name) + end of + {ok,IP} -> + {ok,make_hostent(Name, [IP], [], Type)}; + {error,einval} -> + {error,nxdomain} + end; +gethostbyname_string(_, _) -> + {error,formerr}. make_hostent(Name, Addrs, Aliases, Type) -> #hostent{h_name = Name, diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl index b5317f72f5..311e6bc9f9 100644 --- a/lib/kernel/src/inet_config.erl +++ b/lib/kernel/src/inet_config.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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_config). @@ -130,21 +130,25 @@ init() -> {unix,_} -> %% The Etc variable enables us to run tests with other %% configuration files than the normal ones - Etc = case os:getenv("ERL_INET_ETC_DIR") of - false -> ?DEFAULT_ETC; - _EtcDir -> - _EtcDir - end, + Etc = + case os:getenv("ERL_INET_ETC_DIR") of + false -> + ?DEFAULT_ETC; + _EtcDir -> + _EtcDir + end, case inet_db:res_option(resolv_conf) of undefined -> - inet_db:set_resolv_conf(filename:join(Etc, - ?DEFAULT_RESOLV)); + inet_db:res_option( + resolv_conf_name, + filename:join(Etc, ?DEFAULT_RESOLV)); _ -> ok end, case inet_db:res_option(hosts_file) of undefined -> - inet_db:set_hosts_file(filename:join(Etc, - ?DEFAULT_HOSTS)); + inet_db:res_option( + hosts_file_name, + filename:join(Etc, ?DEFAULT_HOSTS)); _ -> ok end; _ -> ok diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl index 211847014f..a05b380855 100644 --- a/lib/kernel/src/inet_db.erl +++ b/lib/kernel/src/inet_db.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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% %% @@ -425,7 +425,9 @@ res_optname(usevc) -> res_usevc; res_optname(edns) -> res_edns; res_optname(udp_payload_size) -> res_udp_payload_size; res_optname(resolv_conf) -> res_resolv_conf; +res_optname(resolv_conf_name) -> res_resolv_conf; res_optname(hosts_file) -> res_hosts_file; +res_optname(hosts_file_name) -> res_hosts_file; res_optname(_) -> undefined. res_check_option(nameserver, NSs) -> %% Legacy @@ -458,9 +460,15 @@ res_check_option(udp_payload_size, S) when is_integer(S), S >= 512 -> true; res_check_option(resolv_conf, "") -> true; res_check_option(resolv_conf, F) -> res_check_option_absfile(F); +res_check_option(resolv_conf_name, "") -> true; +res_check_option(resolv_conf_name, F) -> + res_check_option_absfile(F); res_check_option(hosts_file, "") -> true; res_check_option(hosts_file, F) -> res_check_option_absfile(F); +res_check_option(hosts_file_name, "") -> true; +res_check_option(hosts_file_name, F) -> + res_check_option_absfile(F); res_check_option(_, _) -> false. res_check_option_absfile(F) -> @@ -503,7 +511,7 @@ res_update_hosts() -> res_update(res_hosts_file, res_hosts_file_tm, res_hosts_file_info, set_hosts_file_tm, fun set_hosts_file/1). -res_update(Tag, TagTm, TagInfo, CallTag, SetFun) -> +res_update(Tag, TagTm, TagInfo, TagSetTm, SetFun) -> case db_get(TagTm) of undefined -> ok; TM -> @@ -522,12 +530,12 @@ res_update(Tag, TagTm, TagInfo, CallTag, SetFun) -> atime = undefined}, case db_get(TagInfo) of Finfo -> - call({CallTag, Now}); + call({TagSetTm, Now}); _ -> SetFun(File) end; _ -> - call({CallTag, Now}), + call({TagSetTm, Now}), error end end; @@ -974,37 +982,55 @@ handle_call(Request, From, #state{db=Db}=State) -> {reply, error, State} end; + {res_set, hosts_file_name=Option, Fname} -> + handle_set_file( + Option, Fname, res_hosts_file_tm, res_hosts_file_info, + undefined, From, State); + {res_set, resolv_conf_name=Option, Fname} -> + handle_set_file( + Option, Fname, res_resolv_conf_tm, res_resolv_conf_info, + undefined, From, State); + {res_set, hosts_file=Option, Fname} -> - handle_set_file(Option, Fname, - res_hosts_file_tm, res_hosts_file_info, - fun (Bin) -> - case inet_parse:hosts(Fname, - {chars,Bin}) of - {ok,Opts} -> - [{load_hosts_file,Opts}]; - _ -> error - end - end, - From, State); + handle_set_file( + Option, Fname, res_hosts_file_tm, res_hosts_file_info, + fun (Bin) -> + case inet_parse:hosts( + Fname, {chars,Bin}) of + {ok,Opts} -> + [{load_hosts_file,Opts}]; + _ -> error + end + end, + From, State); %% {res_set, resolv_conf=Option, Fname} -> - handle_set_file(Option, Fname, - res_resolv_conf_tm, res_resolv_conf_info, - fun (Bin) -> - case inet_parse:resolv(Fname, - {chars,Bin}) of - {ok,Opts} -> - [del_ns, - clear_search, - clear_cache - |[Opt || - {T,_}=Opt <- Opts, - (T =:= nameserver orelse - T =:= search)]]; - _ -> error - end - end, - From, State); + handle_set_file( + Option, Fname, res_resolv_conf_tm, res_resolv_conf_info, + fun (Bin) -> + case inet_parse:resolv( + Fname, {chars,Bin}) of + {ok,Opts} -> + Search = + lists:foldl( + fun ({search,L}, _) -> + L; + ({domain,""}, S) -> + S; + ({domain,D}, _) -> + [D]; + (_, S) -> + S + end, [], Opts), + [del_ns, + clear_search, + clear_cache, + {search,Search} + |[Opt || {nameserver,_}=Opt <- Opts]]; + _ -> error + end + end, + From, State); %% {res_set, Opt, Value} -> case res_optname(Opt) of @@ -1156,6 +1182,12 @@ handle_set_file(Option, Fname, TagTm, TagInfo, ParseFun, From, ets:delete(Db, TagInfo), ets:delete(Db, TagTm), handle_set_file(ParseFun, <<>>, From, State); + true when ParseFun =:= undefined -> + File = filename:flatten(Fname), + ets:insert(Db, {res_optname(Option), File}), + ets:insert(Db, {TagInfo, undefined}), + ets:insert(Db, {TagTm, 0}), + {reply,ok,State}; true -> File = filename:flatten(Fname), ets:insert(Db, {res_optname(Option), File}), @@ -1178,7 +1210,8 @@ handle_set_file(Option, Fname, TagTm, TagInfo, ParseFun, From, handle_set_file(ParseFun, Bin, From, State) -> case ParseFun(Bin) of - error -> {reply,error,State}; + error -> + {reply,error,State}; Opts -> handle_rc_list(Opts, From, State) end. diff --git a/lib/kernel/src/inet_gethost_native.erl b/lib/kernel/src/inet_gethost_native.erl index abdbe2b8cf..fabe9bf8b3 100644 --- a/lib/kernel/src/inet_gethost_native.erl +++ b/lib/kernel/src/inet_gethost_native.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1998-2010. 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_gethost_native). @@ -443,19 +443,23 @@ gethostbyname(Name) -> gethostbyname(Name, inet). gethostbyname(Name, inet) when is_list(Name) -> - getit(?OP_GETHOSTBYNAME, ?PROTO_IPV4, Name); + getit(?OP_GETHOSTBYNAME, ?PROTO_IPV4, Name, Name); gethostbyname(Name, inet6) when is_list(Name) -> - getit(?OP_GETHOSTBYNAME, ?PROTO_IPV6, Name); + getit(?OP_GETHOSTBYNAME, ?PROTO_IPV6, Name, Name); gethostbyname(Name, Type) when is_atom(Name) -> gethostbyname(atom_to_list(Name), Type); gethostbyname(_, _) -> {error, formerr}. -gethostbyaddr({A,B,C,D}) when ?VALID_V4(A), ?VALID_V4(B), ?VALID_V4(C), ?VALID_V4(D) -> - getit(?OP_GETHOSTBYADDR, ?PROTO_IPV4, <<A,B,C,D>>); -gethostbyaddr({A,B,C,D,E,F,G,H}) when ?VALID_V6(A), ?VALID_V6(B), ?VALID_V6(C), ?VALID_V6(D), - ?VALID_V6(E), ?VALID_V6(F), ?VALID_V6(G), ?VALID_V6(H) -> - getit(?OP_GETHOSTBYADDR, ?PROTO_IPV6, <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16>>); +gethostbyaddr({A,B,C,D}=Addr) + when ?VALID_V4(A), ?VALID_V4(B), ?VALID_V4(C), ?VALID_V4(D) -> + getit(?OP_GETHOSTBYADDR, ?PROTO_IPV4, <<A,B,C,D>>, Addr); +gethostbyaddr({A,B,C,D,E,F,G,H}=Addr) + when ?VALID_V6(A), ?VALID_V6(B), ?VALID_V6(C), ?VALID_V6(D), + ?VALID_V6(E), ?VALID_V6(F), ?VALID_V6(G), ?VALID_V6(H) -> + getit + (?OP_GETHOSTBYADDR, ?PROTO_IPV6, + <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16>>, Addr); gethostbyaddr(Addr) when is_list(Addr) -> case inet_parse:address(Addr) of {ok, IP} -> gethostbyaddr(IP); @@ -466,30 +470,30 @@ gethostbyaddr(Addr) when is_atom(Addr) -> gethostbyaddr(_) -> {error, formerr}. control({debug_level, Level}) when is_integer(Level) -> - getit(?OP_CONTROL, ?SETOPT_DEBUG_LEVEL, <<Level:32>>); + getit(?OP_CONTROL, ?SETOPT_DEBUG_LEVEL, <<Level:32>>, undefined); control(soft_restart) -> - getit(restart_port); + getit(restart_port, undefined); control(_) -> {error, formerr}. -getit(Op, Proto, Data) -> - getit({Op, Proto, Data}). +getit(Op, Proto, Data, DefaultName) -> + getit({Op, Proto, Data}, DefaultName). -getit(Req) -> +getit(Req, DefaultName) -> Pid = ensure_started(), Ref = make_ref(), Pid ! {{self(),Ref}, Req}, receive {Ref, {ok,BinHostent}} -> - parse_address(BinHostent); - {Ref, Error} -> - Error + parse_address(BinHostent, DefaultName); + {Ref, Result} -> + Result after 5000 -> Ref2 = erlang:monitor(process,Pid), Res2 = receive {Ref, {ok,BinHostent}} -> - parse_address(BinHostent); - {Ref, Error} -> - Error; + parse_address(BinHostent, DefaultName); + {Ref, Result} -> + Result; {'DOWN', Ref2, process, Pid, Reason} -> {error, Reason} @@ -546,21 +550,23 @@ ensure_started() -> Pid end. -parse_address(BinHostent) -> +parse_address(BinHostent, DefaultName) -> case catch begin case BinHostent of <<?UNIT_ERROR, Errstring/binary>> -> {error, list_to_atom(listify(Errstring))}; <<?UNIT_IPV4, Naddr:32, T0/binary>> -> - {T1,Addresses} = pick_addresses_v4(Naddr, T0), - [Name | Names] = pick_names(T1), + {T1, Addresses} = pick_addresses_v4(Naddr, T0), + {Name, Names} = + expand_default_name(pick_names(T1), DefaultName), {ok, #hostent{h_addr_list = Addresses, h_addrtype = inet, h_aliases = Names, h_length = ?UNIT_IPV4, h_name = Name}}; <<?UNIT_IPV6, Naddr:32, T0/binary>> -> - {T1,Addresses} = pick_addresses_v6(Naddr, T0), - [Name | Names] = pick_names(T1), + {T1, Addresses} = pick_addresses_v6(Naddr, T0), + {Name, Names} = + expand_default_name(pick_names(T1), DefaultName), {ok, #hostent{h_addr_list = Addresses, h_addrtype = inet6, h_aliases = Names, h_length = ?UNIT_IPV6, h_name = Name}}; @@ -573,7 +579,15 @@ parse_address(BinHostent) -> Normal -> Normal end. - + +expand_default_name([], DefaultName) when is_list(DefaultName) -> + {DefaultName, []}; +expand_default_name([], DefaultName) when is_tuple(DefaultName) -> + {inet_parse:ntoa(DefaultName), []}; +expand_default_name([Name|Names], DefaultName) + when is_list(DefaultName); is_tuple(DefaultName) -> + {Name, Names}. + listify(Bin) -> N = byte_size(Bin) - 1, <<Bin2:N/binary, Ch>> = Bin, diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl index 62d44fb723..3bd5fa0958 100644 --- a/lib/kernel/src/inet_parse.erl +++ b/lib/kernel/src/inet_parse.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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_parse). @@ -34,6 +34,7 @@ -export([nsswitch_conf/1, nsswitch_conf/2]). -export([ipv4_address/1, ipv6_address/1]). +-export([ipv4strict_address/1, ipv6strict_address/1]). -export([address/1]). -export([visible_string/1, domain/1]). -export([ntoa/1, dots/1]). @@ -456,17 +457,15 @@ is_dom2(_) -> %% -%% Test ipv4 address or ipv6 address +%% Parse ipv4 address or ipv6 address %% Return {ok, Address} | {error, Reason} %% address(Cs) when is_list(Cs) -> case ipv4_address(Cs) of - {ok,IP} -> {ok,IP}; + {ok,IP} -> + {ok,IP}; _ -> - case ipv6_address(Cs) of - {ok, IP} -> {ok, IP}; - Error -> Error - end + ipv6strict_address(Cs) end; address(_) -> {error, einval}. @@ -477,49 +476,145 @@ address(_) -> %% d1.d2.d4 %% d1.d4 %% d4 +%% Any d may be octal, hexadecimal or decimal by C language standards. +%% d4 fills all LSB bytes. This is legacy behaviour from Solaris +%% and FreeBSD. And partly Linux that behave the same except +%% it does not accept hexadecimal. %% %% Return {ok, IP} | {error, einval} %% ipv4_address(Cs) -> - case catch ipv4_addr(Cs) of - {'EXIT',_} -> {error,einval}; - Addr -> {ok,Addr} + try ipv4_addr(Cs) of + Addr -> + {ok,Addr} + catch + error:badarg -> + {error,einval} end. -ipv4_addr(Cs) -> - ipv4_addr(d3(Cs), []). +ipv4_addr(Cs) -> + case ipv4_addr(Cs, []) of + [D] when D < (1 bsl 32) -> + <<D1,D2,D3,D4>> = <<D:32>>, + {D1,D2,D3,D4}; + [D,D1] when D < (1 bsl 24), D1 < 256 -> + <<D2,D3,D4>> = <<D:24>>, + {D1,D2,D3,D4}; + [D,D2,D1] when D < (1 bsl 16), (D2 bor D1) < 256 -> + <<D3,D4>> = <<D:16>>, + {D1,D2,D3,D4}; + [D4,D3,D2,D1] when (D4 bor D3 bor D2 bor D1) < 256 -> + {D1,D2,D3,D4}; + _ -> + erlang:error(badarg) + end. -ipv4_addr({Cs0,[]}, A) when length(A) =< 3 -> - case [tod(Cs0)|A] of - [D4,D3,D2,D1] -> +ipv4_addr([_|_], [_,_,_,_]) -> + %% Early bailout for extra characters + erlang:error(badarg); +ipv4_addr("0x"++Cs, Ds) -> + ipv4_addr(strip0(Cs), Ds, [], 16, 8); +ipv4_addr("0X"++Cs, Ds) -> + ipv4_addr(strip0(Cs), Ds, [], 16, 8); +ipv4_addr("0"++Cs, Ds) -> + ipv4_addr(strip0(Cs), Ds, [$0], 8, 11); +ipv4_addr(Cs, Ds) when is_list(Cs) -> + ipv4_addr(Cs, Ds, [], 10, 10). + +ipv4_addr(Cs0, Ds, Rs, Base, N) -> + case ipv4_field(Cs0, N, Rs, Base) of + {D,""} -> + [D|Ds]; + {D,[$.|[_|_]=Cs]} -> + ipv4_addr(Cs, [D|Ds]); + {_,_} -> + erlang:error(badarg) + end. + +strip0("0"++Cs) -> + strip0(Cs); +strip0(Cs) when is_list(Cs) -> + Cs. + + +%% +%% Parse IPv4 strict dotted decimal address, no leading zeros: +%% d1.d2.d3.d4 +%% +%% Return {ok, IP} | {error, einval} +%% +ipv4strict_address(Cs) -> + try ipv4strict_addr(Cs) of + Addr -> + {ok,Addr} + catch + error:badarg -> + {error,einval} + end. + +ipv4strict_addr(Cs) -> + case ipv4strict_addr(Cs, []) of + [D4,D3,D2,D1] when (D4 bor D3 bor D2 bor D1) < 256 -> {D1,D2,D3,D4}; - [D4,D2,D1] -> - {D1,D2,0,D4}; - [D4,D1] -> - {D1,0,0,D4}; - [D4] -> - {0,0,0,D4} - end; -ipv4_addr({Cs0,"."++Cs1}, A) when length(A) =< 2 -> - ipv4_addr(d3(Cs1), [tod(Cs0)|A]). + _ -> + erlang:error(badarg) + end. + +ipv4strict_addr([_|_], [_,_,_,_]) -> + %% Early bailout for extra characters + erlang:error(badarg); +ipv4strict_addr("0", Ds) -> + [0|Ds]; +ipv4strict_addr("0."++Cs, Ds) -> + ipv4strict_addr(Cs, [0|Ds]); +ipv4strict_addr(Cs0, Ds) when is_list(Cs0) -> + case ipv4_field(Cs0, 3, [], 10) of + {D,""} -> + [D|Ds]; + {D,[$.|[_|_]=Cs]} -> + ipv4strict_addr(Cs, [D|Ds]); + {_,_} -> + erlang:error(badarg) + end. + -d3(Cs) -> d3(Cs, []). -d3([C|Cs], R) when C >= $0, C =< $9, length(R) =< 2 -> - d3(Cs, [C|R]); -d3(Cs, [_|_]=R) -> - {lists:reverse(R),Cs}. +ipv4_field("", _, Rs, Base) -> + {ipv4_field(Rs, Base),""}; +ipv4_field("."++_=Cs, _, Rs, Base) -> + {ipv4_field(Rs, Base),Cs}; +ipv4_field("0"++_, _, [], _) -> + erlang:error(badarg); +ipv4_field([C|Cs], N, Rs, Base) when N > 0 -> + ipv4_field(Cs, N-1, [C|Rs], Base); +ipv4_field(Cs, _, _, _) when is_list(Cs) -> + erlang:error(badarg). + +ipv4_field(Rs, Base) -> + V = erlang:list_to_integer(lists:reverse(Rs), Base), + if V < 0 -> + erlang:error(badarg); + true -> + V + end. -tod(Cs) -> - case erlang:list_to_integer(Cs) of - D when D >= 0, D =< 255 -> - D; + + +%% +%% Forgiving IPv6 address +%% +%% Accepts IPv4 address and returns it as a IPv4 compatible IPv6 address +%% +ipv6_address(Cs) -> + case ipv4_address(Cs) of + {ok,{D1,D2,D3,D4}} -> + {ok,{0,0,0,0,0,16#ffff,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4}}; _ -> - erlang:error(badarg, [Cs]) + ipv6strict_address(Cs) end. %% -%% Parse IPv6 address: +%% Parse IPv6 address according to RFC 4291: %% x1:x2:x3:x4:x5:x6:x7:x8 %% x1:x2::x7:x8 %% ::x7:x8 @@ -530,77 +625,89 @@ tod(Cs) -> %% ::x5:x6:d7a.d7b.d8a.d8b %% x1:x2::d7a.d7b.d8a.d8b %% ::d7a.d7b.d8a.d8b +%% etc %% %% Return {ok, IP} | {error, einval} %% -ipv6_address(Cs) -> - case catch ipv6_addr(Cs) of - {'EXIT',_} -> {error,einval}; - Addr -> {ok,Addr} +ipv6strict_address(Cs) -> + try ipv6_addr(Cs) of + Addr -> + {ok,Addr} + catch + error:badarg -> + {error,einval} end. ipv6_addr("::") -> - ipv6_addr_done([], []); + ipv6_addr_done([], [], 0); ipv6_addr("::"++Cs) -> - ipv6_addr(x4(Cs), [], []); + ipv6_addr(hex(Cs), [], [], 0); ipv6_addr(Cs) -> - ipv6_addr(x4(Cs), []). + ipv6_addr(hex(Cs), [], 0). %% Before "::" -ipv6_addr({Cs0,[]}, A) when length(A) =:= 7 -> - ipv6_addr_done([tox(Cs0)|A]); -ipv6_addr({Cs0,"::"}, A) when length(A) =< 6 -> - ipv6_addr_done([tox(Cs0)|A], []); -ipv6_addr({Cs0,"::"++Cs1}, A) when length(A) =< 5 -> - ipv6_addr(x4(Cs1), [tox(Cs0)|A], []); -ipv6_addr({Cs0,":"++Cs1}, A) when length(A) =< 6 -> - ipv6_addr(x4(Cs1), [tox(Cs0)|A]); -ipv6_addr({Cs0,"."++Cs1}, A) when length(A) =:= 6 -> - ipv6_addr(d3(Cs1), A, [], [tod(Cs0)]). +ipv6_addr({Cs0,[]}, A, N) when N == 7 -> + ipv6_addr_done([hex_to_int(Cs0)|A]); +ipv6_addr({Cs0,"::"}, A, N) when N =< 6 -> + ipv6_addr_done([hex_to_int(Cs0)|A], [], N+1); +ipv6_addr({Cs0,"::"++Cs1}, A, N) when N =< 5 -> + ipv6_addr(hex(Cs1), [hex_to_int(Cs0)|A], [], N+1); +ipv6_addr({Cs0,":"++Cs1}, A, N) when N =< 6 -> + ipv6_addr(hex(Cs1), [hex_to_int(Cs0)|A], N+1); +ipv6_addr({Cs0,"."++_=Cs1}, A, N) when N == 6 -> + ipv6_addr_done(A, [], N, ipv4strict_addr(Cs0++Cs1)); +ipv6_addr(_, _, _) -> + erlang:error(badarg). %% After "::" -ipv6_addr({Cs0,[]}, A, B) when length(A)+length(B) =< 6 -> - ipv6_addr_done(A, [tox(Cs0)|B]); -ipv6_addr({Cs0,":"++Cs1}, A, B) when length(A)+length(B) =< 5 -> - ipv6_addr(x4(Cs1), A, [tox(Cs0)|B]); -ipv6_addr({Cs0,"."++Cs1}, A, B) when length(A)+length(B) =< 5 -> - ipv6_addr(x4(Cs1), A, B, [tod(Cs0)]). +ipv6_addr({Cs0,[]}, A, B, N) when N =< 6 -> + ipv6_addr_done(A, [hex_to_int(Cs0)|B], N+1); +ipv6_addr({Cs0,":"++Cs1}, A, B, N) when N =< 5 -> + ipv6_addr(hex(Cs1), A, [hex_to_int(Cs0)|B], N+1); +ipv6_addr({Cs0,"."++_=Cs1}, A, B, N) when N =< 5 -> + ipv6_addr_done(A, B, N, ipv4strict_addr(Cs0++Cs1)); +ipv6_addr(_, _, _, _) -> + erlang:error(badarg). -%% After "." -ipv6_addr({Cs0,[]}, A, B, C) when length(C) =:= 3 -> - ipv6_addr_done(A, B, [tod(Cs0)|C]); -ipv6_addr({Cs0,"."++Cs1}, A, B, C) when length(C) =< 2 -> - ipv6_addr(d3(Cs1), A, B, [tod(Cs0)|C]). +ipv6_addr_done(Ar, Br, N, {D1,D2,D3,D4}) -> + ipv6_addr_done(Ar, [((D3 bsl 8) bor D4),((D1 bsl 8) bor D2)|Br], N+2). -ipv6_addr_done(Ar, Br, [D4,D3,D2,D1]) -> - ipv6_addr_done(Ar, [((D3 bsl 8) bor D4),((D1 bsl 8) bor D2)|Br]). - -ipv6_addr_done(Ar, Br) -> - ipv6_addr_done(Br++dup(8-length(Ar)-length(Br), 0, Ar)). +ipv6_addr_done(Ar, Br, N) -> + ipv6_addr_done(Br++dup(8-N, 0, Ar)). ipv6_addr_done(Ar) -> list_to_tuple(lists:reverse(Ar)). -x4(Cs) -> x4(Cs, []). - -x4([C|Cs], R) when C >= $0, C =< $9, length(R) =< 3 -> - x4(Cs, [C|R]); -x4([C|Cs], R) when C >= $a, C =< $f, length(R) =< 3 -> - x4(Cs, [C|R]); -x4([C|Cs], R) when C >= $A, C =< $F, length(R) =< 3 -> - x4(Cs, [C|R]); -x4(Cs, [_|_]=R) -> - {lists:reverse(R),Cs}. - -tox(Cs) -> - erlang:list_to_integer(Cs, 16). +%% Collect Hex digits +hex(Cs) -> hex(Cs, []). +%% +hex([C|Cs], R) when C >= $0, C =< $9 -> + hex(Cs, [C|R]); +hex([C|Cs], R) when C >= $a, C =< $f -> + hex(Cs, [C|R]); +hex([C|Cs], R) when C >= $A, C =< $F -> + hex(Cs, [C|R]); +hex(Cs, [_|_]=R) when is_list(Cs) -> + {lists:reverse(R),Cs}; +hex(_, _) -> + erlang:error(badarg). + +%% Hex string to integer +hex_to_int(Cs0) -> + case strip0(Cs0) of + Cs when length(Cs) =< 4 -> + erlang:list_to_integer("0"++Cs, 16); + _ -> + erlang:error(badarg) + end. +%% Dup onto head of existing list dup(0, _, L) -> L; dup(N, E, L) when is_integer(N), N >= 1 -> - dup(N-1, E, [E|L]); -dup(N, E, L) -> - erlang:error(badarg, [N,E,L]). + dup(N-1, E, [E|L]). + + %% Convert IPv4 adress to ascii %% Convert IPv6 / IPV4 adress to ascii (plain format) @@ -674,7 +781,7 @@ separate(_E, [H], R) -> lists:reverse(R, [H]). %% convert to A.B decimal form -dig_to_dec(0) -> [$0,$.,$0]; +dig_to_dec(0) -> "0.0"; dig_to_dec(X) -> integer_to_list((X bsr 8) band 16#ff) ++ "." ++ integer_to_list(X band 16#ff). diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl index 30c0e85dd9..795bf83807 100644 --- a/lib/kernel/src/inet_sctp.erl +++ b/lib/kernel/src/inet_sctp.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. 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% %% %% SCTP protocol contribution by Leonid Timochouk and Serge Aleynikov. @@ -64,16 +64,22 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +%% A non-blocking connect is implemented when the initial call is to +%% gen_sctp:connect_init which passes the value nowait as the Timer connect(S, Addr, Port, Opts, Timer) -> case prim_inet:chgopts(S, Opts) of ok -> case prim_inet:getopt(S, active) of {ok,Active} -> - Timeout = inet:timeout(Timer), + Timeout = if Timer =:= nowait -> + infinity; %% don't start driver timer in inet_drv + true -> + inet:timeout(Timer) + end, case prim_inet:connect(S, Addr, Port, Timeout) of - ok -> + ok when Timer =/= nowait -> connect_get_assoc(S, Addr, Port, Active, Timer); - Err1 -> Err1 + OkOrErr1 -> OkOrErr1 end; Err2 -> Err2 end; @@ -89,10 +95,10 @@ connect(S, Addr, Port, Opts, Timer) -> %% connect_get_assoc/5 below mistakes it for an invalid response %% for a socket in {active,false} or {active,once} modes. %% -%% In {active,true} mode it probably gets right, but it is -%% a blocking connect that is implemented even for {active,true}, -%% and that may be a shortcoming. A non-blocking connect -%% would be nice to have. +%% In {active,true} mode the window of time for the race is smaller, +%% but it is possible and also it is a blocking connect that is +%% implemented even for {active,true}, and that may be a +%% shortcoming. connect_get_assoc(S, Addr, Port, false, Timer) -> case recv(S, inet:timeout(Timer)) of diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 8e1e3d5390..37b9200942 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -26,7 +26,7 @@ delete/1, purge/1, soft_purge/1, is_loaded/1, all_loaded/1, load_binary/1, dir_req/1, object_code/1, set_path_file/1, sticky_dir/1, pa_pz_option/1, add_del_path/1, - dir_disappeared/1, ext_mod_dep/1, + dir_disappeared/1, ext_mod_dep/1, clash/1, load_cached/1, start_node_with_cache/1, add_and_rehash/1, where_is_file_cached/1, where_is_file_no_cache/1, purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1, @@ -48,7 +48,7 @@ all(suite) -> delete, purge, soft_purge, is_loaded, all_loaded, load_binary, dir_req, object_code, set_path_file, pa_pz_option, add_del_path, - dir_disappeared, ext_mod_dep, + dir_disappeared, ext_mod_dep, clash, load_cached, start_node_with_cache, add_and_rehash, where_is_file_no_cache, where_is_file_cached, purge_stacktrace, mult_lib_roots, bad_erl_libs, @@ -531,7 +531,7 @@ pa_pz_option(Config) when is_list(Config) -> add_del_path(suite) -> []; add_del_path(doc) -> ["add_path, del_path should not cause priv_dir(App) to fail"]; -add_del_path(Config) -> +add_del_path(Config) when is_list(Config) -> DDir = ?config(data_dir,Config), Dir1 = filename:join(DDir,"dummy_app-1.0/ebin"), Dir2 = filename:join(DDir,"dummy_app-2.0/ebin"), @@ -545,6 +545,38 @@ add_del_path(Config) -> ok. +clash(Config) when is_list(Config) -> + DDir = ?config(data_dir,Config)++"clash/", + P = code:get_path(), + + %% test non-clashing entries + + %% remove "." to prevent clash with test-server path + ?line true = code:del_path("."), + ?line true = code:add_path(DDir++"foobar-0.1/ebin"), + ?line true = code:add_path(DDir++"zork-0.8/ebin"), + ?line test_server:capture_start(), + ?line code:clash(), + ?line test_server:capture_stop(), + ?line OKMsg = test_server:capture_get(), + ?line lists:prefix("** Found 0 name clashes in code paths", OKMsg), + ?line true = code:set_path(P), + + %% test clashing entries + + %% remove "." to prevent clash with test-server path + ?line true = code:del_path("."), + ?line true = code:add_path(DDir++"foobar-0.1/ebin"), + ?line true = code:add_path(DDir++"foobar-0.1.ez/foobar-0.1/ebin"), + ?line test_server:capture_start(), + ?line code:clash(), + ?line test_server:capture_stop(), + ?line [ErrMsg1|_] = test_server:capture_get(), + ?line {match, [" hides "]} = re:run(ErrMsg1, "\\*\\* .*( hides ).*", + [{capture,all_but_first,list}]), + ?line true = code:set_path(P), + ok. + ext_mod_dep(suite) -> []; ext_mod_dep(doc) -> diff --git a/lib/kernel/test/code_SUITE_data/clash/foobar-0.1.ez b/lib/kernel/test/code_SUITE_data/clash/foobar-0.1.ez Binary files differnew file mode 100644 index 0000000000..33d8a59b92 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/clash/foobar-0.1.ez diff --git a/lib/kernel/test/code_SUITE_data/clash/foobar-0.1/ebin/baz.beam b/lib/kernel/test/code_SUITE_data/clash/foobar-0.1/ebin/baz.beam new file mode 100644 index 0000000000..da87f32b9f --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/clash/foobar-0.1/ebin/baz.beam @@ -0,0 +1 @@ +baz 298734 diff --git a/lib/kernel/test/code_SUITE_data/clash/foobar-0.1/ebin/blarg.beam b/lib/kernel/test/code_SUITE_data/clash/foobar-0.1/ebin/blarg.beam new file mode 100644 index 0000000000..e4c70c267c --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/clash/foobar-0.1/ebin/blarg.beam @@ -0,0 +1 @@ +baz 86234 diff --git a/lib/kernel/test/code_SUITE_data/clash/zork-0.8.ez b/lib/kernel/test/code_SUITE_data/clash/zork-0.8.ez Binary files differnew file mode 100644 index 0000000000..051fa1efe4 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/clash/zork-0.8.ez diff --git a/lib/kernel/test/code_SUITE_data/clash/zork-0.8/ebin/bork.beam b/lib/kernel/test/code_SUITE_data/clash/zork-0.8/ebin/bork.beam new file mode 100644 index 0000000000..7b292c0b44 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/clash/zork-0.8/ebin/bork.beam @@ -0,0 +1 @@ +baz 23784 diff --git a/lib/kernel/test/code_SUITE_data/clash/zork-0.8/ebin/flarp.beam b/lib/kernel/test/code_SUITE_data/clash/zork-0.8/ebin/flarp.beam new file mode 100644 index 0000000000..7b2f6a850f --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/clash/zork-0.8/ebin/flarp.beam @@ -0,0 +1 @@ +baz 3246238 diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index dd7d5f111a..fad8c7398b 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. 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(gen_sctp_SUITE). @@ -24,10 +24,11 @@ %%-compile(export_all). -export([all/1,init_per_testcase/2,fin_per_testcase/2, - basic/1,xfer_min/1,xfer_active/1,api_open_close/1,api_listen/1]). + basic/1,api_open_close/1,api_listen/1,api_connect_init/1, + xfer_min/1,xfer_active/1]). all(suite) -> - [basic,xfer_min,xfer_active,api_open_close,api_listen]. + [basic,api_open_close,api_listen,api_connect_init,xfer_min,xfer_active]. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(15)), @@ -325,7 +326,7 @@ api_listen(Config) when is_list(Config) -> ?line {ok,{Localhost, Pb,[], #sctp_assoc_change{ - state = comm_lost}}} = + state=comm_lost}}} = gen_sctp:recv(Sa, infinity); {error,#sctp_assoc_change{state=cant_assoc}} -> ok end, @@ -336,3 +337,48 @@ api_listen(Config) when is_list(Config) -> ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), ok. + +api_connect_init(doc) -> + "Test the API function connect_init/4"; +api_connect_init(suite) -> + []; +api_connect_init(Config) when is_list(Config) -> + ?line Localhost = {127,0,0,1}, + + ?line {ok,S} = gen_sctp:open(), + ?line {ok,Pb} = inet:port(S), + ?line try gen_sctp:connect_init(S, Localhost, not_allowed_for_port, []) + catch error:badarg -> ok + end, + ?line try gen_sctp:connect_init(S, Localhost, 12345, not_allowed_for_opts) + catch error:badarg -> ok + end, + ?line ok = gen_sctp:close(S), + ?line {error,closed} = gen_sctp:connect_init(S, Localhost, 12345, []), + + ?line {ok,Sb} = gen_sctp:open(Pb), + ?line {ok,Sa} = gen_sctp:open(), + ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of + {error,econnrefused} -> + ?line {ok,{Localhost, + Pb,[], + #sctp_assoc_change{state=comm_lost}}} = + gen_sctp:recv(Sa, infinity); + ok -> + ?line {ok,{Localhost, + Pb,[], + #sctp_assoc_change{state=cant_assoc}}} = + gen_sctp:recv(Sa, infinity) + end, + ?line ok = gen_sctp:listen(Sb, true), + ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of + ok -> + ?line {ok,{Localhost, + Pb,[], + #sctp_assoc_change{ + state = comm_up}}} = + gen_sctp:recv(Sa, infinity) + end, + ?line ok = gen_sctp:close(Sa), + ?line ok = gen_sctp:close(Sb), + ok. diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index cf33e8b27f..eb8f918491 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. 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). @@ -28,7 +28,7 @@ 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, +-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1, kill_gethost/0, parallell_gethost/0]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -249,14 +249,16 @@ t_getaddr_v6(Config) when is_list(Config) -> ?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 {ok,IP46} = inet:getaddr(IPStr, inet6), +%% ?line IP4toIP6 = inet:getaddr(IPStr, inet6), +%% ?line case IP4toIP6 of +%% {ok,IP46} -> +%% ?line ok; +%% {error,nxdomain} -> +%% ?line false = +%% lists:member(native, +%% inet_db:res_option(lookup)) +%% end, ?line {Name6, FullName6, IPStr6, IP6, _} = ?config(test_host_ipv6_only, Config), ?line {ok,_} = inet:getaddr(list_to_atom(Name6), inet6), @@ -301,7 +303,6 @@ ipv4_to_ipv6(Config) when is_list(Config) -> 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]}, @@ -374,9 +375,10 @@ get_hosts([C|Rest], Cur, Ip, Result) -> get_hosts([], _, _, Result) -> Result. -parse(suite) -> [parse_hosts]; +parse(suite) -> [parse_hosts, parse_address]; 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"), @@ -388,6 +390,170 @@ parse_hosts(Config) when is_list(Config) -> ?line ResolvErr1 = filename:join(DataDir,"resolv.conf.err1"), ?line inet_parse:resolv(ResolvErr1). +parse_address(Config) when is_list(Config) -> + V4Strict = + [{{0,0,0,0},"0.0.0.0"}, + {{1,2,3,4},"1.2.3.4"}, + {{253,252,251,250},"253.252.251.250"}, + {{1,2,255,254},"1.2.255.254"}], + V6Strict = + [{{0,0,0,0,0,0,0,0},"::"}, + {{15,0,0,0,0,0,0,2},"f::2"}, + {{15,16#f11,0,0,0,0,256,2},"f:f11::0100:2"}, + {{0,0,0,0,0,0,0,16#17},"::17"}, + {{16#700,0,0,0,0,0,0,0},"0700::"}, + {{0,0,0,0,0,0,2,1},"::2:1"}, + {{0,0,0,0,0,3,2,1},"::3:2:1"}, + {{0,0,0,0,4,3,2,1},"::4:3:2:1"}, + {{0,0,0,5,4,3,2,1},"::5:4:3:2:1"}, + {{0,0,6,5,4,3,2,1},"::6:5:4:3:2:1"}, + {{0,7,6,5,4,3,2,1},"::7:6:5:4:3:2:1"}, + {{7,0,0,0,0,0,0,0},"7::"}, + {{7,6,0,0,0,0,0,0},"7:6::"}, + {{7,6,5,0,0,0,0,0},"7:6:5::"}, + {{7,6,5,4,0,0,0,0},"7:6:5:4::"}, + {{7,6,5,4,3,0,0,0},"7:6:5:4:3::"}, + {{7,6,5,4,3,2,0,0},"7:6:5:4:3:2::"}, + {{7,6,5,4,3,2,1,0},"7:6:5:4:3:2:1::"}, + {{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88}, + "c11:0c22:5c33:c440:55c0:c66c:77:0088"}, + {{16#c11,0,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88}, + "c11::5c33:c440:55c0:c66c:77:0088"}, + {{16#c11,16#c22,0,16#c440,16#55c0,16#c66c,16#77,16#88}, + "c11:0c22::c440:55c0:c66c:77:0088"}, + {{16#c11,16#c22,16#5c33,0,16#55c0,16#c66c,16#77,16#88}, + "c11:0c22:5c33::55c0:c66c:77:0088"}, + {{16#c11,16#c22,16#5c33,16#c440,0,16#c66c,16#77,16#88}, + "c11:0c22:5c33:c440::c66c:77:0088"}, + {{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,16#77,16#88}, + "c11:0c22:5c33:c440:55c0::77:0088"}, + {{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,0,16#88}, + "c11:0c22:5c33:c440:55c0:c66c::0088"}, + {{16#c11,0,0,16#c440,16#55c0,16#c66c,16#77,16#88}, + "c11::c440:55c0:c66c:77:0088"}, + {{16#c11,16#c22,0,0,16#55c0,16#c66c,16#77,16#88}, + "c11:0c22::55c0:c66c:77:0088"}, + {{16#c11,16#c22,16#5c33,0,0,16#c66c,16#77,16#88}, + "c11:0c22:5c33::c66c:77:0088"}, + {{16#c11,16#c22,16#5c33,16#c440,0,0,16#77,16#88}, + "c11:0c22:5c33:c440::77:0088"}, + {{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,0,16#88}, + "c11:0c22:5c33:c440:55c0::0088"}, + {{16#c11,0,0,0,16#55c0,16#c66c,16#77,16#88}, + "c11::55c0:c66c:77:0088"}, + {{16#c11,16#c22,0,0,0,16#c66c,16#77,16#88}, + "c11:0c22::c66c:77:0088"}, + {{16#c11,16#c22,16#5c33,0,0,0,16#77,16#88}, + "c11:0c22:5c33::77:0088"}, + {{16#c11,16#c22,16#5c33,16#c440,0,0,0,16#88}, + "c11:0c22:5c33:c440::0088"}, + {{16#c11,0,0,0,0,16#c66c,16#77,16#88}, + "c11::c66c:77:0088"}, + {{16#c11,16#c22,0,0,0,0,16#77,16#88}, + "c11:0c22::77:0088"}, + {{16#c11,16#c22,16#5c33,0,0,0,0,16#88}, + "c11:0c22:5c33::0088"}, + {{16#c11,0,0,0,0,0,16#77,16#88}, + "c11::77:0088"}, + {{16#c11,16#c22,0,0,0,0,0,16#88}, + "c11:0c22::0088"}, + {{0,0,0,0,0,65535,258,65534},"::FFFF:1.2.255.254"}, + {{16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff}, + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"} + |[{{D2,0,0,0,0,P,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4}, + erlang:integer_to_list(D2, 16)++"::"++Q++S} + || {{D1,D2,D3,D4},S} <- V4Strict, + {P,Q} <- [{0,""},{16#17,"17:"},{16#ff0,"0ff0:"}]]], + V4Sloppy = + [{{10,1,16#98,16#76},"10.0x019876"}, + {{8#12,1,8#130,8#321},"012.01.054321"}, + {{255,255,255,255},"255.255.255.0377"}, + {{255,255,255,255},"0Xff.000000000377.0x0000ff.255"}, + {{255,255,255,255},"255.255.65535"}, + {{255,255,255,255},"255.0xFF.0177777"}, + {{255,255,255,255},"255.16777215"}, + {{255,255,255,255},"00377.0XFFFFFF"}, + {{255,255,255,255},"4294967295"}, + {{255,255,255,255},"0xffffffff"}, + {{255,255,255,255},"00000000000037777777777"}, + {{16#12,16#34,16#56,16#78},"0x12345678"}, + {{16#12,16#34,16#56,16#78},"0x12.0x345678"}, + {{16#12,16#34,16#56,16#78},"0x12.0X34.0x5678"}, + {{16#12,16#34,16#56,16#78},"0x12.0X34.0x56.0X78"}, + {{0,0,0,0},"0"}, + {{0,0,0,0},"00"}, + {{0,0,0,0},"0.0"}, + {{0,0,0,0},"00.00.00"}, + {{0,0,0,0},"0.00.0.0"}, + {{0,0,0,0},"0.0.000000000000.0"}], + V6Sloppy = + [{{0,0,0,0,0,65535,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4},S} + || {{D1,D2,D3,D4},S} <- V4Strict++V4Sloppy], + V4Err = + ["0.256.0.1", + "1.2.3.4.5", + "256.255.65535", + "4294967296", + "0x100000000", + "040000000000", + "1.2.3.-4", + "1.2.-3.4", + "1.-2.3.4", + "-1.2.3.4", + "10.", + "172.16.", + "198.168.0.", + "127.0.0.1."], + V6Err = + [":::", + "f:::2", + "::-1", + "::g", + "f:f11::10100:2", + "::17000", + "10000::", + "::8:7:6:5:4:3:2:1", + "8:7:6:5:4:3:2:1::", + "8:7:6:5:4::3:2:1", + "::1.2.3.4.5", + "::1.2.3.04", + "::1.256.3.4", + "::-5.4.3.2", + "::5.-4.3.2", + "::5.4.-3.2", + "::5.4.3.-2", + "::FFFF:1.2.3.4.5", + "::10.", + "::FFFF:172.16.", + "fe80::198.168.0.", + "fec0::fFfF:127.0.0.1."], + t_parse_address + (ipv6_address, + V6Strict++V6Sloppy++V6Err++V4Err), + t_parse_address + (ipv6strict_address, + V6Strict++V6Err++V4Err++[S || {_,S} <- V6Sloppy]), + t_parse_address + (ipv4_address, + V4Strict++V4Sloppy++V4Err++V6Err++[S || {_,S} <- V6Strict]), + t_parse_address + (ipv4strict_address, + V4Strict++V4Err++V6Err++[S || {_,S} <- V4Sloppy++V6Strict]). + +t_parse_address(Func, []) -> + io:format("~p done.~n", [Func]), + ok; +t_parse_address(Func, [{Addr,String}|L]) -> + io:format("~p = ~p.~n", [Addr,String]), + {ok,Addr} = inet_parse:Func(String), + t_parse_address(Func, L); +t_parse_address(Func, [String|L]) -> + io:format("~p.~n", [String]), + {error,einval} = inet_parse:Func(String), + t_parse_address(Func, L). + + + t_gethostnative(suite) ->[]; t_gethostnative(doc) ->[]; t_gethostnative(Config) when is_list(Config) -> diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index 659cfc5988..cc32d1f8f9 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2009-2010. 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_res_SUITE). @@ -239,16 +239,37 @@ resolve(_Opts, []) -> ok; resolve(Opts, [{Class,Type,Name,Answers,Authority}=Q|Qs]) -> io:format("Query: ~p~nOptions: ~p~n", [Q,Opts]), {ok,Msg} = inet_res:resolve(Name, Class, Type, Opts), - if Answers =/= undefined -> - AnList = lists:sort(Answers), - AnList = lists:sort([inet_dns:rr(RR, data) || - RR <- inet_dns:msg(Msg, anlist)]); - true -> ok end, - if Authority =/= undefined -> - NsList = lists:sort(Authority), - NsList = lists:sort([inet_dns:rr(RR, data) || - RR <- inet_dns:msg(Msg, nslist)]); - true -> ok end, + AnList = + if + Answers =/= undefined -> + lists:sort(Answers); + true -> + undefined + end, + NsList = + if + Authority =/= undefined -> + lists:sort(Authority); + true -> + undefined + end, + case {lists:sort + ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, anlist)]), + lists:sort + ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, nslist)])} of + {AnList,NsList} -> + ok; + {NsList,AnList} when Type =:= ns -> + %% This whole case statement is kind of inside out just + %% to accept this case when some legacy DNS resolvers + %% return the answer to a NS query in the answer section + %% instead of in the authority section. + ok; + {AnList,_} when NsList =:= undefined -> + ok; + {_,NsList} when AnList =:= undefined -> + ok + end, Buf = inet_dns:encode(Msg), {ok,Msg} = inet_dns:decode(Buf), resolve(Opts, Qs). @@ -292,10 +313,23 @@ edns0(Config) when is_list(Config) -> MXs = lists:sort(inet_res_filter(inet_dns:msg(Msg2, anlist), in, mx)), Buf2 = inet_dns:encode(Msg2), {ok,Msg2} = inet_dns:decode(Buf2), - [OptRR] = [RR || RR <- inet_dns:msg(Msg2, arlist), - inet_dns:rr(RR, type) =:= opt], - io:format("~p~n", [inet_dns:rr(OptRR)]), - ok. + case [RR || RR <- inet_dns:msg(Msg2, arlist), + inet_dns:rr(RR, type) =:= opt] of + [OptRR] -> + io:format("~p~n", [inet_dns:rr(OptRR)]), + ok; + [] -> + case os:type() of + {unix,sunos} -> + case os:version() of + {M,V,_} when M < 5; M == 5, V =< 8 -> + %% In our test park only known platform + %% with an DNS resolver that can not do + %% EDNS0. + {comment,"No EDNS0"} + end + end + end. inet_res_filter(Anlist, Class, Type) -> [inet_dns:rr(RR, data) || RR <- Anlist, @@ -331,11 +365,13 @@ files_monitor(suite) -> files_monitor(doc) -> ["Tests monitoring of /etc/hosts and /etc/resolv.conf, but not them"]; files_monitor(Config) when is_list(Config) -> + Search = inet_db:res_option(search), HostsFile = inet_db:res_option(hosts_file), ResolvConf = inet_db:res_option(resolv_conf), Inet6 = inet_db:res_option(inet6), try do_files_monitor(Config) after + inet_db:res_option(search, Search), inet_db:res_option(resolv_conf, ResolvConf), inet_db:res_option(hosts_file, HostsFile), inet_db:res_option(inet6, Inet6) @@ -344,7 +380,13 @@ files_monitor(Config) when is_list(Config) -> do_files_monitor(Config) -> Dir = ?config(priv_dir, Config), {ok,Hostname} = inet:gethostname(), - FQDN = Hostname++"."++inet_db:res_option(domain), + FQDN = + case inet_db:res_option(domain) of + "" -> + Hostname; + _ -> + Hostname++"."++inet_db:res_option(domain) + end, HostsFile = filename:join(Dir, "files_monitor_hosts"), ResolvConf = filename:join(Dir, "files_monitor_resolv.conf"), ok = inet_db:res_option(resolv_conf, ResolvConf), @@ -362,20 +404,20 @@ do_files_monitor(Config) -> {error,nxdomain} = inet_res:gethostbyname(FQDN), {ok,{127,0,0,10}} = inet:getaddr("mx.otptest", inet), {ok,{0,0,0,0,0,0,32512,28}} = inet:getaddr("resolve.otptest", inet6), - ok = inet_db:res_option(inet6, true), {ok,#hostent{h_name = Hostname, h_addrtype = inet6, h_length = 16, h_addr_list = [{0,0,0,0,0,0,0,1}]}} = - inet:gethostbyname(Hostname), + inet:gethostbyname(Hostname, inet6), {ok,#hostent{h_name = FQDN, h_addrtype = inet6, h_length = 16, h_addr_list = [{0,0,0,0,0,0,0,1}]}} = - inet:gethostbyname(FQDN), + inet:gethostbyname(FQDN, inet6), {error,nxdomain} = inet_res:gethostbyname("resolve"), %% XXX inet does not honour res_option inet6, might be a problem? %% therefore inet_res is called here + ok = inet_db:res_option(inet6, true), {ok,#hostent{h_name = "resolve.otptest", h_addrtype = inet6, h_length = 16, diff --git a/lib/megaco/test/Makefile b/lib/megaco/test/Makefile index 85c97359d7..682b83d368 100644 --- a/lib/megaco/test/Makefile +++ b/lib/megaco/test/Makefile @@ -62,8 +62,6 @@ SOURCE = $(HRL_FILES) $(ERL_FILES) TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) -COVER_SPEC_FILE = megaco.cover - APP_CASES = app appup CODEC_CASES = codec1 codec2 codec3a codec3b codec3c @@ -80,10 +78,10 @@ MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile) ifeq ($(MAKE_EMAKE),) BUILDTARGET = $(TARGET_FILES) -RELTEST_FILES = $(MEGACO_SPECS) $(COVER_SPEC_FILE) $(SOURCE) +RELTEST_FILES = $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) $(SOURCE) else BUILDTARGET = emakebuild -RELTEST_FILES = $(EMAKEFILE) $(MEGACO_SPECS) $(COVER_SPEC_FILE) $(SOURCE) +RELTEST_FILES = $(EMAKEFILE) $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) $(SOURCE) endif diff --git a/lib/megaco/test/modules.mk b/lib/megaco/test/modules.mk index 0186a84c26..049d8babe2 100644 --- a/lib/megaco/test/modules.mk +++ b/lib/megaco/test/modules.mk @@ -1,24 +1,26 @@ #-*-makefile-*- ; force emacs to enter makefile-mode # %CopyrightBegin% -# -# Copyright Ericsson AB 2001-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2001-2010. 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% TEST_SPEC_FILE = megaco.spec +COVER_SPEC_FILE = megaco.cover + BEHAVIOUR_MODULES = \ megaco_test_generator diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk index b0574bbeef..1ee78c423a 100644 --- a/lib/megaco/vsn.mk +++ b/lib/megaco/vsn.mk @@ -19,7 +19,7 @@ APPLICATION = megaco MEGACO_VSN = 3.13.1 -PRE_VSN =-p03 +PRE_VSN =-p04 APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)" TICKETS = OTP-8317 OTP-8323 OTP-8362 OTP-8403 diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c index 63177121bc..6a920e6c76 100644 --- a/lib/odbc/c_src/odbcserver.c +++ b/lib/odbc/c_src/odbcserver.c @@ -1,19 +1,19 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 1999-2010. 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% * @@ -749,11 +749,12 @@ static db_result_msg db_param_query(byte *buffer, db_state *state) byte *sql; db_result_msg msg; int i, num_param_values, ver = 0, - erl_type = 0, index = 0, size = 0, cols = 0; + erl_type = 0, index = 0, size = 0, cols = 0; long long_num_param_values; param_status param_status; diagnos diagnos; - param_array *params; + param_array *params; + SQLRETURN result; if (associated_result_set(state)) { clean_state(state); @@ -784,10 +785,16 @@ static db_result_msg db_param_query(byte *buffer, db_state *state) num_param_values, state); if(params != NULL) { - if(!sql_success(SQLExecDirect(statement_handle(state), - sql, SQL_NTS))) { - diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state)); - msg = encode_error_message(diagnos.error_msg); + + result = SQLExecDirect(statement_handle(state), sql, SQL_NTS); + if (!sql_success(result) || result == SQL_NO_DATA) { + diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state)); + } + /* SQL_NO_DATA and SQLSTATE 00000 indicate success for + updates/deletes that affect no rows */ + if(!sql_success(result) && + !(result == SQL_NO_DATA && !strcmp((char *)diagnos.sqlState, INFO))) { + msg = encode_error_message(diagnos.error_msg); } else { for (i = 0; i < param_status.params_processed; i++) { switch (param_status.param_status_array[i]) { @@ -2452,6 +2459,7 @@ static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle) int acc_errmsg_size; byte *current_errmsg_pos; SQLCHAR current_sql_state[SQL_STATE_SIZE]; + SQLRETURN result; diagnos.error_msg[0] = 0; @@ -2464,10 +2472,10 @@ static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle) /* Foreach diagnostic record in the current set of diagnostic records the error message is obtained */ for(record_nr = 1; ;record_nr++) { - if(SQLGetDiagRec(handleType, handle, record_nr, current_sql_state, + result = SQLGetDiagRec(handleType, handle, record_nr, current_sql_state, &nativeError, current_errmsg_pos, - (SQLSMALLINT)errmsg_buffer_size, &errmsg_size) - != SQL_SUCCESS) { + (SQLSMALLINT)errmsg_buffer_size, &errmsg_size); + if(result != SQL_SUCCESS && result != SQL_NO_DATA) { break; diff --git a/lib/percept/src/egd_render.erl b/lib/percept/src/egd_render.erl index cea9d2d926..4a0247dd33 100644 --- a/lib/percept/src/egd_render.erl +++ b/lib/percept/src/egd_render.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2008-2010. 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% %% @@ -179,7 +179,7 @@ color(Trans,Layers,Type,OldC) -> color([],_) -> {0.0,0.0,0.0,0.0}; color([{_,C}|_],opaque) -> C; -color(Layers,alpha) -> color1({0,0,0,0},Layers). +color(Layers,alpha) -> color1({0.0,0.0,0.0,0.0},Layers). color1(Color,[]) -> Color; color1(Color,[{_,C}|Layers]) -> color1(alpha_blend(Color,C),Layers). diff --git a/lib/percept/test/egd_SUITE.erl b/lib/percept/test/egd_SUITE.erl index a2595400dd..fde02b47d5 100644 --- a/lib/percept/test/egd_SUITE.erl +++ b/lib/percept/test/egd_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. 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% %% @@ -143,6 +143,8 @@ image_shape(Config) when is_list(Config) -> ?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt2, Fgc), ?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt1, Fgc), + ?line <<_/binary>> = egd:render(Im, raw_bitmap, [{render_engine, alpha}]), + ?line ok = egd:destroy(Im), erase(image_size), ok. @@ -177,6 +179,8 @@ image_primitives(Config) when is_list(Config) -> ?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt2, Fgc), ?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt1, Fgc), + ?line <<_/binary>> = egd_render:binary(Im2, alpha), + erase(image_size), ok. |