diff options
Diffstat (limited to 'lib/kernel/test/gen_udp_SUITE.erl')
-rw-r--r-- | lib/kernel/test/gen_udp_SUITE.erl | 268 |
1 files changed, 209 insertions, 59 deletions
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index bc2a7cb25b..4419999036 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -58,9 +58,14 @@ t_simple_local_sockaddr_in_send_recv/1, t_simple_link_local_sockaddr_in_send_recv/1, t_simple_local_sockaddr_in6_send_recv/1, - t_simple_link_local_sockaddr_in6_send_recv/1 + t_simple_link_local_sockaddr_in6_send_recv/1, + + otp_18323_opts_processing/1, + otp_18323_open/1 + ]). +-include_lib("kernel/src/inet_int.hrl"). -define(TRY_TC(F), try_tc(F)). @@ -69,7 +74,7 @@ suite() -> {timetrap,{minutes,1}}]. all() -> - %% This is a temporary messure to ensure that we can + %% This is a temporary measure to ensure that we can %% test the socket backend without effecting *all* %% applications on *all* machines. %% This flag is set only for *one* host. @@ -93,10 +98,12 @@ groups() -> {inet_backend_inet, [], inet_backend_inet_cases()}, {inet_backend_socket, [], inet_backend_socket_cases()}, + {recv_and_send_opts, [], recv_and_send_opts_cases()}, {local, [], local_cases()}, {socket_monitor, [], socket_monitor_cases()}, - {sockaddr, [], sockaddr_cases()} + {sockaddr, [], sockaddr_cases()}, + {otp18323, [], otp18323_cases()} ]. inet_backend_default_cases() -> @@ -122,13 +129,19 @@ all_cases() -> reconnect, implicit_inet6, active_n, - recvtos, recvtosttl, recvttl, recvtclass, - sendtos, sendtosttl, sendttl, sendtclass, + {group, recv_and_send_opts}, {group, local}, recv_close, {group, socket_monitor}, otp_17492, - {group, sockaddr} + {group, sockaddr}, + {group, otp18323} + ]. + +recv_and_send_opts_cases() -> + [ + recvtos, recvtosttl, recvttl, recvtclass, + sendtos, sendtosttl, sendttl, sendtclass ]. local_cases() -> @@ -159,6 +172,12 @@ sockaddr_cases() -> t_simple_link_local_sockaddr_in6_send_recv ]. +otp18323_cases() -> + [ + otp_18323_opts_processing, + otp_18323_open + ]. + init_per_suite(Config0) -> @@ -242,6 +261,14 @@ init_per_group(sockaddr = _GroupName, Config) -> ?P("init_per_group(sockaddr) -> 'socket' not configured"), {skip, "esock not configured"} end; +init_per_group(otp18323 = _GroupName, Config) -> + ?P("init_per_group(otp18323) -> inet-drv specific bug(s)"), + case ?IS_SOCKET_BACKEND(Config) of + true -> + {skip, "Inet Drv specific bugs"}; + false -> + ok + end; init_per_group(_GroupName, Config) -> Config. @@ -561,7 +588,8 @@ do_binary_passive_recv(Config) when is_list(Config) -> D2 = iolist_to_binary(D3), B = D2, ?P("open receive socket"), - {ok, R} = ?OPEN(Config, 0, [binary, {active, false}]), + {ok, R} = ?OPEN(Config, 0, [binary, {active, false}, {debug, true}]), + ok = inet:setopts(R, [{debug, false}]), {ok, RP} = inet:port(R), ?P("open send socket"), {ok, S} = ?OPEN(Config, 0), @@ -630,7 +658,7 @@ do_bad_address(Config) when is_list(Config) -> %%------------------------------------------------------------- %% OTP-6249 UDP option for number of packet reads %% -%% Starts a slave node that on command sends a bunch of messages +%% Starts a node that on command sends a bunch of messages %% to our UDP port. The receiving process just receives and %% ignores the incoming messages. %% A tracing process traces the receiving port for @@ -645,39 +673,28 @@ read_packets(Config) when is_list(Config) -> true -> %% We have not (yet) implemented support for %% this option. We accept it but do not use it. - {skip, "Not complient with socket"}; + {skip, "Not compliant with socket"}; false -> ok end end, - Pre = fun() -> - ?P("~w:pre -> try create node", [?FUNCTION_NAME]), - {ok, Node} = start_node(gen_udp_SUITE_read_packets), - ?P("~w:pre -> node created", [?FUNCTION_NAME]), - Node - end, - TC = fun(Node) -> + TC = fun() -> ?P("~w:tc -> begin", [?FUNCTION_NAME]), - Res = do_read_packets(Config, Node), + Res = do_read_packets(Config), ?P("~w:tc -> done", [?FUNCTION_NAME]), Res end, - Post = fun(Node) -> - ?P("~w:post -> try stop node ~p", [?FUNCTION_NAME, Node]), - stop_node(Node), - ?P("~w:post -> done", [?FUNCTION_NAME]), - ok - end, - ?TC_TRY(?FUNCTION_NAME, Cond, Pre, TC, Post). + ?TC_TRY(?FUNCTION_NAME, Cond, TC). -do_read_packets(Config, Node) when is_list(Config) -> +do_read_packets(Config) when is_list(Config) -> N1 = 5, N2 = 1, Msgs = 30000, ?P("open socket (with read-packets: ~p)", [N1]), {ok, R} = ?OPEN(Config, 0, [{read_packets,N1}]), {ok, RP} = inet:port(R), - + ?P("create slave node"), + {ok,Peer,Node} = ?CT_PEER(), %% ?P("perform read-packets test"), {V1, Trace1} = read_packets_test(Config, R, RP, Msgs, Node), @@ -691,7 +708,8 @@ do_read_packets(Config, Node) when is_list(Config) -> ?P("verify read-packets (to ~w)", [N2]), {ok, [{read_packets,N2}]} = inet:getopts(R, [read_packets]), %% - + ?P("stop slave node"), + peer:stop(Peer), ?P("dump trace 1"), dump_terms(Config, "trace1.terms", Trace1), ?P("dump trace 2"), @@ -1142,7 +1160,7 @@ recvtclass(Config) -> sendtos(Config) -> - ?TC_TRY(sendtos, fun() -> do_sendtos(Config) end). + ?TC_TRY(?FUNCTION_NAME, fun() -> do_sendtos(Config) end). do_sendtos(Config) -> test_recv_opts( @@ -1151,7 +1169,7 @@ do_sendtos(Config) -> fun sendtos_ok/2). sendtosttl(Config) -> - ?TC_TRY(sendtosttl, fun() -> do_sendtosttl(Config) end). + ?TC_TRY(?FUNCTION_NAME, fun() -> do_sendtosttl(Config) end). do_sendtosttl(Config) -> test_recv_opts( @@ -1171,7 +1189,7 @@ do_sendttl(Config) -> fun sendttl_ok/2). sendtclass(Config) -> - ?TC_TRY(sendtclass, fun() -> do_sendtclass(Config) end). + ?TC_TRY(?FUNCTION_NAME, fun() -> do_sendtclass(Config) end). do_sendtclass(Config) -> {ok,IFs} = inet:getifaddrs(), @@ -1345,6 +1363,8 @@ test_recv_opts(Config, Family, Spec, TestSend, _OSType, _OSVer) -> %% ?P("send/3: S2 -> S1"), ok = gen_udp:send(S2, {Addr,P1}, <<"abcde">>), + ?SLEEP(100), + ?P("send/4: S1 -> S2"), ok = gen_udp:send(S1, Addr, P2, <<"fghij">>), TestSend andalso @@ -1353,6 +1373,7 @@ test_recv_opts(Config, Family, Spec, TestSend, _OSType, _OSVer) -> "~n ~p", [OptsVals]), case gen_udp:send(S2, Addr, P1, OptsVals, <<"ABCDE">>) of ok -> + ?SLEEP(100), ok; {error, enoprotoopt = Reason1} -> ?SKIPT(?F("send (1) failed: ~p", [Reason1])) @@ -1361,6 +1382,7 @@ test_recv_opts(Config, Family, Spec, TestSend, _OSType, _OSVer) -> "~n ~p", [OptsVals]), case gen_udp:send(S2, {Addr,P1}, OptsVals, <<"12345">>) of ok -> + ?SLEEP(100), ok; {error, enoprotoopt = Reason2} -> ?SKIPT(?F("send (2) failed: ~p", [Reason2])) @@ -1370,6 +1392,8 @@ test_recv_opts(Config, Family, Spec, TestSend, _OSType, _OSVer) -> {ok,{_,P2,OptsVals3, <<"abcde">>}} = gen_udp:recv(S1, 0, Timeout), ?P("S1 recv: " "~n OptsVals3: ~p", [OptsVals3]), + ?SLEEP(100), + verify_sets_eq(OptsVals3, OptsVals2), TestSend andalso begin @@ -1377,10 +1401,13 @@ test_recv_opts(Config, Family, Spec, TestSend, _OSType, _OSVer) -> {ok,{_,P2,OptsVals0,<<"ABCDE">>}} = gen_udp:recv(S1, 0, Timeout), ?P("S1 recv: " "~n OptsVals0: ~p", [OptsVals0]), + ?SLEEP(100), + ?P("try S1 recv"), {ok,{_,P2,OptsVals1,<<"12345">>}} = gen_udp:recv(S1, 0, Timeout), ?P("S1 recv: " "~n OptsVals1: ~p", [OptsVals1]), + ?SLEEP(100), verify_sets_eq(OptsVals0, OptsVals), verify_sets_eq(OptsVals1, OptsVals) end, @@ -1410,14 +1437,21 @@ test_recv_opts(Config, Family, Spec, TestSend, _OSType, _OSVer) -> %% ?P("send/4: S2 -> S1"), ok = gen_udp:send(S2, {Addr,P1}, [], <<"klmno">>), + ?SLEEP(100), + ?P("send/3: S1 -> S2"), ok = gen_udp:send(S1, {Family,{loopback,P2}}, <<"pqrst">>), + ?SLEEP(100), + TestSend andalso begin ?P("send/4: S1 -> S2" "~n ~p", [OptsVals]), - ok = gen_udp:send(S1, {Family,{loopback,P2}}, OptsVals2, <<"PQRST">>) + ok = gen_udp:send(S1, + {Family,{loopback,P2}}, OptsVals2, <<"PQRST">>), + ?SLEEP(100) end, + ?P("try recv data on S1"), {ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout), ?P("await message on S2"), @@ -1660,7 +1694,7 @@ recv_close(Config) when is_list(Config) -> receive {'DOWN', MRef, process, Pid, PreReason} -> %% Make sure id does not die for some other reason... - ?line ct:fail("Unexpected pre close from reader (~p): ~p", + ct:fail("Unexpected pre close from reader (~p): ~p", [Pid, PreReason]) after 5000 -> % Just in case... ok @@ -1674,13 +1708,13 @@ recv_close(Config) when is_list(Config) -> ok; {'DOWN', MRef, process, Pid, PostReason} -> ?P("unexpected reader termination: ~p", [PostReason]), - ?line ct:fail("Unexpected post close from reader (~p): ~p", + ct:fail("Unexpected post close from reader (~p): ~p", [Pid, PostReason]) after 5000 -> ?P("unexpected reader termination timeout"), demonitor(MRef, [flush]), exit(Pid, kill), - ?line ct:fail("Reader (~p) termination timeout", [Pid]) + ct:fail("Reader (~p) termination timeout", [Pid]) end, ?P("done"), ok. @@ -1705,15 +1739,20 @@ do_connect(Config) when is_list(Config) -> ok = inet:setopts(S2, [{active, false}]), ?P("try close first socket"), ok = gen_udp:close(S1), + + %% Test if this helps... + ?P("sleep some"), + ct:sleep({seconds, 5}), + ?P("try connect second socket to: ~p, ~p", [Addr, P1]), ok = gen_udp:connect(S2, Addr, P1), ?P("try send on second socket"), ok = gen_udp:send(S2, <<16#deadbeef:32>>), - ?P("try recv on second socket - expect failure: " - "~n ~p", [inet:info(S2)]), + ?P("try recv on second socket - expect failure when" + "~n Socket Info: ~p", [inet:info(S2)]), ok = case gen_udp:recv(S2, 0, 500) of - {error, econnrefused} -> ok; - {error, econnreset} -> ok; + {error, econnrefused = R} -> ?P("expected failure: ~w", [R]), ok; + {error, econnreset = R} -> ?P("expected failure: ~w", [R]), ok; Other -> ?P("UNEXPECTED failure: ~p:" "~n ~p", [Other, inet:info(S2)]), @@ -1801,9 +1840,9 @@ do_implicit_inet6(Config) -> end. implicit_inet6(Config, Host, Addr) -> - Active = {active,false}, + Active = {active,false}, Loopback = {0,0,0,0,0,0,0,1}, - ?P("try 1 with explit inet6 on loopback"), + ?P("try 1 with explicit inet6 on loopback"), S1 = case ?OPEN(Config, 0, [inet6, Active, {ip, Loopback}]) of {ok, Sock1} -> Sock1; @@ -1814,6 +1853,7 @@ implicit_inet6(Config, Host, Addr) -> end, implicit_inet6(Config, S1, Active, Loopback), ok = gen_udp:close(S1), + %% Localaddr = ok(get_localaddr()), ?P("try 2 on local addr (~p)", [Localaddr]), @@ -1825,6 +1865,7 @@ implicit_inet6(Config, Host, Addr) -> end, implicit_inet6(Config, S2, Active, Localaddr), ok = gen_udp:close(S2), + %% ?P("try 3 on addr ~p (~p)", [Addr, Host]), S3 = case ?OPEN(Config, 0, [{ifaddr, Addr}, Active]) of @@ -1862,16 +1903,43 @@ implicit_inet6(Config, S1, Active, Addr) -> ?P("sockname of \"remote\" socket"), {Addr,P2} = ok(inet:sockname(S2)), ?P("send ping on \"local\" socket (to ~p:~p)", [Addr, P2]), - ok = gen_udp:send(S1, Addr, P2, "ping"), - ?P("recv ping on \"remote\" socket (from ~p:~p)", [Addr, P1]), - {Addr,P1,"ping"} = ok(gen_udp:recv(S2, 1024, 1000)), - ?P("send pong on \"remote\" socket (to ~p:~p)", [Addr, P1]), - ok = gen_udp:send(S2, Addr, P1, "pong"), - ?P("recv ping on \"local\" socket (from ~p:~p)", [Addr, P2]), - {Addr,P2,"pong"} = ok(gen_udp:recv(S1, 1024)), - ?P("close \"remote\" socket"), - ok = gen_udp:close(S2), - ok. + %% On some platforms its allowed to specify address and port + %% (that is; when useing sendto) *even* if the socket is connected + %% (assuming the send destination is the same as connected destination). + %% But on other platforms, e.g. FreeBSD, this is *not* allowed! + %% Linux: + %% EISCONN + %% The connection-mode socket was connected already but a recipient + %% was specified. (Now either this error is returned, or the re- + %% cipient specification is ignored.) + %% FreeBSD: + %% [EISCONN] A destination address was specified and the socket is + %% already connected. + case gen_udp:send(S1, Addr, P2, "ping") of + ok -> + ?P("recv ping on \"remote\" socket (from ~p:~p)", [Addr, P1]), + {Addr,P1,"ping"} = ok(gen_udp:recv(S2, 1024, 1000)), + ?P("send pong on \"remote\" socket (to ~p:~p)", [Addr, P1]), + ok = gen_udp:send(S2, Addr, P1, "pong"), + ?P("recv ping on \"local\" socket (from ~p:~p)", [Addr, P2]), + {Addr,P2,"pong"} = ok(gen_udp:recv(S1, 1024)), + ?P("close \"remote\" socket"), + ok = gen_udp:close(S2), + ok; + {error, eisconn} -> + ?P("socket is connect => *not* allowed to use sendto"), + ok = gen_udp:send(S1, "ping"), + %% Not allowed to specify address *at all* for a connected socket + ?P("recv ping on \"remote\" socket (from ~p:~p)", [Addr, P1]), + {Addr,P1,"ping"} = ok(gen_udp:recv(S2, 1024, 1000)), + ?P("send pong on \"remote\" socket (to ~p:~p)", [Addr, P1]), + ok = gen_udp:send(S2, "pong"), + ?P("recv ping on \"local\" socket (from ~p:~p)", [Addr, P2]), + {Addr,P2,"pong"} = ok(gen_udp:recv(S1, 1024)), + ?P("close \"remote\" socket"), + ok = gen_udp:close(S2), + ok + end. @@ -2793,6 +2861,97 @@ do_simple_sockaddr_send_recv(#{family := _Fam} = SockAddr, _) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Verify that the options [add|drop]_membership do not mess up +%% the options (including 'ip' which could not be added *after*). +%% This just attempts to very that the option processing is ok. +otp_18323_opts_processing(Config) when is_list(Config) -> + ct:timetrap(?MINS(1)), + ?TC_TRY(?FUNCTION_NAME, fun() -> do_otp_18323_opts_processing(Config) end). + +do_otp_18323_opts_processing(_Config) -> + ?P("begin"), + + do_otp_18323_opts_processing_verify( + {add_membership, {{239,1,2,3},{0,0,0,0}}}), + + do_otp_18323_opts_processing_verify( + {drop_membership, {{239,1,2,3},{0,0,0,0}}}), + + ?P("done"), + ok. + +do_otp_18323_opts_processing_verify(MembershipOpt) -> + Port = 4321, + RecBuf = 123456, + Active = 10, + IP = {1,2,3,4}, + Opts = [binary, MembershipOpt, {ip, IP}, {active, Active}], + + case inet:udp_options([{port, Port}, {recbuf, RecBuf} | Opts], inet_udp) of + {ok, #udp_opts{ifaddr = IP, + port = Port, + opts = SockOpts}} -> + ?P("Processed Socket Options: " + "~n IfAddr: ~p" + "~n Port: ~p" + "~n Sock Opts: ~p", [IP, Port, SockOpts]), + %% Check that the recbuf and mode options are as expected + %% The option 'binary' is shorthand for {mode, binary} + {value, {recbuf, RecBuf}} = lists:keysearch(recbuf, 1, SockOpts), + {value, {mode, binary}} = lists:keysearch(mode, 1, SockOpts), + {value, {active, Active}} = lists:keysearch(active, 1, SockOpts), + ok; + {error, Reason} -> + exit(?F("Failed processing options: ~p", [Reason])) + end. + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Verify that the options [add|drop]_membership do not mess up +%% the options (including 'ip' which could not be added *after*). +otp_18323_open(Config) when is_list(Config) -> + ct:timetrap(?MINS(1)), + Pre = fun() -> + {ok, Addr} = ?LIB:which_local_addr(inet), + #{local_addr => Addr} + end, + Case = fun(State) -> do_otp_18323_open(State) end, + Post = fun(_) -> ok end, + ?TC_TRY(?FUNCTION_NAME, Pre, Case, Post). + +do_otp_18323_open(#{local_addr := Addr}) -> + ?P("begin"), + + ROpts = [binary, + {add_membership, {Addr,{0,0,0,0}}}, + {ip, Addr}, + {active,false}, + {debug, true}], + SOpts = [{reuseaddr, true}, binary], + + ?P("create received socket"), + {ok, R} = gen_udp:open(0, ROpts), + ?P("extract received socket port"), + {ok, RPort} = inet:port(R), + + ?P("create sender socket"), + {ok, S} = gen_udp:open(0, SOpts), + + ?P("send to receiver (at port ~w)", [RPort]), + ok = gen_udp:send(S, Addr, RPort, <<"aaaaa">>), + + ?P("attempt to receive data on specified format binary)"), + {ok, {_,_,<<"aaaaa">>}} = gen_udp:recv(R, 0, 200), + + ?P("done"), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ok({ok,V}) -> V; ok(NotOk) -> try throw(not_ok) @@ -2897,14 +3056,5 @@ pi(Item) -> %% Utils %% -start_node(Name) -> - ?START_NODE(Name, []). - -stop_node(Node) -> - ?STOP_NODE(Node). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - open_failed_str(Reason) -> ?F("Open failed: ~w", [Reason]). |