diff options
Diffstat (limited to 'lib/kernel/test/gen_udp_SUITE.erl')
-rw-r--r-- | lib/kernel/test/gen_udp_SUITE.erl | 743 |
1 files changed, 491 insertions, 252 deletions
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index 2354f8accd..1029d7ef0a 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -1,51 +1,58 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. 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. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% -% -% test the behavior of gen_udp. Testing udp is really a very unfunny task, -% because udp is not deterministic. -% --module(gen_udp_SUITE). --include_lib("test_server/include/test_server.hrl"). +%% +%% Test the behavior of gen_udp. Testing udp is really a very unfunny task, +%% because udp is not deterministic. +%% +-module(gen_udp_SUITE). +-include_lib("common_test/include/ct.hrl"). --define(default_timeout, ?t:minutes(1)). -% XXX - we should pick a port that we _know_ is closed. That's pretty hard. +%% XXX - we should pick a port that we _know_ is closed. That's pretty hard. -define(CLOSED_PORT, 6666). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). -export([init_per_testcase/2, end_per_testcase/2]). --export([send_to_closed/1, +-export([send_to_closed/1, active_n/1, buffer_size/1, binary_passive_recv/1, bad_address/1, - read_packets/1, open_fd/1, connect/1, implicit_inet6/1]). + read_packets/1, open_fd/1, connect/1, implicit_inet6/1, + local_basic/1, local_unbound/1, + local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]). -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. all() -> [send_to_closed, buffer_size, binary_passive_recv, bad_address, read_packets, open_fd, connect, - implicit_inet6]. + implicit_inet6, active_n, + {group, local}]. groups() -> - []. + [{local, [], + [local_basic, local_unbound, + local_fdopen, local_fdopen_unbound, local_abstract]}]. init_per_suite(Config) -> Config. @@ -53,36 +60,40 @@ init_per_suite(Config) -> end_per_suite(_Config) -> ok. +init_per_group(local, Config) -> + case gen_udp:open(0, [local]) of + {ok,S} -> + ok = gen_udp:close(S), + Config; + {error,eafnosupport} -> + {skip, "AF_LOCAL not supported"} + end; init_per_group(_GroupName, Config) -> Config. +end_per_group(local, _Config) -> + delete_local_filenames(); end_per_group(_GroupName, Config) -> Config. init_per_testcase(_Case, Config) -> - ?line Dog=test_server:timetrap(?default_timeout), - [{watchdog, Dog}|Config]. + Config. -end_per_testcase(_Case, Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), +end_per_testcase(_Case, _Config) -> ok. %%------------------------------------------------------------- %% Send two packets to a closed port (on some systems this causes the socket %% to be closed). -send_to_closed(doc) -> - ["Tests core functionality."]; -send_to_closed(suite) -> - []; +%% Tests core functionality. send_to_closed(Config) when is_list(Config) -> - ?line {ok, Sock} = gen_udp:open(0), - ?line ok = gen_udp:send(Sock, {127,0,0,1}, ?CLOSED_PORT, "foo"), + {ok, Sock} = gen_udp:open(0), + ok = gen_udp:send(Sock, {127,0,0,1}, ?CLOSED_PORT, "foo"), timer:sleep(2), - ?line ok = gen_udp:send(Sock, {127,0,0,1}, ?CLOSED_PORT, "foo"), - ?line ok = gen_udp:close(Sock), + ok = gen_udp:send(Sock, {127,0,0,1}, ?CLOSED_PORT, "foo"), + ok = gen_udp:close(Sock), ok. @@ -90,19 +101,16 @@ send_to_closed(Config) when is_list(Config) -> %%------------------------------------------------------------- %% Test that the UDP socket buffer sizes are settable -buffer_size(suite) -> - []; -buffer_size(doc) -> - ["Test UDP buffer size setting."]; +%% Test UDP buffer size setting. buffer_size(Config) when is_list(Config) -> - ?line Len = 256, - ?line Bin = list_to_binary(lists:seq(0, Len-1)), - ?line M = 8192 div Len, - ?line Spec0 = + Len = 256, + Bin = list_to_binary(lists:seq(0, Len-1)), + M = 8192 div Len, + Spec0 = [{opt,M},{safe,M-3},{long,M+1}, {opt,2*M},{safe,2*M-3},{long,2*M+1}, {opt,4*M},{safe,4*M-3},{long,4*M+1}], - ?line Spec = + Spec = [case Tag of opt -> [{recbuf,Val*Len},{sndbuf,(Val + 2)*Len}]; @@ -114,12 +122,12 @@ buffer_size(Config) when is_list(Config) -> [truncated,emsgsize,timeout]} end || {Tag,Val} <- Spec0], %% - ?line {ok, ClientSocket} = gen_udp:open(0, [binary]), - ?line {ok, ClientPort} = inet:port(ClientSocket), - ?line Client = self(), - ?line ClientIP = {127,0,0,1}, - ?line ServerIP = {127,0,0,1}, - ?line Server = + {ok, ClientSocket} = gen_udp:open(0, [binary]), + {ok, ClientPort} = inet:port(ClientSocket), + Client = self(), + ClientIP = {127,0,0,1}, + ServerIP = {127,0,0,1}, + Server = spawn_link( fun () -> {ok, ServerSocket} = gen_udp:open(0, [binary]), @@ -129,78 +137,77 @@ buffer_size(Config) when is_list(Config) -> ServerSocket, 1, Spec), ok = gen_udp:close(ServerSocket) end), - ?line Mref = erlang:monitor(process, Server), - ?line receive - {Server,port,ServerPort} -> - ?line buffer_size_client(Server, ServerIP, ServerPort, - ClientSocket, 1, Spec) - end, - ?line ok = gen_udp:close(ClientSocket), - ?line receive - {'DOWN',Mref,_,_,normal} -> - ?line ok - end. + Mref = erlang:monitor(process, Server), + receive + {Server,port,ServerPort} -> + buffer_size_client(Server, ServerIP, ServerPort, + ClientSocket, 1, Spec) + end, + ok = gen_udp:close(ClientSocket), + receive + {'DOWN',Mref,_,_,normal} -> + ok + end. buffer_size_client(_, _, _, _, _, []) -> - ?line ok; + ok; buffer_size_client(Server, IP, Port, Socket, Cnt, [Opts|T]) when is_list(Opts) -> - ?line io:format("buffer_size_client Cnt=~w setopts ~p.~n", [Cnt,Opts]), - ?line ok = inet:setopts(Socket, Opts), - ?line Server ! {self(),setopts,Cnt}, - ?line receive {Server,setopts,Cnt} -> ok end, - ?line buffer_size_client(Server, IP, Port, Socket, Cnt+1, T); + io:format("buffer_size_client Cnt=~w setopts ~p.~n", [Cnt,Opts]), + ok = inet:setopts(Socket, Opts), + Server ! {self(),setopts,Cnt}, + receive {Server,setopts,Cnt} -> ok end, + buffer_size_client(Server, IP, Port, Socket, Cnt+1, T); buffer_size_client(Server, IP, Port, Socket, Cnt, [{B,Replies}|T]=Opts) when is_binary(B) -> - ?line io:format( - "buffer_size_client Cnt=~w send size ~w expecting ~p.~n", - [Cnt,size(B),Replies]), - ?line ok = gen_udp:send(Socket, IP, Port, <<Cnt,B/binary>>), - ?line receive - {Server,Cnt,Reply} -> - ?line Tag = - if - is_tuple(Reply) -> - element(1, Reply); - is_atom(Reply) -> - Reply - end, - ?line case lists:member(Tag, Replies) of - true -> ok; - false -> - ?line - ?t:fail({reply_mismatch,Cnt,Reply,Replies, - byte_size(B), - inet:getopts(Socket, - [sndbuf,recbuf])}) - end, - ?line buffer_size_client(Server, IP, Port, Socket, Cnt+1, T) - after 1313 -> - ?line buffer_size_client(Server, IP, Port, Socket, Cnt, Opts) - end. + io:format( + "buffer_size_client Cnt=~w send size ~w expecting ~p.~n", + [Cnt,size(B),Replies]), + ok = gen_udp:send(Socket, IP, Port, <<Cnt,B/binary>>), + receive + {Server,Cnt,Reply} -> + Tag = + if + is_tuple(Reply) -> + element(1, Reply); + is_atom(Reply) -> + Reply + end, + case lists:member(Tag, Replies) of + true -> ok; + false -> + ct:fail({reply_mismatch,Cnt,Reply,Replies, + byte_size(B), + inet:getopts(Socket, + [sndbuf,recbuf])}) + end, + buffer_size_client(Server, IP, Port, Socket, Cnt+1, T) + after 1313 -> + buffer_size_client(Server, IP, Port, Socket, Cnt, Opts) + end. buffer_size_server(_, _, _, _, _, []) -> ok; buffer_size_server(Client, IP, Port, Socket, Cnt, [Opts|T]) when is_list(Opts) -> receive {Client,setopts,Cnt} -> ok end, - ?line io:format("buffer_size_server Cnt=~w setopts ~p.~n", [Cnt,Opts]), + io:format("buffer_size_server Cnt=~w setopts ~p.~n", [Cnt,Opts]), ok = inet:setopts(Socket, Opts), Client ! {self(),setopts,Cnt}, buffer_size_server(Client, IP, Port, Socket, Cnt+1, T); buffer_size_server(Client, IP, Port, Socket, Cnt, [{B,_}|T]) when is_binary(B) -> - ?line io:format( - "buffer_size_server Cnt=~w expecting size ~w.~n", - [Cnt,size(B)]), + io:format( + "buffer_size_server Cnt=~w expecting size ~w.~n", + [Cnt,size(B)]), Client ! {self(),Cnt, case buffer_size_server_recv(Socket, IP, Port, Cnt) of D when is_binary(D) -> SizeD = byte_size(D), - ?line io:format( - "buffer_size_server Cnt=~w received size ~w.~n", - [Cnt,SizeD]), + io:format( + "buffer_size_server Cnt=~w received size ~w.~n", + [Cnt,SizeD]), case B of D -> correct; @@ -210,9 +217,9 @@ buffer_size_server(Client, IP, Port, {unexpected,D} end; Error -> - ?line io:format( - "buffer_size_server Cnt=~w received error ~w.~n", - [Cnt,Error]), + io:format( + "buffer_size_server Cnt=~w received error ~w.~n", + [Cnt,Error]), Error end}, buffer_size_server(Client, IP, Port, Socket, Cnt+1, T). @@ -235,50 +242,44 @@ buffer_size_server_recv(Socket, IP, Port, Cnt) -> %% OTP-3823 gen_udp:recv does not return address in binary mode %% -binary_passive_recv(suite) -> - []; -binary_passive_recv(doc) -> - ["OTP-3823 gen_udp:recv does not return address in binary mode"]; +%% OTP-3823 gen_udp:recv does not return address in binary mode. binary_passive_recv(Config) when is_list(Config) -> - ?line D1 = "The quick brown fox jumps over a lazy dog", - ?line D2 = list_to_binary(D1), - ?line D3 = ["The quick", <<" brown ">>, "fox jumps ", <<"over ">>, - <<>>, $a, [[], " lazy ", <<"dog">>]], - ?line D2 = iolist_to_binary(D3), - ?line B = D2, - ?line {ok, R} = gen_udp:open(0, [binary, {active, false}]), - ?line {ok, RP} = inet:port(R), - ?line {ok, S} = gen_udp:open(0), - ?line {ok, SP} = inet:port(S), - ?line ok = gen_udp:send(S, localhost, RP, D1), - ?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), - ?line ok = gen_udp:send(S, localhost, RP, D2), - ?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), - ?line ok = gen_udp:send(S, localhost, RP, D3), - ?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), - ?line ok = gen_udp:close(S), - ?line ok = gen_udp:close(R), + D1 = "The quick brown fox jumps over a lazy dog", + D2 = list_to_binary(D1), + D3 = ["The quick", <<" brown ">>, "fox jumps ", <<"over ">>, + <<>>, $a, [[], " lazy ", <<"dog">>]], + D2 = iolist_to_binary(D3), + B = D2, + {ok, R} = gen_udp:open(0, [binary, {active, false}]), + {ok, RP} = inet:port(R), + {ok, S} = gen_udp:open(0), + {ok, SP} = inet:port(S), + ok = gen_udp:send(S, localhost, RP, D1), + {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), + ok = gen_udp:send(S, localhost, RP, D2), + {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), + ok = gen_udp:send(S, localhost, RP, D3), + {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), + ok = gen_udp:close(S), + ok = gen_udp:close(R), ok. %%------------------------------------------------------------- %% OTP-3836 inet_udp crashes when IP-address is larger than 255. -bad_address(suite) -> - []; -bad_address(doc) -> - ["OTP-3836 inet_udp crashes when IP-address is larger than 255."]; +%% OTP-3836 inet_udp crashes when IP-address is larger than 255. bad_address(Config) when is_list(Config) -> - ?line {ok, R} = gen_udp:open(0), - ?line {ok, RP} = inet:port(R), - ?line {ok, S} = gen_udp:open(0), - ?line {ok, _SP} = inet:port(S), - ?line {'EXIT', badarg} = + {ok, R} = gen_udp:open(0), + {ok, RP} = inet:port(R), + {ok, S} = gen_udp:open(0), + {ok, _SP} = inet:port(S), + {'EXIT', badarg} = (catch gen_udp:send(S, {127,0,0,1,0}, RP, "void")), - ?line {'EXIT', badarg} = + {'EXIT', badarg} = (catch gen_udp:send(S, {127,0,0,256}, RP, "void")), - ?line ok = gen_udp:close(S), - ?line ok = gen_udp:close(R), + ok = gen_udp:close(S), + ok = gen_udp:close(R), ok. @@ -297,8 +298,7 @@ bad_address(Config) when is_list(Config) -> %% What happens on the SMP emulator remains to be seen... %% -read_packets(doc) -> - ["OTP-6249 UDP option for number of packet reads."]; +%% OTP-6249 UDP option for number of packet reads. read_packets(Config) when is_list(Config) -> case erlang:system_info(smp_support) of false -> @@ -310,35 +310,35 @@ read_packets(Config) when is_list(Config) -> end. read_packets_1() -> - ?line N1 = 5, - ?line N2 = 7, - ?line {ok,R} = gen_udp:open(0, [{read_packets,N1}]), - ?line {ok,RP} = inet:port(R), - ?line {ok,Node} = start_node(gen_udp_SUITE_read_packets), - ?line Die = make_ref(), - ?line Loop = erlang:spawn_link(fun () -> infinite_loop(Die) end), + N1 = 5, + N2 = 7, + {ok,R} = gen_udp:open(0, [{read_packets,N1}]), + {ok,RP} = inet:port(R), + {ok,Node} = start_node(gen_udp_SUITE_read_packets), + Die = make_ref(), + Loop = erlang:spawn_link(fun () -> infinite_loop(Die) end), %% - ?line Msgs1 = [erlang:integer_to_list(M) || M <- lists:seq(1, N1*3)], - ?line [V1|_] = read_packets_test(R, RP, Msgs1, Node), - ?line {ok,[{read_packets,N1}]} = inet:getopts(R, [read_packets]), + Msgs1 = [erlang:integer_to_list(M) || M <- lists:seq(1, N1*3)], + [V1|_] = read_packets_test(R, RP, Msgs1, Node), + {ok,[{read_packets,N1}]} = inet:getopts(R, [read_packets]), %% - ?line ok = inet:setopts(R, [{read_packets,N2}]), - ?line Msgs2 = [erlang:integer_to_list(M) || M <- lists:seq(1, N2*3)], - ?line [V2|_] = read_packets_test(R, RP, Msgs2, Node), - ?line {ok,[{read_packets,N2}]} = inet:getopts(R, [read_packets]), + ok = inet:setopts(R, [{read_packets,N2}]), + Msgs2 = [erlang:integer_to_list(M) || M <- lists:seq(1, N2*3)], + [V2|_] = read_packets_test(R, RP, Msgs2, Node), + {ok,[{read_packets,N2}]} = inet:getopts(R, [read_packets]), %% - ?line stop_node(Node), - ?line Mref = erlang:monitor(process, Loop), - ?line Loop ! Die, - ?line receive - {'DOWN',Mref,_,_, normal} -> - case {V1,V2} of - {N1,N2} -> - ok; - _ when V1 =/= N1, V2 =/= N2 -> - ok - end - end. + stop_node(Node), + Mref = erlang:monitor(process, Loop), + Loop ! Die, + receive + {'DOWN',Mref,_,_, normal} -> + case {V1,V2} of + {N1,N2} -> + ok; + _ when V1 =/= N1, V2 =/= N2 -> + ok + end + end. infinite_loop(Die) -> receive @@ -406,21 +406,21 @@ read_packets_recv(N) -> read_packets_verify(R, SP, Msg, Trace) -> lists:reverse( - lists:sort(read_packets_verify(R, SP, Msg, Trace, 0))). - + lists:sort(read_packets_verify(R, SP, Msg, Trace, 0))). + read_packets_verify(R, SP, Msgs, [{trace,Self,OutIn,_}|Trace], M) when Self =:= self(), OutIn =:= out; Self =:= self(), OutIn =:= in -> push(M, read_packets_verify(R, SP, Msgs, Trace, 0)); read_packets_verify(R, SP, [Msg|Msgs], - [{trace,Self,'receive',{udp,R,{127,0,0,1},SP,Msg}} - |Trace], M) + [{trace,Self,'receive',{udp,R,{127,0,0,1},SP,Msg}} + |Trace], M) when Self =:= self() -> read_packets_verify(R, SP, Msgs, Trace, M+1); read_packets_verify(_R, _SP, [], [], M) -> push(M, []); read_packets_verify(_R, _SP, Msgs, Trace, M) -> - ?t:fail({read_packets_verify,mismatch,Msgs,Trace,M}). + ct:fail({read_packets_verify,mismatch,Msgs,Trace,M}). push(0, Vs) -> Vs; @@ -437,18 +437,15 @@ flush() -> -open_fd(suite) -> - []; -open_fd(doc) -> - ["Test that the 'fd' option works"]; +%% Test that the 'fd' option works. open_fd(Config) when is_list(Config) -> - Msg = "Det g�r ont n�r knoppar brista. Varf�r skulle annars v�ren tveka?", + Msg = "Det gör ont när knoppar brista. Varför skulle annars våren tveka?", Addr = {127,0,0,1}, {ok,S1} = gen_udp:open(0), {ok,P2} = inet:port(S1), {ok,FD} = prim_inet:getfd(S1), - {error,einval} = gen_udp:open(P2, [inet6, {fd,FD}]), - {ok,S2} = gen_udp:open(P2, [{fd,FD}]), + {error,einval} = gen_udp:open(0, [inet6, {fd,FD}]), + {ok,S2} = gen_udp:open(0, [{fd,FD}]), {ok,S3} = gen_udp:open(0), {ok,P3} = inet:port(S3), ok = gen_udp:send(S3, Addr, P2, Msg), @@ -459,95 +456,337 @@ open_fd(Config) when is_list(Config) -> {udp,S3,Addr,P2,Msg} -> ok after 1000 -> - ?t:fail(io_lib:format("~w", [flush()])) + ct:fail(io_lib:format("~w", [flush()])) end after 1000 -> - ?t:fail(io_lib:format("~w", [flush()])) + ct:fail(io_lib:format("~w", [flush()])) + end. + +active_n(Config) when is_list(Config) -> + N = 3, + S1 = ok(gen_udp:open(0, [{active,N}])), + [{active,N}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,-N}]), + receive + {udp_passive, S1} -> ok + after + 5000 -> + exit({error,udp_passive_failure}) + end, + [{active,false}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,0}]), + receive + {udp_passive, S1} -> ok + after + 5000 -> + exit({error,udp_passive_failure}) + end, + ok = inet:setopts(S1, [{active,32767}]), + {error,einval} = inet:setopts(S1, [{active,1}]), + {error,einval} = inet:setopts(S1, [{active,-32769}]), + ok = inet:setopts(S1, [{active,-32768}]), + receive + {udp_passive, S1} -> ok + after + 5000 -> + exit({error,udp_passive_failure}) + end, + [{active,false}] = ok(inet:getopts(S1, [active])), + ok = inet:setopts(S1, [{active,N}]), + ok = inet:setopts(S1, [{active,true}]), + [{active,true}] = ok(inet:getopts(S1, [active])), + receive + _ -> exit({error,active_n}) + after + 0 -> + ok + end, + ok = inet:setopts(S1, [{active,N}]), + ok = inet:setopts(S1, [{active,once}]), + [{active,once}] = ok(inet:getopts(S1, [active])), + receive + _ -> exit({error,active_n}) + after + 0 -> + ok + end, + {error,einval} = inet:setopts(S1, [{active,32768}]), + ok = inet:setopts(S1, [{active,false}]), + [{active,false}] = ok(inet:getopts(S1, [active])), + S1Port = ok(inet:port(S1)), + S2 = ok(gen_udp:open(0, [{active,N}])), + S2Port = ok(inet:port(S2)), + [{active,N}] = ok(inet:getopts(S2, [active])), + ok = inet:setopts(S1, [{active,N}]), + [{active,N}] = ok(inet:getopts(S1, [active])), + lists:foreach( + fun(I) -> + Msg = "message "++integer_to_list(I), + ok = gen_udp:send(S2, "localhost", S1Port, Msg), + receive + {udp,S1,_,S2Port,Msg} -> + ok = gen_udp:send(S1, "localhost", S2Port, Msg) + after + 5000 -> + exit({error,timeout}) + end, + receive + {udp,S2,_,S1Port,Msg} -> + ok + after + 5000 -> + exit({error,timeout}) + end + end, lists:seq(1,N)), + receive + {udp_passive,S1} -> + [{active,false}] = ok(inet:getopts(S1, [active])) + after + 5000 -> + exit({error,udp_passive}) + end, + receive + {udp_passive,S2} -> + [{active,false}] = ok(inet:getopts(S2, [active])) + after + 5000 -> + exit({error,udp_passive}) + end, + S3 = ok(gen_udp:open(0, [{active,0}])), + receive + {udp_passive,S3} -> + [{active,false}] = ok(inet:getopts(S3, [active])) + after + 5000 -> + exit({error,udp_passive}) + end, + ok = gen_udp:close(S3), + ok = gen_udp:close(S2), + ok = gen_udp:close(S1), + ok. + + +local_basic(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + CFile = local_filename(client), + CAddr = {local,bin_filename(CFile)}, + _ = file:delete(SFile), + _ = file:delete(CFile), + %% + S = ok(gen_udp:open(0, [{ifaddr,{local,SFile}},{active,false}])), + C = ok(gen_udp:open(0, [{ifaddr,{local,CFile}},{active,false}])), + SAddr = ok(inet:sockname(S)), + CAddr = ok(inet:sockname(C)), + local_handshake(S, SAddr, C, CAddr), + ok = gen_udp:close(S), + ok = gen_udp:close(C), + %% + ok = file:delete(SFile), + ok = file:delete(CFile), + ok. + +local_unbound(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + _ = file:delete(SFile), + %% + S = ok(gen_udp:open(0, [{ifaddr,SAddr},{active,false}])), + C = ok(gen_udp:open(0, [local,{active,false}])), + SAddr = ok(inet:sockname(S)), + local_handshake(S, SAddr, C, undefined), + ok = gen_udp:close(S), + ok = gen_udp:close(C), + %% + ok = file:delete(SFile), + ok. + +local_fdopen(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + CFile = local_filename(client), + CAddr = {local,bin_filename(CFile)}, + _ = file:delete(SFile), + _ = file:delete(CFile), + %% + S0 = ok(gen_udp:open(0, [{ifaddr,SAddr},{active,false}])), + C = ok(gen_udp:open(0, [{ifaddr,{local,CFile}},{active,false}])), + SAddr = ok(inet:sockname(S0)), + CAddr = ok(inet:sockname(C)), + Fd = ok(prim_inet:getfd(S0)), + S = ok(gen_udp:open(0, [{fd,Fd},local,{active,false}])), + SAddr = ok(inet:sockname(S)), + local_handshake(S, SAddr, C, CAddr), + ok = gen_udp:close(S), + ok = gen_udp:close(S0), + ok = gen_udp:close(C), + %% + ok = file:delete(SFile), + ok = file:delete(CFile), + ok. + +local_fdopen_unbound(_Config) -> + SFile = local_filename(server), + SAddr = {local,bin_filename(SFile)}, + _ = file:delete(SFile), + %% + S = ok(gen_udp:open(0, [{ifaddr,SAddr},{active,false}])), + C0 = ok(gen_udp:open(0, [local,{active,false}])), + SAddr = ok(inet:sockname(S)), + Fd = ok(prim_inet:getfd(C0)), + C = ok(gen_udp:open(0, [{fd,Fd},local,{active,false}])), + local_handshake(S, SAddr, C, undefined), + ok = gen_udp:close(S), + ok = gen_udp:close(C), + ok = gen_udp:close(C0), + %% + ok = file:delete(SFile), + ok. + +local_abstract(_Config) -> + case os:type() of + {unix,linux} -> + S = ok(gen_udp:open(0, [{ifaddr,{local,<<>>}},{active,false}])), + C = ok(gen_udp:open(0, [{ifaddr,{local,<<>>}},{active,false}])), + {local,_} = SAddr = ok(inet:sockname(S)), + {local,_} = CAddr = ok(inet:sockname(C)), + local_handshake(S, SAddr, C, CAddr), + ok = gen_udp:close(S), + ok = gen_udp:close(C), + ok; + _ -> + {skip,"AF_LOCAL Abstract Addresses only supported on Linux"} end. -% -% Utils -% +local_handshake(S, SAddr, C, CAddr) -> + SData = "9876543210", + CData = "0123456789", + ok = gen_udp:send(C, SAddr, 0, CData), + case ok(gen_tcp:recv(S, 112)) of + {{unspec,<<>>}, 0, CData} when CAddr =:= undefined -> + ok; + {{local,<<>>}, 0, CData} when CAddr =:= undefined -> + ok; + {CAddr, 0, CData} when CAddr =/= undefined -> + ok = gen_udp:send(S, CAddr, 0, SData), + {SAddr, 0, SData} = ok(gen_tcp:recv(C, 112)), + ok + + end. + +%% +%% Utils +%% + start_node(Name) -> Pa = filename:dirname(code:which(?MODULE)), - ?t:start_node(Name, slave, [{args, "-pa " ++ Pa}]). + test_server:start_node(Name, slave, [{args, "-pa " ++ Pa}]). stop_node(Node) -> - ?t:stop_node(Node). + test_server:stop_node(Node). -connect(suite) -> - []; -connect(doc) -> - ["Test that connect/3 has effect"]; +%% Test that connect/3 has effect. connect(Config) when is_list(Config) -> - ?line Addr = {127,0,0,1}, - ?line {ok,S1} = gen_udp:open(0), - ?line {ok,P1} = inet:port(S1), - ?line {ok,S2} = gen_udp:open(0), - ?line ok = inet:setopts(S2, [{active,false}]), - ?line ok = gen_udp:close(S1), - ?line ok = gen_udp:connect(S2, Addr, P1), - ?line ok = gen_udp:send(S2, <<16#deadbeef:32>>), - ?line ok = case gen_udp:recv(S2, 0, 5) of - {error,econnrefused} -> ok; - {error,econnreset} -> ok; - Other -> Other - end, + Addr = {127,0,0,1}, + {ok,S1} = gen_udp:open(0), + {ok,P1} = inet:port(S1), + {ok,S2} = gen_udp:open(0), + ok = inet:setopts(S2, [{active,false}]), + ok = gen_udp:close(S1), + ok = gen_udp:connect(S2, Addr, P1), + ok = gen_udp:send(S2, <<16#deadbeef:32>>), + ok = case gen_udp:recv(S2, 0, 500) of + {error,econnrefused} -> ok; + {error,econnreset} -> ok; + Other -> Other + end, ok. implicit_inet6(Config) when is_list(Config) -> - ?line Host = ok(inet:gethostname()), - ?line - case inet:getaddr(Host, inet6) of - {ok,Addr} -> - ?line implicit_inet6(Host, Addr); - {error,Reason} -> - {skip, - "Can not look up IPv6 address: " - ++atom_to_list(Reason)} - end. + Host = ok(inet:gethostname()), + case inet:getaddr(Host, inet6) of + {ok,Addr} -> + implicit_inet6(Host, Addr); + {error,Reason} -> + {skip, + "Can not look up IPv6 address: " + ++atom_to_list(Reason)} + end. implicit_inet6(Host, Addr) -> - ?line Active = {active,false}, - ?line - case gen_udp:open(0, [inet6,Active]) of - {ok,S1} -> - ?line Loopback = {0,0,0,0,0,0,0,1}, - ?line io:format("~s ~p~n", ["::1",Loopback]), - ?line implicit_inet6(S1, Active, Loopback), - ?line ok = gen_udp:close(S1), - %% - ?line Localhost = "localhost", - ?line Localaddr = ok(inet:getaddr(Localhost, inet6)), - ?line io:format("~s ~p~n", [Localhost,Localaddr]), - ?line S2 = ok(gen_udp:open(0, [{ip,Localaddr},Active])), - ?line implicit_inet6(S2, Active, Localaddr), - ?line ok = gen_udp:close(S2), - %% - ?line io:format("~s ~p~n", [Host,Addr]), - ?line S3 = ok(gen_udp:open(0, [{ifaddr,Addr},Active])), - ?line implicit_inet6(S3, Active, Addr), - ?line ok = gen_udp:close(S3); - _ -> - {skip,"IPv6 not supported"} - end. + Active = {active,false}, + case gen_udp:open(0, [inet6,Active]) of + {ok,S1} -> + Loopback = {0,0,0,0,0,0,0,1}, + io:format("~s ~p~n", ["::1",Loopback]), + implicit_inet6(S1, Active, Loopback), + ok = gen_udp:close(S1), + %% + Localaddr = ok(get_localaddr()), + S2 = ok(gen_udp:open(0, [{ip,Localaddr},Active])), + implicit_inet6(S2, Active, Localaddr), + ok = gen_udp:close(S2), + %% + io:format("~s ~p~n", [Host,Addr]), + S3 = ok(gen_udp:open(0, [{ifaddr,Addr},Active])), + implicit_inet6(S3, Active, Addr), + ok = gen_udp:close(S3); + _ -> + {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. + P1 = ok(inet:port(S1)), + S2 = ok(gen_udp:open(0, [inet6,Active])), + P2 = ok(inet:port(S2)), + ok = gen_udp:connect(S2, Addr, P1), + ok = gen_udp:connect(S1, Addr, P2), + {Addr,P2} = ok(inet:peername(S1)), + {Addr,P1} = ok(inet:peername(S2)), + {Addr,P1} = ok(inet:sockname(S1)), + {Addr,P2} = ok(inet:sockname(S2)), + ok = gen_udp:send(S1, Addr, P2, "ping"), + {Addr,P1,"ping"} = ok(gen_udp:recv(S2, 1024, 1000)), + ok = gen_udp:send(S2, Addr, P1, "pong"), + {Addr,P2,"pong"} = ok(gen_udp:recv(S1, 1024)), + ok = gen_udp:close(S2). + +ok({ok,V}) -> V; +ok(NotOk) -> + try throw(not_ok) + catch + Thrown -> + erlang:raise( + error, {Thrown, NotOk}, tl(erlang:get_stacktrace())) + end. + + +local_filename(Tag) -> + "/tmp/" ?MODULE_STRING "_" ++ os:getpid() ++ "_" ++ atom_to_list(Tag). + +bin_filename(String) -> + unicode:characters_to_binary(String, file:native_name_encoding()). + +delete_local_filenames() -> + _ = + [file:delete(F) || + F <- + filelib:wildcard( + "/tmp/" ?MODULE_STRING "_" ++ os:getpid() ++ "_*")], + ok. + +get_localaddr() -> + get_localaddr(["localhost", "localhost6", "ip6-localhost"]). + +get_localaddr([]) -> + {error, localaddr_not_found}; +get_localaddr([Localhost|Ls]) -> + case inet:getaddr(Localhost, inet6) of + {ok, LocalAddr} -> + io:format("~s ~p~n", [Localhost, LocalAddr]), + {ok, LocalAddr}; + _ -> + get_localaddr(Ls) + end. |