aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test/gen_udp_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test/gen_udp_SUITE.erl')
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl302
1 files changed, 236 insertions, 66 deletions
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index aa616d43d6..af9985de45 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,8 +34,9 @@
-export([init_per_testcase/2, end_per_testcase/2]).
-export([send_to_closed/1, active_n/1,
- buffer_size/1, binary_passive_recv/1, bad_address/1,
+ buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
+ recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
local_basic/1, local_unbound/1,
local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
@@ -44,9 +45,10 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [send_to_closed, buffer_size, binary_passive_recv,
+ [send_to_closed, buffer_size, binary_passive_recv, max_buffer_size,
bad_address, read_packets, open_fd, connect,
implicit_inet6, active_n,
+ recvtos, recvtosttl, recvttl, recvtclass,
{group, local}].
groups() ->
@@ -237,6 +239,14 @@ buffer_size_server_recv(Socket, IP, Port, Cnt) ->
end.
+%%-------------------------------------------------------------
+%% OTP-15206: Keep buffer small for udp
+%%-------------------------------------------------------------
+max_buffer_size(Config) when is_list(Config) ->
+ {ok, Socket} = gen_udp:open(0, [binary]),
+ ok = inet:setopts(Socket,[{recbuf, 1 bsl 20}]),
+ {ok, [{buffer, 65536}]} = inet:getopts(Socket,[buffer]),
+ gen_udp:close(Socket).
%%-------------------------------------------------------------
%% OTP-3823 gen_udp:recv does not return address in binary mode
@@ -288,58 +298,56 @@ bad_address(Config) when is_list(Config) ->
%%
%% Starts a slave node that on command sends a bunch of messages
%% to our UDP port. The receiving process just receives and
-%% ignores the incoming messages, but counts them.
-%% A tracing process traces the receiving process for
-%% 'receive' and scheduling events. From the trace,
-%% message contents is verified; and, how many messages
-%% are received per in/out scheduling, which should be
-%% the same as the read_packets parameter.
-%%
-%% What happens on the SMP emulator remains to be seen...
-%%
+%% ignores the incoming messages.
+%% A tracing process traces the receiving port for
+%% 'send' and scheduling events. From the trace,
+%% how many messages are received per in/out scheduling,
+%% which should never be more than the read_packet parameter.
%% OTP-6249 UDP option for number of packet reads.
read_packets(Config) when is_list(Config) ->
- case erlang:system_info(smp_support) of
- false ->
- read_packets_1();
- true ->
- %% We would need some new sort of tracing to test this
- %% option reliably in an SMP emulator.
- {skip,"SMP emulator"}
- end.
-
-read_packets_1() ->
N1 = 5,
- N2 = 7,
+ N2 = 1,
+ Msgs = 30000,
{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),
%%
- Msgs1 = [erlang:integer_to_list(M) || M <- lists:seq(1, N1*3)],
- [V1|_] = read_packets_test(R, RP, Msgs1, Node),
+ {V1, Trace1} = read_packets_test(R, RP, Msgs, Node),
{ok,[{read_packets,N1}]} = 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),
+ {V2, Trace2} = read_packets_test(R, RP, Msgs, Node),
{ok,[{read_packets,N2}]} = inet:getopts(R, [read_packets]),
%%
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
+ ct:log("N1=~p, V1=~p vs N2=~p, V2=~p",[N1,V1,N2,V2]),
+
+ dump_terms(Config, "trace1.terms", Trace2),
+ dump_terms(Config, "trace2.terms", Trace2),
+
+ %% Because of the inherit racy-ness of the feature it is
+ %% hard to test that it behaves correctly.
+ %% Right now (OTP 21) a port task takes 5% of the
+ %% allotted port task reductions to execute, so
+ %% the max number of executions a port is allowed to
+ %% do before being re-scheduled is N * 20
+
+ if
+ V1 > (N1 * 20) ->
+ ct:fail("Got ~p msgs, max was ~p", [V1, N1]);
+ V2 > (N2 * 20) ->
+ ct:fail("Got ~p msgs, max was ~p", [V2, N2]);
+ true ->
+ ok
end.
+dump_terms(Config, Name, Terms) ->
+ FName = filename:join(proplists:get_value(priv_dir, Config),Name),
+ file:write_file(FName, term_to_binary(Terms)),
+ ct:log("Logged terms to ~s",[FName]).
+
infinite_loop(Die) ->
receive
Die ->
@@ -350,7 +358,6 @@ infinite_loop(Die) ->
end.
read_packets_test(R, RP, Msgs, Node) ->
- Len = length(Msgs),
Receiver = self(),
Tracer =
spawn_link(
@@ -375,24 +382,24 @@ read_packets_test(R, RP, Msgs, Node) ->
[link,{priority,high}]),
receive
{Sender,{port,SP}} ->
- erlang:trace(self(), true,
- [running,'receive',{tracer,Tracer}]),
+ erlang:trace(R, true,
+ [running_ports,'send',{tracer,Tracer}]),
erlang:yield(),
Sender ! {Receiver,go},
- read_packets_recv(Len),
- erlang:trace(self(), false, [all]),
+ read_packets_recv(Msgs),
+ erlang:trace(R, false, [all]),
Tracer ! {Receiver,get_trace},
receive
{Tracer,{trace,Trace}} ->
- read_packets_verify(R, SP, Msgs, Trace)
+ {read_packets_verify(R, SP, Trace), Trace}
end
end.
-read_packets_send(S, RP, [Msg|Msgs]) ->
- ok = gen_udp:send(S, localhost, RP, Msg),
- read_packets_send(S, RP, Msgs);
-read_packets_send(_S, _RP, []) ->
- ok.
+read_packets_send(_S, _RP, 0) ->
+ ok;
+read_packets_send(S, RP, Msgs) ->
+ ok = gen_udp:send(S, localhost, RP, "UDP FLOOOOOOD"),
+ read_packets_send(S, RP, Msgs - 1).
read_packets_recv(0) ->
ok;
@@ -404,23 +411,24 @@ read_packets_recv(N) ->
timeout
end.
-read_packets_verify(R, SP, Msg, Trace) ->
- lists:reverse(
- 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)
+read_packets_verify(R, SP, Trace) ->
+ [Max | _] = Pkts = lists:reverse(lists:sort(read_packets_verify(R, SP, Trace, 0))),
+ ct:pal("~p",[lists:sublist(Pkts,10)]),
+ Max.
+
+read_packets_verify(R, SP, [{trace,R,OutIn,_}|Trace], M)
+ when OutIn =:= out; OutIn =:= in ->
+ push(M, read_packets_verify(R, SP, Trace, 0));
+read_packets_verify(R, SP, [{trace, R,'receive',timeout}|Trace], M) ->
+ push(M, read_packets_verify(R, SP, Trace, 0));
+read_packets_verify(R, SP,
+ [{trace,R,'send',{udp,R,{127,0,0,1},SP,_Msg}, Self} | Trace], M)
when Self =:= self() ->
- read_packets_verify(R, SP, Msgs, Trace, M+1);
-read_packets_verify(_R, _SP, [], [], M) ->
+ read_packets_verify(R, SP, Trace, M+1);
+read_packets_verify(_R, _SP, [], M) ->
push(M, []);
-read_packets_verify(_R, _SP, Msgs, Trace, M) ->
- ct:fail({read_packets_verify,mismatch,Msgs,Trace,M}).
+read_packets_verify(_R, _SP, Trace, M) ->
+ ct:fail({read_packets_verify,mismatch,Trace,M}).
push(0, Vs) ->
Vs;
@@ -566,6 +574,168 @@ active_n(Config) when is_list(Config) ->
ok.
+
+recvtos(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2).
+
+recvtosttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end).
+
+recvttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_recv_opts(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2);
+ [] ->
+ {skip,ipv6_not_supported,IFs}
+ end.
+
+%% These version numbers are just above the highest noted in daily tests
+%% where the test fails for a plausible reason, that is the lowest
+%% where we can expect that the test mighe succeed, so
+%% skip on platforms lower than this.
+%%
+%% On newer versions it might be fixed, but we'll see about that
+%% when machines with newer versions gets installed...
+%% If the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+%% Or maybe we should change to only test on known good platforms?
+
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_recv_opts(Family, Spec, OSFilter) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_recv_opts(Family, Spec, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_recv_opts(Family, Spec, _OSType, _OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ TrueRecvOpts_OptsVals = TrueRecvOpts ++ OptsVals,
+ Addr =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ {ok,S1} =
+ gen_udp:open(0, [Family,binary,{active,false}|TrueRecvOpts]),
+ {ok,P1} = inet:port(S1),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, TrueRecvOpts_OptsVals),
+ {ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts),
+ %%
+ {ok,S2} =
+ gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]),
+ {ok,P2} = inet:port(S2),
+ {ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts),
+ OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts,
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"abcde">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"fghij">>),
+ {ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout),
+ verify_sets_eq(OptsVals3, OptsVals2),
+ receive
+ {udp,S2,_,P1,<<"fghij">>} ->
+ ok;
+ Other1 ->
+ exit({unexpected,Other1})
+ after Timeout ->
+ exit(timeout)
+ end,
+ %%
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S2, TrueRecvOpts),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"klmno">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>),
+ {ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout),
+ receive
+ {udp,S2,_,P1,OptsVals4,<<"pqrst">>} ->
+ verify_sets_eq(OptsVals4, OptsVals);
+ Other2 ->
+ exit({unexpected,Other2})
+ after Timeout ->
+ exit(timeout)
+ end,
+ ok = gen_udp:close(S1),
+ ok = gen_udp:close(S2),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+verify_sets_eq(L1, L2) ->
+ L = lists:sort(L1),
+ case lists:sort(L2) of
+ L ->
+ ok;
+ _ ->
+ exit({sets_neq,L1,L2})
+ end.
+
+
local_basic(_Config) ->
SFile = local_filename(server),
SAddr = {local,bin_filename(SFile)},
@@ -757,9 +927,9 @@ ok({ok,V}) -> V;
ok(NotOk) ->
try throw(not_ok)
catch
- Thrown ->
+ throw:Thrown:Stacktrace ->
erlang:raise(
- error, {Thrown, NotOk}, tl(erlang:get_stacktrace()))
+ error, {Thrown, NotOk}, tl(Stacktrace))
end.