From ee62825c1ca752f401662529af7fe8fe247c2165 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 30 Aug 2017 18:04:04 +0200 Subject: Fix extraction of Experimental-Result for counter keys The introduction of decode_format in commit 722fa415 (and then 55e65b26) meant the value was not necessarily the intended tuple. --- lib/diameter/src/base/diameter_traffic.erl | 67 ++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 23 deletions(-) (limited to 'lib/diameter/src/base/diameter_traffic.erl') diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 27a41d6eb0..4388175c3a 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -1891,16 +1891,12 @@ str(T) -> %% get_avp/3 %% -%% Find an AVP in a message of one of three forms: -%% -%% - a message record (as generated from a .dia spec) or -%% - a list of an atom message name followed by 2-tuple, avp name/value pairs. -%% - a list of a #diameter_header{} followed by #diameter_avp{} records, -%% -%% In the first two forms a dictionary module is used at encode to -%% identify the type of the AVP and its arity in the message in -%% question. The third form allows messages to be sent as is, without -%% a dictionary, which is needed in the case of relay agents, for one. +%% Find an AVP in a message in one of the decoded formats, or as a +%% header/avps list. There are only four AVPs that are extracted here: +%% Result-Code and Experimental-Result in order when constructing +%% counter keys, and Destination-Host/Realm when selecting a next-hop +%% peer. Experimental-Result is the only of type Grouped, and is given +%% special treatment in order to return the value as a record. %% Messages will be header/avps list as a relay and the only AVP's we %% look for are in the common dictionary. This is required since the @@ -1909,12 +1905,12 @@ str(T) -> get_avp(?RELAY, Name, Msg) -> get_avp(?BASE, Name, Msg); -%% Message is a header/avps list. +%% Message as header/avps list. get_avp(Dict, Name, [#diameter_header{} | Avps]) -> try - {Code, _, VId} = Dict:avp_header(Name), - A = find_avp(Code, VId, Avps), - (avp_decode(Dict, Name, ungroup(A)))#diameter_avp{name = Name} + {Code, _, Vid} = Dict:avp_header(Name), + A = find_avp(Code, Vid, Avps), + avp_decode(Dict, Name, ungroup(A)) catch error: _ -> undefined @@ -1924,20 +1920,33 @@ get_avp(Dict, Name, [#diameter_header{} | Avps]) -> get_avp(_, Name, [_MsgName | Avps]) -> case find(Name, Avps) of {_, V} -> - #diameter_avp{name = Name, value = V}; + #diameter_avp{name = Name, value = value(Name, V)}; _ -> undefined end; -%% ... or record (but not necessarily). +%% ... or record. get_avp(Dict, Name, Rec) -> - try - #diameter_avp{name = Name, value = Dict:'#get-'(Name, Rec)} + try Dict:'#get-'(Name, Rec) of + V -> + #diameter_avp{name = Name, value = value(Name, V)} catch error:_ -> undefined end. +value('Experimental-Result' = N, #{'Vendor-Id' := Vid, + 'Experimental-Result-Code' := RC}) -> + {N, Vid, RC}; +value('Experimental-Result' = N, [{'Experimental-Result-Code', RC}, + {'Vendor-Id', Vid}]) -> + {N, Vid, RC}; +value('Experimental-Result' = N, [{'Vendor-Id', Vid}, + {'Experimental-Result-Code', RC}]) -> + {N, Vid, RC}; +value(_, V) -> + V. + %% find/2 find(Key, Map) @@ -1967,14 +1976,25 @@ ungroup(Avp) -> %% avp_decode/3 -avp_decode(Dict, Name, #diameter_avp{value = undefined, +%% Ensure Experimental-Result is decoded as record, since this format +%% is used for counter keys. +avp_decode(Dict, 'Experimental-Result' = N, #diameter_avp{data = Bin} + = Avp) + when is_binary(Bin) -> + {V,_} = Dict:avp(decode, Bin, N, decode_opts(Dict)), + Avp#diameter_avp{name = N, value = V}; + +avp_decode(Dict, Name, #diameter_avp{value = X, data = Bin} = Avp) - when is_binary(Bin) -> + when is_binary(Bin), X == undefined orelse X == false -> V = Dict:avp(decode, Bin, Name, decode_opts(Dict)), - Avp#diameter_avp{value = V}; -avp_decode(_, _, #diameter_avp{} = Avp) -> - Avp. + Avp#diameter_avp{name = Name, value = V}; + +avp_decode(_, Name, #diameter_avp{} = Avp) -> + Avp#diameter_avp{name = Name}. + +%% cb/3 cb(#diameter_app{module = [_|_] = M}, F, A) -> eval(M, F, A). @@ -1991,4 +2011,5 @@ decode_opts(Dict) -> string_decode => false, strict_mbit => false, failed_avp => false, + module => Dict, dictionary => Dict}. -- cgit v1.2.3