diff options
author | Anders Svensson <[email protected]> | 2015-08-14 00:18:00 +0200 |
---|---|---|
committer | Anders Svensson <[email protected]> | 2015-08-14 00:18:00 +0200 |
commit | 5dc6f0ba7001e4f5da6e2858996198539495daf3 (patch) | |
tree | 223f56cd383e988118525308ada874e34e71ba45 | |
parent | ed6f4e7a855aad6c04cc180f48b1600ce6ade0f1 (diff) | |
parent | 8c5d719afaeae0c9cfa1079c0de5452f8bdc837b (diff) | |
download | otp-5dc6f0ba7001e4f5da6e2858996198539495daf3.tar.gz otp-5dc6f0ba7001e4f5da6e2858996198539495daf3.tar.bz2 otp-5dc6f0ba7001e4f5da6e2858996198539495daf3.zip |
Merge branch 'maint'
25 files changed, 281 insertions, 173 deletions
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index 1e1206aa2d..47247bc2ff 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -795,14 +795,6 @@ Messages larger than the specified number of bytes are discarded.</p> Defaults to <c>16777215</c>, the maximum value of the 24-bit Message Length field in a Diameter Header.</p> -<warning> -<p> -This option should be set to as low a value as is sufficient for the -Diameter applications and peers in question, since decoding incoming -messages from a malicious peer can otherwise generate significant -load.</p> -</warning> - </item> <tag><c>{restrict_connections, false @@ -1232,9 +1224,7 @@ is not the length of the message in question, as received over the transport interface documented in &man_transport;.</p> <p> -If <c>exit</c> then a warning report is emitted and the parent of the -transport process in question exits, which causes the transport -process itself to exit as described in &man_transport;. +If <c>exit</c> then the transport process in question exits. If <c>handle</c> then the message is processed as usual, a resulting &app_handle_request; or &app_handle_answer; callback (if one takes place) indicating the <c>5015</c> error (DIAMETER_INVALID_MESSAGE_LENGTH). diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml index 299d4093da..2953de95d1 100644 --- a/lib/diameter/doc/src/notes.xml +++ b/lib/diameter/doc/src/notes.xml @@ -43,6 +43,65 @@ first.</p> <!-- ===================================================================== --> +<section><title>diameter 1.11</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Don't report 5005 (DIAMETER_AVP_MISSING) errors + unnecessarily.</p> + <p> + An AVP whose decode failed was reported as missing, + despite having been reported with another error as a + consequence of the failure.</p> + <p> + Own Id: OTP-12871</p> + </item> + <item> + <p> + Fix relay encode of nested, Grouped AVPs.</p> + <p> + A fault in OTP-12475 caused encode to fail if the first + AVP in a Grouped AVP was itself Grouped.</p> + <p> + Own Id: OTP-12879 Aux Id: OTP-12475 </p> + </item> + <item> + <p> + Improve decode performance.</p> + <p> + The time required to decode a message increased + quadratically with the number of AVPs in the worst case, + leading to extremely long execution times.</p> + <p> + Own Id: OTP-12891</p> + </item> + <item> + <p> + Match acceptable peer addresses case insensitively.</p> + <p> + Regular expressions passed in an 'accept' tuple to + diameter_tcp or diameter_sctp inappropriately matched + case.</p> + <p> + Own Id: OTP-12902</p> + </item> + <item> + <p> + Improve watchdog and statistics performance.</p> + <p> + Inefficient use of timers contributed to poor performance + at high load, as did ordering of the table statistics are + written to.</p> + <p> + Own Id: OTP-12912</p> + </item> + </list> + </section> + +<!-- ===================================================================== --> + <section><title>diameter 1.10</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -134,7 +193,7 @@ first.</p> <item> <p> Change license text from Erlang Public License to Apache - Public License v2</p> + Public License v2.</p> <p> Own Id: OTP-12845</p> </item> diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl index a43ab4edb2..5624ee6626 100644 --- a/lib/diameter/include/diameter_gen.hrl +++ b/lib/diameter/include/diameter_gen.hrl @@ -186,9 +186,10 @@ decode_avps(Name, Recs) -> = lists:foldl(fun(T,A) -> decode(Name, T, A) end, {[], {newrec(Name), []}}, Recs), - {Rec, Avps, Failed ++ missing(Rec, Name)}. -%% Append 5005 errors so that a 5014 for the same AVP will take -%% precedence in a Result-Code/Failed-AVP setting. + {Rec, Avps, Failed ++ missing(Rec, Name, Failed)}. +%% Append 5005 errors so that errors are reported in the order +%% encountered. Failed-AVP should typically contain the first +%% encountered error accordg to the RFC. newrec(Name) -> '#new-'(name2rec(Name)). @@ -201,20 +202,36 @@ newrec(Name) -> %% Failed-AVP AVP SHOULD be included in the message. The Failed-AVP %% AVP MUST contain an example of the missing AVP complete with the %% Vendor-Id if applicable. The value field of the missing AVP -%% should be of correct minimum length and contain zeroes. - -missing(Rec, Name) -> - [{5005, empty_avp(F)} || F <- '#info-'(element(1, Rec), fields), - A <- [avp_arity(Name, F)], - false <- [have_arity(A, '#get-'(F, Rec))]]. +%% should be of correct minimum length and contain zeros. + +missing(Rec, Name, Failed) -> + Avps = lists:foldl(fun({_, #diameter_avp{code = C, vendor_id = V}}, A) -> + sets:add_element({C,V}, A) + end, + sets:new(), + Failed), + [{5005, A} || F <- '#info-'(element(1, Rec), fields), + not has_arity(avp_arity(Name, F), '#get-'(F, Rec)), + #diameter_avp{code = C, vendor_id = V} + = A <- [empty_avp(F)], + not sets:is_element({C,V}, Avps)]. %% Maximum arities have already been checked in building the record. -have_arity({Min, _}, L) -> - Min =< length(L); -have_arity(N, V) -> +has_arity({Min, _}, L) -> + has_prefix(Min, L); +has_arity(N, V) -> N /= 1 orelse V /= undefined. +%% Compare a non-negative integer and the length of a list without +%% computing the length. +has_prefix(0, _) -> + true; +has_prefix(_, []) -> + false; +has_prefix(N, L) -> + has_prefix(N-1, tl(L)). + %% empty_avp/1 empty_avp(Name) -> @@ -608,14 +625,17 @@ pack(undefined, 1, FieldName, Avp, Acc) -> %% AVP MUST be included and contain a copy of the first instance of %% the offending AVP that exceeded the maximum number of occurrences %% + pack(_, 1, _, Avp, {Rec, Failed}) -> {Rec, [{5009, Avp} | Failed]}; -pack(L, {_, Max}, _, Avp, {Rec, Failed}) - when length(L) == Max -> - {Rec, [{5009, Avp} | Failed]}; - -pack(L, _, FieldName, Avp, Acc) -> - p(FieldName, fun(V) -> [V|L] end, Avp, Acc). +pack(L, {_, Max}, FieldName, Avp, Acc) -> + case '*' /= Max andalso has_prefix(Max, L) of + true -> + {Rec, Failed} = Acc, + {Rec, [{5009, Avp} | Failed]}; + false -> + p(FieldName, fun(V) -> [V|L] end, Avp, Acc) + end. %% p/4 diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 34276a1674..bcdc5b3005 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -657,16 +657,23 @@ split_data(Bin, Len) -> %% The normal case here is data as an #diameter_avp{} list or an %% iolist, which are the cases that generated codec modules use. The -%% other case is as a convenience in the relay case in which the +%% other cases are a convenience in the relay case in which the %% dictionary doesn't know about specific AVP's. -%% Grouped AVP whose components need packing ... -pack_avp([#diameter_avp{} = A | Avps]) -> - pack_avp(A#diameter_avp{data = Avps}); -pack_avp(#diameter_avp{data = [#diameter_avp{} | _] = Avps} = A) -> - pack_avp(A#diameter_avp{data = encode_avps(Avps)}); +%% Decoded Grouped AVP with decoded components: ignore components +%% since they're already encoded in the Grouped AVP. +pack_avp([#diameter_avp{} = Grouped | _Components]) -> + pack_avp(Grouped); -%% ... data as a type/value tuple ... +%% Grouped AVP whose components need packing. It's intentional that +%% this isn't equivalent to [Grouped | Components]: here the +%% components need to be encoded before wrapping with the Grouped AVP, +%% and the list is flat, nesting being accomplished in the data +%% fields. +pack_avp(#diameter_avp{data = [#diameter_avp{} | _] = Components} = Grouped) -> + pack_avp(Grouped#diameter_avp{data = encode_avps(Components)}); + +%% Data as a type/value tuple ... pack_avp(#diameter_avp{data = {Type, Value}} = A) when is_atom(Type) -> pack_avp(A#diameter_avp{data = diameter_types:Type(encode, Value)}); diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 5ae4ff1f46..b7d8345b6c 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -38,8 +38,7 @@ -module(diameter_config). -behaviour(gen_server). --compile({no_auto_import, [monitor/2, now/0]}). --import(diameter_lib, [now/0]). +-compile({no_auto_import, [monitor/2]}). -export([start_service/2, stop_service/1, @@ -70,7 +69,7 @@ -include("diameter_internal.hrl"). %% Server state. --record(state, {id = now()}). +-record(state, {id = diameter_lib:now()}). %% Registered name of the server. -define(SERVER, ?MODULE). diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl index b5b37dcf62..43b0ca24ab 100644 --- a/lib/diameter/src/base/diameter_lib.erl +++ b/lib/diameter/src/base/diameter_lib.erl @@ -103,32 +103,18 @@ fmt(T) -> %% # now/0 %% --------------------------------------------------------------------------- --type timestamp() :: {non_neg_integer(), 0..999999, 0..999999}. --type now() :: integer() %% monotonic time - | timestamp(). - -spec now() - -> now(). - -%% Use monotonic time if it exists, fall back to erlang:now() -%% otherwise. + -> integer(). now() -> - try - erlang:monotonic_time() - catch - error: undef -> erlang:now() - end. + erlang:monotonic_time(). %% --------------------------------------------------------------------------- %% # timestamp/1 %% --------------------------------------------------------------------------- --spec timestamp(NowT :: now()) - -> timestamp(). - -timestamp({_,_,_} = T) -> %% erlang:now() - T; +-spec timestamp(integer()) + -> erlang:timestamp(). timestamp(MonoT) -> %% monotonic time MicroSecs = monotonic_to_microseconds(MonoT + erlang:time_offset()), @@ -142,30 +128,27 @@ monotonic_to_microseconds(MonoT) -> %% # now_diff/1 %% --------------------------------------------------------------------------- --spec now_diff(NowT :: now()) +-spec now_diff(T0 :: integer()) -> {Hours, Mins, Secs, MicroSecs} when Hours :: non_neg_integer(), Mins :: 0..59, Secs :: 0..59, MicroSecs :: 0..999999. -%% Return timer:now_diff(now(), NowT) as an {H, M, S, MicroS} tuple -%% instead of as integer microseconds. +%% Return time difference as an {H, M, S, MicroS} tuple instead of as +%% integer microseconds. -now_diff(Time) -> - time(micro_diff(Time)). +now_diff(T0) -> + time(micro_diff(T0)). %% --------------------------------------------------------------------------- %% # micro_diff/1 %% --------------------------------------------------------------------------- --spec micro_diff(NowT :: now()) +-spec micro_diff(T0 :: integer()) -> MicroSecs when MicroSecs :: non_neg_integer(). -micro_diff({_,_,_} = T0) -> - timer:now_diff(erlang:now(), T0); - micro_diff(T0) -> %% monotonic time monotonic_to_microseconds(erlang:monotonic_time() - T0). @@ -173,16 +156,12 @@ micro_diff(T0) -> %% monotonic time %% # micro_diff/2 %% --------------------------------------------------------------------------- --spec micro_diff(T1 :: now(), T0 :: now()) +-spec micro_diff(T1 :: integer(), T0 :: integer()) -> MicroSecs when MicroSecs :: non_neg_integer(). -micro_diff(T1, T0) - when is_integer(T1), is_integer(T0) -> %% monotonic time - monotonic_to_microseconds(T1 - T0); - -micro_diff(T1, T0) -> %% at least one erlang:now() - timer:now_diff(timestamp(T1), timestamp(T0)). +micro_diff(T1, T0) -> %% monotonic time + monotonic_to_microseconds(T1 - T0). %% --------------------------------------------------------------------------- %% # time/1 @@ -190,19 +169,13 @@ micro_diff(T1, T0) -> %% at least one erlang:now() %% Return an elapsed time as an {H, M, S, MicroS} tuple. %% --------------------------------------------------------------------------- --spec time(NowT | Diff) +-spec time(Diff :: non_neg_integer()) -> {Hours, Mins, Secs, MicroSecs} - when NowT :: timestamp(), - Diff :: non_neg_integer(), - Hours :: non_neg_integer(), + when Hours :: non_neg_integer(), Mins :: 0..59, Secs :: 0..59, MicroSecs :: 0..999999. -time({_,_,_} = NowT) -> %% time of day - %% 24 hours = 24*60*60*1000000 = 86400000000 microsec - time(timer:now_diff(NowT, {0,0,0}) rem 86400000000); - time(Micro) -> %% elapsed time Seconds = Micro div 1000000, H = Seconds div 3600, @@ -215,7 +188,7 @@ time(Micro) -> %% elapsed time %% --------------------------------------------------------------------------- -spec seed() - -> {timestamp(), {integer(), integer(), integer()}}. + -> {erlang:timestamp(), {integer(), integer(), integer()}}. %% Return an argument for random:seed/1. @@ -225,9 +198,6 @@ seed() -> %% seed/1 -seed({_,_,_} = T) -> - T; - seed(T) -> %% monotonic time {erlang:phash2(node()), T, erlang:unique_integer()}. diff --git a/lib/diameter/src/base/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl index acec91c43f..2759f17e64 100644 --- a/lib/diameter/src/base/diameter_peer.erl +++ b/lib/diameter/src/base/diameter_peer.erl @@ -21,9 +21,6 @@ -module(diameter_peer). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - %% Interface towards transport modules ... -export([recv/2, up/1, @@ -60,7 +57,7 @@ -define(SERVER, ?MODULE). %% Server state. --record(state, {id = now()}). +-record(state, {id = diameter_lib:now()}). %% Default transport_module/config. -define(DEFAULT_TMOD, diameter_tcp). diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl index f5e04d3eae..2b23183d18 100644 --- a/lib/diameter/src/base/diameter_peer_fsm.erl +++ b/lib/diameter/src/base/diameter_peer_fsm.erl @@ -315,7 +315,7 @@ handle_info(T, #state{} = State) -> ?LOG(stop, Reason), {stop, {shutdown, Reason}, State}; stop -> - ?LOG(stop, T), + ?LOG(stop, truncate(T)), {stop, {shutdown, T}, State} catch exit: {diameter_codec, encode, T} = Reason -> @@ -348,6 +348,11 @@ code_change(_, State, _) -> %% --------------------------------------------------------------------------- %% --------------------------------------------------------------------------- +truncate({'DOWN' = T, _, process, Pid, _}) -> + {T, Pid}; +truncate(T) -> + T. + putr(Key, Val) -> put({?MODULE, Key}, Val). diff --git a/lib/diameter/src/base/diameter_reg.erl b/lib/diameter/src/base/diameter_reg.erl index ce29baae45..7f198080ba 100644 --- a/lib/diameter/src/base/diameter_reg.erl +++ b/lib/diameter/src/base/diameter_reg.erl @@ -25,8 +25,7 @@ -module(diameter_reg). -behaviour(gen_server). --compile({no_auto_import, [monitor/2, now/0]}). --import(diameter_lib, [now/0]). +-compile({no_auto_import, [monitor/2]}). -export([add/1, add_new/1, @@ -68,7 +67,7 @@ %% Table entry containing the Term -> Pid mapping. -define(MAPPING(Term, Pid), {Term, Pid}). --record(state, {id = now(), +-record(state, {id = diameter_lib:now(), q = []}). %% [{From, Pat}] %% =========================================================================== diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 5cb7fa5abe..e47b975768 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -25,9 +25,6 @@ -module(diameter_service). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - %% towards diameter_service_sup -export([start_link/1]). @@ -115,7 +112,7 @@ %% to determine whether or not we need to call the process for a %% pick_peer callback in the statefull case. -record(state, - {id = now(), + {id = diameter_lib:now(), service_name :: diameter:service_name(), %% key in ?STATE_TABLE service :: #diameter_service{}, watchdogT = ets_new(watchdogs) %% #watchdog{} at start @@ -144,7 +141,7 @@ ref :: match(reference()), %% key into diameter_config options :: match([diameter:transport_opt()]),%% from start_transport state = ?WD_INITIAL :: match(wd_state()), - started = now(), %% at process start + started = diameter_lib:now(),%% at process start peer = false :: match(boolean() | pid())}). %% true at accepted, pid() at okay/reopen @@ -154,7 +151,7 @@ {pid :: pid(), apps :: [{0..16#FFFFFFFF, diameter:app_alias()}], %% {Id, Alias} caps :: #diameter_caps{}, - started = now(), %% at process start + started = diameter_lib:now(), %% at process start watchdog :: pid()}). %% key into watchdogT %% --------------------------------------------------------------------------- diff --git a/lib/diameter/src/base/diameter_stats.erl b/lib/diameter/src/base/diameter_stats.erl index 83e562e7fe..8c10464e98 100644 --- a/lib/diameter/src/base/diameter_stats.erl +++ b/lib/diameter/src/base/diameter_stats.erl @@ -25,9 +25,6 @@ -module(diameter_stats). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - -export([reg/2, reg/1, incr/3, incr/1, read/1, @@ -61,7 +58,7 @@ -define(SERVER, ?MODULE). %% Server state. --record(state, {id = now()}). +-record(state, {id = diameter_lib:now()}). -type counter() :: any(). -type ref() :: any(). @@ -143,9 +140,14 @@ read(Refs, B) -> L. to_refdict(L) -> - lists:foldl(fun({{C,R}, N}, D) -> orddict:append(R, {C,N}, D) end, - orddict:new(), - L). + lists:foldl(fun append/2, orddict:new(), L). + +%% Order both references and counters in the returned list. +append({{Ctr, Ref}, N}, Dict) -> + orddict:update(Ref, + fun(D) -> orddict:store(Ctr, N, D) end, + [{Ctr, N}], + Dict). %% --------------------------------------------------------------------------- %% # sum(Refs) @@ -221,7 +223,7 @@ uptime() -> %% ---------------------------------------------------------- init([]) -> - ets:new(?TABLE, [named_table, ordered_set, public]), + ets:new(?TABLE, [named_table, set, public, {write_concurrency, true}]), {ok, #state{}}. %% ---------------------------------------------------------- diff --git a/lib/diameter/src/base/diameter_sync.erl b/lib/diameter/src/base/diameter_sync.erl index 3309224399..7fb6888e21 100644 --- a/lib/diameter/src/base/diameter_sync.erl +++ b/lib/diameter/src/base/diameter_sync.erl @@ -28,9 +28,6 @@ -module(diameter_sync). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - -export([call/4, call/5, cast/4, cast/5, carp/1, carp/2]). @@ -73,7 +70,7 @@ %% Server state. -record(state, - {time = now(), + {time = diameter_lib:now(), pending = 0 :: non_neg_integer(), %% outstanding requests monitor = new() :: ets:tid(), %% MonitorRef -> {Name, From} queue = new() :: ets:tid()}). %% Name -> queue of {Pid, Ref} diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index c6d0a0b6ed..3c0d8f6f6e 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -66,7 +66,9 @@ %% end PCB parent = self() :: pid(), %% service process transport :: pid() | undefined, %% peer_fsm process - tref :: reference(), %% reference for current watchdog timer + tref :: reference() %% reference for current watchdog timer + | integer() %% monotonic time + | undefined, dictionary :: module(), %% common dictionary receive_data :: term(), %% term passed into diameter_service with incoming message @@ -94,7 +96,7 @@ start({_,_} = Type, T) -> Ack = make_ref(), {ok, Pid} = diameter_watchdog_sup:start_child({Ack, Type, self(), T}), try - {erlang:monitor(process, Pid), Pid} + {monitor(process, Pid), Pid} after send(Pid, Ack) end. @@ -121,7 +123,7 @@ i({Ack, T, Pid, {RecvData, #diameter_service{applications = Apps, capabilities = Caps} = Svc}}) -> - erlang:monitor(process, Pid), + monitor(process, Pid), wait(Ack, Pid), {_, Seed} = diameter_lib:seed(), random:seed(Seed), @@ -246,11 +248,16 @@ handle_info(T, #watchdog{} = State) -> event(T, State, S), %% before 'watchdog' {noreply, S}; stop -> - ?LOG(stop, T), + ?LOG(stop, truncate(T)), event(T, State, State#watchdog{status = down}), {stop, {shutdown, T}, State} end. +truncate({'DOWN' = T, _, process, Pid, _}) -> + {T, Pid}; +truncate(T) -> + T. + close({'DOWN', _, process, TPid, {shutdown, Reason}}, #watchdog{transport = TPid, parent = Pid}) -> @@ -447,11 +454,12 @@ transition({recv, TPid, Name, Pkt}, #watchdog{transport = TPid} = S) -> %% Current watchdog has timed out. transition({timeout, TRef, tw}, #watchdog{tref = TRef} = S) -> - set_watchdog(timeout(S)); + set_watchdog(0, timeout(S)); -%% Timer was canceled after message was already sent. -transition({timeout, _, tw}, #watchdog{}) -> - ok; +%% Message has arrived since the timer was started: subtract time +%% already elapsed from new timer. +transition({timeout, _, tw}, #watchdog{tref = T0} = S) -> + set_watchdog(diameter_lib:micro_diff(T0) div 1000, S); %% State query. transition({state, Pid}, #watchdog{status = S}) -> @@ -527,18 +535,27 @@ role() -> %% set_watchdog/1 -set_watchdog(#watchdog{tw = TwInit, - tref = TRef} - = S) -> - cancel(TRef), - S#watchdog{tref = erlang:start_timer(tw(TwInit), self(), tw)}; +%% Timer not yet set. +set_watchdog(#watchdog{tref = undefined} = S) -> + set_watchdog(0, S); + +%% Timer already set: start at new one only at expiry. +set_watchdog(#watchdog{} = S) -> + S#watchdog{tref = diameter_lib:now()}; + set_watchdog(stop = No) -> No. -cancel(undefined) -> - ok; -cancel(TRef) -> - erlang:cancel_timer(TRef). +%% set_watchdog/2 + +set_watchdog(Ms, #watchdog{tw = TwInit} = S) -> + S#watchdog{tref = erlang:start_timer(tw(TwInit, Ms), self(), tw)}. + +%% A callback could return anything, so ensure the result isn't +%% negative. Don't prevent abuse, even though the smallest valid +%% timeout is 4000. +tw(TwInit, Ms) -> + max(tw(TwInit) - Ms, 0). tw(T) when is_integer(T), T >= 6000 -> diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src index 86d231179c..788ea790fa 100644 --- a/lib/diameter/src/diameter.appup.src +++ b/lib/diameter/src/diameter.appup.src @@ -42,7 +42,23 @@ {"1.8", [{restart_application, diameter}]}, %% 17.4 {"1.9", [{restart_application, diameter}]}, %% 17.5 {"1.9.1", [{restart_application, diameter}]}, %% 17.5.3 - {"1.9.2", [{restart_application, diameter}]} %% 17.5.5 + {"1.9.2", [{restart_application, diameter}]}, %% 17.5.5 + {"1.9.2.1", [{restart_application, diameter}]}, %% 17.5.6.3 + {"1.10", [{load_module, diameter_codec}, %% 18.0 + {load_module, diameter_peer_fsm}, + {load_module, diameter_watchdog}, + {load_module, diameter_stats}, + {load_module, diameter_config}, + {load_module, diameter_lib}, + {load_module, diameter_peer}, + {load_module, diameter_reg}, + {load_module, diameter_service}, + {load_module, diameter_sync}, + {load_module, diameter_gen_base_rfc6733}, + {load_module, diameter_gen_acct_rfc6733}, + {load_module, diameter_gen_base_rfc3588}, + {load_module, diameter_gen_base_accounting}, + {load_module, diameter_gen_relay}]} ], [ {"0.9", [{restart_application, diameter}]}, @@ -66,6 +82,22 @@ {"1.8", [{restart_application, diameter}]}, {"1.9", [{restart_application, diameter}]}, {"1.9.1", [{restart_application, diameter}]}, - {"1.9.2", [{restart_application, diameter}]} + {"1.9.2", [{restart_application, diameter}]}, + {"1.9.2.1", [{restart_application, diameter}]}, + {"1.10", [{load_module, diameter_gen_relay}, + {load_module, diameter_gen_base_accounting}, + {load_module, diameter_gen_base_rfc3588}, + {load_module, diameter_gen_acct_rfc6733}, + {load_module, diameter_gen_base_rfc6733}, + {load_module, diameter_sync}, + {load_module, diameter_service}, + {load_module, diameter_reg}, + {load_module, diameter_peer}, + {load_module, diameter_lib}, + {load_module, diameter_config}, + {load_module, diameter_stats}, + {load_module, diameter_watchdog}, + {load_module, diameter_peer_fsm}, + {load_module, diameter_codec}]} ] }. diff --git a/lib/diameter/src/info/diameter_info.erl b/lib/diameter/src/info/diameter_info.erl index 2e08662a9e..59a3b94ee4 100644 --- a/lib/diameter/src/info/diameter_info.erl +++ b/lib/diameter/src/info/diameter_info.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2014. All Rights Reserved. +%% Copyright Ericsson AB 2010-2015. 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. @@ -52,8 +52,6 @@ p/1, p/3]). --compile({no_auto_import,[max/2]}). - -export([collect/2]). -define(LONG_TIMEOUT, 30000). @@ -684,9 +682,6 @@ pt(T) -> recsplit(SFun, Rec) -> fun(Fs,Vs) -> SFun(element(1, Rec), Fs, Vs) end. -max(A, B) -> - if A > B -> A; true -> B end. - keyfetch(Key, List) -> {Key,V} = lists:keyfind(Key, 1, List), V. diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl index 3e08b78ea1..678dc9b5d6 100644 --- a/lib/diameter/src/transport/diameter_sctp.erl +++ b/lib/diameter/src/transport/diameter_sctp.erl @@ -21,9 +21,6 @@ -module(diameter_sctp). -behaviour(gen_server). --compile({no_auto_import, [now/0]}). --import(diameter_lib, [now/0]). - %% interface -export([start/3]). diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl index 2c10daec50..e4ed2b227d 100644 --- a/lib/diameter/test/diameter_examples_SUITE.erl +++ b/lib/diameter/test/diameter_examples_SUITE.erl @@ -299,7 +299,7 @@ slave(_) -> T0 = diameter_lib:now(), {ok, Node} = ct_slave:start(?MODULE, ?TIMEOUTS), T1 = diameter_lib:now(), - T2 = rpc:call(Node, erlang, now, []), + T2 = rpc:call(Node, diameter_lib, now, []), {ok, Node} = ct_slave:stop(?MODULE), now_diff([T0, T1, T2, diameter_lib:now()]). diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl index c739643dbe..cbd7fc8ec5 100644 --- a/lib/diameter/test/diameter_gen_sctp_SUITE.erl +++ b/lib/diameter/test/diameter_gen_sctp_SUITE.erl @@ -300,10 +300,10 @@ connect2(Pid, PortNr, Bin) -> %% T2 = time after listening process received our message %% T3 = time after reply is received - T1 = diameter_util:timestamp(), + T1 = diameter_lib:now(), ok = send(Sock, Id, Bin), T2 = unmark(recv(Sock, Id)), - T3 = diameter_util:timestamp(), + T3 = diameter_lib:now(), {diameter_lib:micro_diff(T2, T1), %% Outbound diameter_lib:micro_diff(T3, T2)}. %% Inbound @@ -330,13 +330,13 @@ send(Sock, Id, Bin) -> %% mark/1 mark(Bin) -> - Info = term_to_binary(diameter_util:timestamp()), + Info = term_to_binary(diameter_lib:now()), <<Info/binary, Bin/binary>>. %% unmark/1 unmark(Bin) -> - {_,_,_} = binary_to_term(Bin). + binary_to_term(Bin). %% =========================================================================== diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index fd83c2cd7f..f766f54a80 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -334,13 +334,39 @@ realm(Host) -> call(Server) -> Realm = realm(Server), + %% Include some arbitrary AVPs to exercise encode/decode, that + %% are received back in the STA. + Avps = [#diameter_avp{code = 111, + data = [#diameter_avp{code = 222, + data = <<222:24>>}, + #diameter_avp{code = 333, + data = <<333:16>>}]}, + #diameter_avp{code = 444, + data = <<444:24>>}, + #diameter_avp{code = 555, + data = [#diameter_avp{code = 666, + data = [#diameter_avp + {code = 777, + data = <<7>>}]}, + #diameter_avp{code = 888, + data = <<8>>}, + #diameter_avp{code = 999, + data = <<9>>}]}], + Req = ['STR', {'Destination-Realm', Realm}, {'Destination-Host', [Server]}, {'Termination-Cause', ?LOGOUT}, - {'Auth-Application-Id', ?APP_ID}], + {'Auth-Application-Id', ?APP_ID}, + {'AVP', Avps}], + #diameter_base_STA{'Result-Code' = ?SUCCESS, 'Origin-Host' = Server, - 'Origin-Realm' = Realm} + 'Origin-Realm' = Realm, + %% Unknown AVPs can't be decoded as Grouped since + %% types aren't known. + 'AVP' = [#diameter_avp{code = 111}, + #diameter_avp{code = 444}, + #diameter_avp{code = 555}]} = call(Req, [{filter, realm}]). call(Req, Opts) -> @@ -434,9 +460,18 @@ request(_Pkt, #diameter_caps{origin_host = {OH, _}}) request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId, 'Origin-Host' = Host, 'Origin-Realm' = Realm, - 'Route-Record' = Route}}, + 'Route-Record' = Route, + 'AVP' = Avps}}, #diameter_caps{origin_host = {OH, _}, origin_realm = {OR, _}}) -> + + %% Payloads of unknown AVPs aren't decoded, so we don't know that + %% some types here are Grouped. + [#diameter_avp{code = 111, vendor_id = undefined}, + #diameter_avp{code = 444, vendor_id = undefined, data = <<444:24>>}, + #diameter_avp{code = 555, vendor_id = undefined}] + = Avps, + %% The request should have the Origin-Host/Realm of the original %% sender. R = realm(?CLIENT), @@ -447,4 +482,5 @@ request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId, {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS, 'Session-Id' = SId, 'Origin-Host' = OH, - 'Origin-Realm' = OR}}. + 'Origin-Realm' = OR, + 'AVP' = Avps}}. diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl index 39cb6ae30d..4716082394 100644 --- a/lib/diameter/test/diameter_stats_SUITE.erl +++ b/lib/diameter/test/diameter_stats_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2015. 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. @@ -96,7 +96,7 @@ read(_) -> 7 = ?stat:incr(C1, Ref, 7), Self = self(), [{Ref, [{C1,7}]}, {Self, [{C1,2}, {C2,1}]}] - = lists:sort(?stat:read([self(), Ref, make_ref()])), + = ?stat:read([self(), Ref, make_ref()]), [] = ?stat:read([]), [] = ?stat:read([make_ref()]), ?stat:flush([self(), Ref, make_ref()]). @@ -116,7 +116,7 @@ sum(_) -> [{Self, [{C1,1}, {C2,2}]}] = ?stat:sum([self()]), [{Ref, [{C1,7}]}, {Self, [{C1,1}, {C2,2}]}] - = lists:sort(?stat:flush([self(), Ref])). + = ?stat:flush([self(), Ref]). flush(_) -> Ref = make_ref(), diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index 701fe070d0..53d2d6660e 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -54,7 +54,7 @@ %% Receive a message. -define(RECV(Pat, Ret), receive Pat -> Ret end). --define(RECV(Pat), ?RECV(Pat, diameter_util:timestamp())). +-define(RECV(Pat), ?RECV(Pat, diameter_lib:now())). %% Sockets are opened on the loopback address. -define(ADDR, {127,0,0,1}). @@ -417,8 +417,7 @@ gen_accept(tcp, LSock) -> gen_send(sctp, Sock, Bin) -> {OS, _IS, Id} = getr(assoc), - {_, _, Us} = diameter_util:timestamp(), - gen_sctp:send(Sock, Id, Us rem OS, Bin); + gen_sctp:send(Sock, Id, erlang:unique_integer([positive]) rem OS, Bin); gen_send(tcp, Sock, Bin) -> gen_tcp:send(Sock, Bin). diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index c727d10ddf..52b747e99c 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -31,7 +31,6 @@ fold/3, foldl/3, scramble/1, - timestamp/0, seed/0, unique_string/0, have_sctp/0]). @@ -189,12 +188,6 @@ s(Acc, L) -> s([T|Acc], H ++ Rest). %% --------------------------------------------------------------------------- -%% timestamp/0 - -timestamp() -> - diameter_lib:timestamp(diameter_lib:now()). - -%% --------------------------------------------------------------------------- %% seed/0 seed() -> @@ -205,14 +198,7 @@ seed() -> %% unique_string/0 unique_string() -> - try erlang:unique_integer() of - N -> - integer_to_list(N) - catch - error: undef -> %% OTP < 18 - {M,S,U} = timestamp(), - tl(lists:append(["-" ++ integer_to_list(N) || N <- [M,S,U]])) - end. + integer_to_list(erlang:unique_integer()). %% --------------------------------------------------------------------------- %% have_sctp/0 diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl index 016801383b..6d22ddcc18 100644 --- a/lib/diameter/test/diameter_watchdog_SUITE.erl +++ b/lib/diameter/test/diameter_watchdog_SUITE.erl @@ -49,7 +49,8 @@ accept/1, connect/3, send/2, - setopts/2]). + setopts/2, + close/1]). -include("diameter.hrl"). -include("diameter_ct.hrl"). @@ -421,7 +422,6 @@ suspect(TRef, false, SvcName, N) -> %% abuse/1 abuse(F) -> - [] = run([[abuse, F, T] || T <- [listen, connect]]). abuse(F, [_,_,_|_] = Args) -> @@ -546,6 +546,9 @@ setopts(Sock, Opts) -> send(Sock, Bin) -> send(getr(config), Sock, Bin). +close(Sock) -> + gen_tcp:close(Sock). + %% send/3 %% First outgoing message from a new transport process is CER/CEA. diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk index 1e3135680d..041d21b261 100644 --- a/lib/diameter/vsn.mk +++ b/lib/diameter/vsn.mk @@ -17,5 +17,5 @@ # %CopyrightEnd% APPLICATION = diameter -DIAMETER_VSN = 1.10 +DIAMETER_VSN = 1.11 APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN) diff --git a/otp_versions.table b/otp_versions.table index ff6c262743..2adb77bdb7 100644 --- a/otp_versions.table +++ b/otp_versions.table @@ -1,6 +1,7 @@ OTP-18.0.2 : erts-7.0.2 runtime_tools-1.9.1 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 : OTP-18.0.1 : erts-7.0.1 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 : OTP-18.0 : asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.0 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 # : +OTP-17.5.6.3 : diameter-1.9.2.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1.2 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : OTP-17.5.6.2 : erts-6.4.1.2 runtime_tools-1.8.16.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : OTP-17.5.6.1 : erts-6.4.1.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : OTP-17.5.6 : inets-5.10.9 ssh-3.2.4 ssl-6.0.1 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.2 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : |