From 8e415cb7094e9ea4287a56daaf227666f2862ed2 Mon Sep 17 00:00:00 2001 From: Per Hedeland Date: Tue, 24 Aug 2010 19:53:45 +0200 Subject: Let an 8-tuple given as ip_address() for gen_tcp/gen_udp/gen_sctp imply 'inet6' Currently an 8-tuple representing an IPv6 address is not accepted by gen_tcp:listen/2, gen_tcp:connect/3,4, gen_udp:open/2, or gen_sctp:open/1,2, unless the 'inet6' option is also given. This means that an application that has obtained the address, e.g. from configuration that allows for either IPv4 or IPv6, must always check the type of the address before passing it to these functions. Letting the functions infer 'inet6' from the 8-tuple, in case other options do not override this choice, improves usability. --- lib/kernel/src/gen_sctp.erl | 30 ++++++++++++++++++++---------- lib/kernel/src/gen_tcp.erl | 36 +++++++++++++++++++++++------------- lib/kernel/src/gen_udp.erl | 34 ++++++++++++++++++++++------------ 3 files changed, 65 insertions(+), 35 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index a1542ab507..cccfa75005 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -39,7 +39,7 @@ open() -> open([]). open(Opts) when is_list(Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), case Mod:open(Opts) of {error,badarg} -> erlang:error(badarg, [Opts]); @@ -234,17 +234,27 @@ controlling_process(S, Pid) -> %% Utilites %% -%% Get the SCTP moudule -mod() -> inet_db:sctp_module(). +%% Get the SCTP module, but IPv6 address overrides default IPv4 +mod(Address) -> + case inet_db:sctp_module() of + inet_sctp when tuple_size(Address) =:= 8 -> + inet6_sctp; + Mod -> + Mod + end. %% Get the SCTP module, but option sctp_module|inet|inet6 overrides -mod([{sctp_module,Mod}|_]) -> +mod([{sctp_module,Mod}|_], _Address) -> Mod; -mod([inet|_]) -> +mod([inet|_], _Address) -> inet_sctp; -mod([inet6|_]) -> +mod([inet6|_], _Address) -> inet6_sctp; -mod([_|Opts]) -> - mod(Opts); -mod([]) -> - mod(). +mod([{ip, Address}|Opts], _) -> + mod(Opts, Address); +mod([{ifaddr, Address}|Opts], _) -> + mod(Opts, Address); +mod([_|Opts], Address) -> + mod(Opts, Address); +mod([], Address) -> + mod(Address). diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index 7401b06a64..16a87d71b6 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -1,7 +1,7 @@ %% %% %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 @@ -46,7 +46,7 @@ connect(Address, Port, Opts, Time) -> end. connect1(Address,Port,Opts,Timer) -> - Mod = mod(Opts), + Mod = mod(Opts, Address), case Mod:getaddrs(Address,Timer) of {ok,IPs} -> case Mod:getserv(Port) of @@ -73,7 +73,7 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) -> %% Listen on a tcp port %% listen(Port, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), case Mod:getserv(Port) of {ok,TP} -> Mod:listen(TP, Opts); @@ -173,20 +173,30 @@ controlling_process(S, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), Mod:fdopen(Fd, Opts). -%% Get the tcp_module -mod() -> inet_db:tcp_module(). +%% Get the tcp_module, but IPv6 address overrides default IPv4 +mod(Address) -> + case inet_db:tcp_module() of + inet_tcp when tuple_size(Address) =:= 8 -> + inet6_tcp; + Mod -> + Mod + end. %% Get the tcp_module, but option tcp_module|inet|inet6 overrides -mod([{tcp_module,Mod}|_]) -> +mod([{tcp_module,Mod}|_], _Address) -> Mod; -mod([inet|_]) -> +mod([inet|_], _Address) -> inet_tcp; -mod([inet6|_]) -> +mod([inet6|_], _Address) -> inet6_tcp; -mod([_|Opts]) -> - mod(Opts); -mod([]) -> - mod(). +mod([{ip, Address}|Opts], _) -> + mod(Opts, Address); +mod([{ifaddr, Address}|Opts], _) -> + mod(Opts, Address); +mod([_|Opts], Address) -> + mod(Opts, Address); +mod([], Address) -> + mod(Address). diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl index 6bded4bda6..99020c7b6c 100644 --- a/lib/kernel/src/gen_udp.erl +++ b/lib/kernel/src/gen_udp.erl @@ -1,7 +1,7 @@ %% %% %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 @@ -29,7 +29,7 @@ open(Port) -> open(Port, []). open(Port, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), {ok,UP} = Mod:getserv(Port), Mod:open(UP, Opts). @@ -97,21 +97,31 @@ controlling_process(S, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - Mod = mod(), + Mod = mod(Opts, undefined), Mod:fdopen(Fd, Opts). -%% Get the udp_module -mod() -> inet_db:udp_module(). +%% Get the udp_module, but IPv6 address overrides default IPv4 +mod(Address) -> + case inet_db:udp_module() of + inet_udp when tuple_size(Address) =:= 8 -> + inet6_udp; + Mod -> + Mod + end. %% Get the udp_module, but option udp_module|inet|inet6 overrides -mod([{udp_module,Mod}|_]) -> +mod([{udp_module,Mod}|_], _Address) -> Mod; -mod([inet|_]) -> +mod([inet|_], _Address) -> inet_udp; -mod([inet6|_]) -> +mod([inet6|_], _Address) -> inet6_udp; -mod([_|Opts]) -> - mod(Opts); -mod([]) -> - mod(). +mod([{ip, Address}|Opts], _) -> + mod(Opts, Address); +mod([{ifaddr, Address}|Opts], _) -> + mod(Opts, Address); +mod([_|Opts], Address) -> + mod(Opts, Address); +mod([], Address) -> + mod(Address). -- cgit v1.2.3 From 296b3ae4d88c87cdf9638a1dd9cab622c748c5e6 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 6 Sep 2010 12:26:47 +0200 Subject: Add tests Conflicts: lib/kernel/test/gen_sctp_SUITE.erl --- lib/kernel/test/gen_sctp_SUITE.erl | 59 ++++++++++++++++++++++++++++++++-- lib/kernel/test/gen_tcp_api_SUITE.erl | 57 +++++++++++++++++++++++++++++++-- lib/kernel/test/gen_udp_SUITE.erl | 60 +++++++++++++++++++++++++++++++++-- 3 files changed, 168 insertions(+), 8 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index eb06d4324b..9aa94a0868 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -27,12 +27,12 @@ -export( [basic/1, api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, - xfer_min/1,xfer_active/1,def_sndrcvinfo/1]). + xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1]). all(suite) -> [basic, api_open_close,api_listen,api_connect_init,api_opts, - xfer_min,xfer_active,def_sndrcvinfo]. + xfer_min,xfer_active,def_sndrcvinfo,implicit_inet6]. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(15)), @@ -551,3 +551,58 @@ api_opts(Config) when is_list(Config) -> {{error,einval},{unix,sunos}} -> ok end. + +implicit_inet6(Config) when is_list(Config) -> + ?line Hostname = ok(inet:gethostname()), + ?line + case gen_sctp:open(0, [inet6]) of + {ok,S1} -> + ?line + case inet:getaddr(Hostname, inet6) of + {ok,Host} -> + ?line Loopback = {0,0,0,0,0,0,0,1}, + ?line io:format("~s ~p~n", ["Loopback",Loopback]), + ?line implicit_inet6(S1, Loopback), + ?line ok = gen_sctp:close(S1), + %% + ?line Localhost = + ok(inet:getaddr("localhost", inet6)), + ?line io:format("~s ~p~n", ["localhost",Localhost]), + ?line S2 = + ok(gen_sctp:open(0, [{ip,Localhost}])), + ?line implicit_inet6(S2, Localhost), + ?line ok = gen_sctp:close(S2), + %% + ?line io:format("~s ~p~n", [Hostname,Host]), + ?line S3 = + ok(gen_sctp:open(0, [{ifaddr,Host}])), + ?line implicit_inet6(S3, Host), + ?line ok = gen_sctp:close(S1); + {error,eafnosupport} -> + ?line ok = gen_sctp:close(S1), + {skip,"Can not look up IPv6 address"} + end; + _ -> + {skip,"IPv6 not supported"} + end. + +implicit_inet6(S1, Addr) -> + ?line ok = gen_sctp:listen(S1, true), + ?line P1 = ok(inet:port(S1)), + ?line S2 = ok(gen_sctp:open(0, [inet6])), + ?line P2 = ok(inet:port(S2)), + ?line #sctp_assoc_change{state=comm_up} = + ok(gen_sctp:connect(S2, Addr, P1, [])), + ?line case ok(gen_sctp:recv(S1)) of + {Addr,P2,[],#sctp_assoc_change{state=comm_up}} -> + ok + end, + ?line case ok(inet:sockname(S1)) of + {Addr,P1} -> ok; + {{0,0,0,0,0,0,0,0},P1} -> ok + end, + ?line case ok(inet:sockname(S2)) of + {Addr,P2} -> ok; + {{0,0,0,0,0,0,0,0},P2} -> ok + end, + ?line ok = gen_sctp:close(S2). diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index 11d19aaa82..94637290a1 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-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 @@ -30,10 +30,11 @@ t_connect/1, t_connect_bad/1, t_recv/1, t_recv_timeout/1, t_recv_eof/1, t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1, - t_fdopen/1]). + t_fdopen/1, t_implicit_inet6/1]). all(suite) -> [t_accept, t_connect, t_recv, t_shutdown_write, - t_shutdown_both, t_shutdown_error, t_fdopen]. + t_shutdown_both, t_shutdown_error, t_fdopen, + t_implicit_inet6]. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(60)), @@ -156,6 +157,54 @@ t_fdopen(Config) when is_list(Config) -> ok. +%%% implicit inet6 option to api functions + +t_implicit_inet6(Config) when is_list(Config) -> + ?line Hostname = ok(inet:gethostname()), + ?line + case gen_tcp:listen(0, [inet6]) of + {ok,S1} -> + ?line + case inet:getaddr(Hostname, inet6) of + {ok,Host} -> + ?line Loopback = {0,0,0,0,0,0,0,1}, + ?line io:format("~s ~p~n", ["Loopback",Loopback]), + ?line implicit_inet6(S1, Loopback), + ?line ok = gen_tcp:close(S1), + %% + ?line Localhost = + ok(inet:getaddr("localhost", inet6)), + ?line io:format("~s ~p~n", ["localhost",Localhost]), + ?line S2 = ok(gen_tcp:listen(0, [{ip,Localhost}])), + ?line implicit_inet6(S2, Localhost), + ?line ok = gen_tcp:close(S2), + %% + ?line io:format("~s ~p~n", [Hostname,Host]), + ?line S3 = ok(gen_tcp:listen(0, [{ifaddr,Host}])), + ?line implicit_inet6(S3, Host), + ?line ok = gen_tcp:close(S1); + {error,eafnosupport} -> + ?line ok = gen_tcp:close(S1), + {skip,"Can not look up IPv6 address"} + end; + _ -> + {skip,"IPv6 not supported"} + end. + +implicit_inet6(S, Addr) -> + ?line P = ok(inet:port(S)), + ?line S2 = ok(gen_tcp:connect(Addr, P, [])), + ?line P2 = ok(inet:port(S2)), + ?line S1 = ok(gen_tcp:accept(S)), + ?line P1 = P = ok(inet:port(S1)), + ?line {Addr,P2} = ok(inet:peername(S1)), + ?line {Addr,P1} = ok(inet:peername(S2)), + ?line {Addr,P1} = ok(inet:sockname(S1)), + ?line {Addr,P2} = ok(inet:sockname(S2)), + ?line ok = gen_tcp:close(S2), + ?line ok = gen_tcp:close(S1). + + %%% Utilities @@ -217,3 +266,5 @@ unused_ip(A, B, C, D) -> {ok, _} -> unused_ip(A, B, C, D+1); {error, _} -> {ok, {A, B, C, D}} end. + +ok({ok,V}) -> V. diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index fa1991872b..44dd8607b9 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %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 @@ -34,12 +34,12 @@ -export([send_to_closed/1, buffer_size/1, binary_passive_recv/1, bad_address/1, - read_packets/1, open_fd/1, connect/1]). + read_packets/1, open_fd/1, connect/1, implicit_inet6/1]). all(suite) -> [send_to_closed, buffer_size, binary_passive_recv, bad_address, read_packets, - open_fd, connect]. + open_fd, connect, implicit_inet6]. init_per_testcase(_Case, Config) -> ?line Dog=test_server:timetrap(?default_timeout), @@ -425,3 +425,57 @@ connect(Config) when is_list(Config) -> ok = gen_udp:send(S2, <<16#deadbeef:32>>), {error,econnrefused} = gen_udp:recv(S2, 0, 5), ok. + +implicit_inet6(Config) when is_list(Config) -> + ?line Hostname = ok(inet:gethostname()), + ?line Active = {active,false}, + ?line + case gen_udp:open(0, [inet6,Active]) of + {ok,S1} -> + ?line + case inet:getaddr(Hostname, inet6) of + {ok,Host} -> + ?line Loopback = {0,0,0,0,0,0,0,1}, + ?line io:format("~s ~p~n", ["Loopback",Loopback]), + ?line implicit_inet6(S1, Active, Loopback), + ?line ok = gen_udp:close(S1), + %% + ?line Localhost = + ok(inet:getaddr("localhost", inet6)), + ?line io:format("~s ~p~n", ["localhost",Localhost]), + ?line S2 = + ok(gen_udp:open(0, [{ip,Localhost},Active])), + ?line implicit_inet6(S2, Active, Localhost), + ?line ok = gen_udp:close(S2), + %% + ?line io:format("~s ~p~n", [Hostname,Host]), + ?line S3 = + ok(gen_udp:open(0, [{ifaddr,Host},Active])), + ?line implicit_inet6(S3, Active, Host), + ?line ok = gen_udp:close(S1); + {error,eafnosupport} -> + ?line ok = gen_udp:close(S1), + {skip,"Can not look up IPv6 address"} + end; + _ -> + {skip,"IPv6 not supported"} + end. + +implicit_inet6(S1, Active, Addr) -> + ?line P1 = ok(inet:port(S1)), + ?line S2 = ok(gen_udp:open(0, [inet6,Active])), + ?line P2 = ok(inet:port(S2)), + ?line ok = gen_udp:connect(S2, Addr, P1), + ?line ok = gen_udp:connect(S1, Addr, P2), + ?line {Addr,P2} = ok(inet:peername(S1)), + ?line {Addr,P1} = ok(inet:peername(S2)), + ?line {Addr,P1} = ok(inet:sockname(S1)), + ?line {Addr,P2} = ok(inet:sockname(S2)), + ?line ok = gen_udp:send(S1, Addr, P2, "ping"), + ?line {Addr,P1,"ping"} = ok(gen_udp:recv(S2, 1024, 1000)), + ?line ok = gen_udp:send(S2, Addr, P1, "pong"), + ?line {Addr,P2,"pong"} = ok(gen_udp:recv(S1, 1024)), + ?line ok = gen_udp:close(S2). + + +ok({ok,V}) -> V. -- cgit v1.2.3