diff options
author | Anders Svensson <[email protected]> | 2014-05-25 09:30:59 +0200 |
---|---|---|
committer | Anders Svensson <[email protected]> | 2014-05-25 09:30:59 +0200 |
commit | 6202139d7680be7df2fc5a6d6138409c1ae780d6 (patch) | |
tree | d4720faae1220868e6211290ec8061fbbeb63778 /lib/diameter | |
parent | 5782c3aad85c5c1e644d160504d9c8d27ffdc2f1 (diff) | |
parent | 58a070c491e7f2f87a3c6bb09a5c05208a9aa333 (diff) | |
download | otp-6202139d7680be7df2fc5a6d6138409c1ae780d6.tar.gz otp-6202139d7680be7df2fc5a6d6138409c1ae780d6.tar.bz2 otp-6202139d7680be7df2fc5a6d6138409c1ae780d6.zip |
Merge branch 'anders/diameter/rc_counters/OTP-11937' into maint
* anders/diameter/rc_counters/OTP-11937:
Count encode errors in outgoing messages
Count decode errors in incoming requests
Count decode errors independently of result codes
Diffstat (limited to 'lib/diameter')
-rw-r--r-- | lib/diameter/src/base/diameter_codec.erl | 99 | ||||
-rw-r--r-- | lib/diameter/src/base/diameter_peer_fsm.erl | 44 | ||||
-rw-r--r-- | lib/diameter/src/base/diameter_traffic.erl | 88 | ||||
-rw-r--r-- | lib/diameter/src/base/diameter_watchdog.erl | 13 |
4 files changed, 153 insertions, 91 deletions
diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 0de4d53973..9db3552286 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2014. 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 @@ -70,6 +70,12 @@ encode(Mod, #diameter_packet{} = Pkt) -> try e(Mod, Pkt) catch + exit: {_, _, #diameter_header{}} = T -> + %% Exit with a header in the reason to let the caller + %% count encode errors. + X = {?MODULE, encode, T}, + diameter_lib:error_report(X, {?MODULE, encode, [Mod, Pkt]}), + exit(X); error: Reason -> %% Be verbose since a crash report may be truncated and %% encode errors are self-inflicted. @@ -87,53 +93,62 @@ encode(Mod, Msg) -> msg = Msg}). e(_, #diameter_packet{msg = [#diameter_header{} = Hdr | As]} = Pkt) -> - Avps = encode_avps(As), - Length = size(Avps) + 20, - - #diameter_header{version = Vsn, - cmd_code = Code, - application_id = Aid, - hop_by_hop_id = Hid, - end_to_end_id = Eid} - = Hdr, - - Flags = make_flags(0, Hdr), - - Pkt#diameter_packet{header = Hdr, - bin = <<Vsn:8, Length:24, - Flags:8, Code:24, - Aid:32, - Hid:32, - Eid:32, - Avps/binary>>}; + try encode_avps(As) of + Avps -> + Length = size(Avps) + 20, + + #diameter_header{version = Vsn, + cmd_code = Code, + application_id = Aid, + hop_by_hop_id = Hid, + end_to_end_id = Eid} + = Hdr, + + Flags = make_flags(0, Hdr), + + Pkt#diameter_packet{header = Hdr, + bin = <<Vsn:8, Length:24, + Flags:8, Code:24, + Aid:32, + Hid:32, + Eid:32, + Avps/binary>>} + catch + error: Reason -> + exit({Reason, ?STACK, Hdr}) + end; -e(Mod, #diameter_packet{header = Hdr, msg = Msg} = Pkt) -> +e(Mod, #diameter_packet{header = Hdr0, msg = Msg} = Pkt) -> #diameter_header{version = Vsn, hop_by_hop_id = Hid, end_to_end_id = Eid} - = Hdr, + = Hdr0, MsgName = rec2msg(Mod, Msg), - {Code, Flags0, Aid} = msg_header(Mod, MsgName, Hdr), - Flags = make_flags(Flags0, Hdr), - - Avps = encode_avps(Mod, MsgName, values(Msg)), - Length = size(Avps) + 20, - - Pkt#diameter_packet{header = Hdr#diameter_header - {length = Length, - cmd_code = Code, - application_id = Aid, - is_request = 0 /= ?MASK(7, Flags), - is_proxiable = 0 /= ?MASK(6, Flags), - is_error = 0 /= ?MASK(5, Flags), - is_retransmitted = 0 /= ?MASK(4, Flags)}, - bin = <<Vsn:8, Length:24, - Flags:8, Code:24, - Aid:32, - Hid:32, - Eid:32, - Avps/binary>>}. + {Code, Flags0, Aid} = msg_header(Mod, MsgName, Hdr0), + Flags = make_flags(Flags0, Hdr0), + Hdr = Hdr0#diameter_header{cmd_code = Code, + application_id = Aid, + is_request = 0 /= ?MASK(7, Flags), + is_proxiable = 0 /= ?MASK(6, Flags), + is_error = 0 /= ?MASK(5, Flags), + is_retransmitted = 0 /= ?MASK(4, Flags)}, + Values = values(Msg), + + try encode_avps(Mod, MsgName, Values) of + Avps -> + Length = size(Avps) + 20, + Pkt#diameter_packet{header = Hdr#diameter_header{length = Length}, + bin = <<Vsn:8, Length:24, + Flags:8, Code:24, + Aid:32, + Hid:32, + Eid:32, + Avps/binary>>} + catch + error: Reason -> + exit({Reason, ?STACK, Hdr}) + end. %% make_flags/2 diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl index ac87c1a2c1..4b97fa96b3 100644 --- a/lib/diameter/src/base/diameter_peer_fsm.erl +++ b/lib/diameter/src/base/diameter_peer_fsm.erl @@ -292,7 +292,8 @@ handle_info(T, #state{} = State) -> ?LOG(stop, T), {stop, {shutdown, T}, State} catch - exit: {diameter_codec, encode, _} = Reason -> + exit: {diameter_codec, encode, T} = Reason -> + incr_error(send, T), ?LOG(stop, Reason), %% diameter_codec:encode/2 emits an error report. Only %% indicate the probable reason here. @@ -615,7 +616,7 @@ rcv('DPA' = N, transport = TPid, dpr = {Hid, Eid}}) -> - incr_A(recv, diameter_codec:decode(Dict0, Pkt), Dict0), + incr_rc(recv, diameter_codec:decode(Dict0, Pkt), Dict0), diameter_peer:close(TPid), {stop, N}; @@ -623,10 +624,15 @@ rcv('DPA' = N, rcv(_, _, _) -> ok. -%% incr_A/3 +%% incr_rc/3 -incr_A(Dir, Pkt, Dict0) -> - diameter_traffic:incr_A(Dir, Pkt, self(), Dict0). +incr_rc(Dir, Pkt, Dict0) -> + diameter_traffic:incr_rc(Dir, Pkt, self(), Dict0). + +%% incr_error/2 + +incr_error(Dir, Pkt) -> + diameter_traffic:incr_error(Dir, Pkt, self()). %% send/2 @@ -646,6 +652,8 @@ handle_request(Type, #diameter_packet{} = Pkt, #state{dictionary = D} = S) -> %% send_answer/3 send_answer(Type, ReqPkt, #state{transport = TPid, dictionary = Dict} = S) -> + incr_error(recv, ReqPkt), + #diameter_packet{header = H, transport_data = TD} = ReqPkt, @@ -654,18 +662,18 @@ send_answer(Type, ReqPkt, #state{transport = TPid, dictionary = Dict} = S) -> %% An answer message clears the R and T flags and retains the P %% flag. The E flag is set at encode. - Pkt0 = #diameter_packet{header - = H#diameter_header{version = ?DIAMETER_VERSION, - is_request = false, - is_error = undefined, - is_retransmitted = false}, - msg = Msg, - transport_data = TD}, - - Pkt = diameter_codec:encode(Dict, Pkt0), - - incr_A(send, Pkt, Dict), - send(TPid, Pkt), + Pkt = #diameter_packet{header + = H#diameter_header{version = ?DIAMETER_VERSION, + is_request = false, + is_error = undefined, + is_retransmitted = false}, + msg = Msg, + transport_data = TD}, + + AnsPkt = diameter_codec:encode(Dict, Pkt), + + incr_rc(send, AnsPkt, Dict), + send(TPid, AnsPkt), eval(PostF, S). eval([F|A], S) -> @@ -874,7 +882,7 @@ handle_CEA(#diameter_packet{bin = Bin} = DPkt = diameter_codec:decode(Dict0, Pkt), - RC = result_code(incr_A(recv, DPkt, Dict0)), + RC = result_code(incr_rc(recv, DPkt, Dict0)), {SApps, IS, RCaps} = recv_CEA(DPkt, S), diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 5ec79474bb..f2ac745053 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -32,7 +32,8 @@ -export([receive_message/4]). %% towards diameter_peer_fsm and diameter_watchdog --export([incr_A/4]). +-export([incr_error/3, + incr_rc/4]). %% towards diameter_service -export([make_recvdata/1, @@ -112,10 +113,35 @@ peer_down(TPid) -> failover(TPid). %% --------------------------------------------------------------------------- -%% incr_A/4 +%% incr_error/3 %% --------------------------------------------------------------------------- --spec incr_A(send|recv, #diameter_packet{}, TPid, Dict0) +%% A decoded message with errors. +incr_error(Dir, #diameter_packet{header = H, errors = [_|_]}, TPid) -> + incr_error(Dir, H, TPid); + +%% An encoded message with errors and an identifiable header ... +incr_error(Dir, {_, _, #diameter_header{} = H}, TPid) -> + incr_error(Dir, H, TPid); + +%% ... or not. +incr_error(Dir, {_,_}, TPid) -> + incr(TPid, {unknown, Dir, error}); + +incr_error(Dir, #diameter_header{} = H, TPid) -> + incr_error(Dir, diameter_codec:msg_id(H), TPid); + +incr_error(Dir, {_,_,_} = Id, TPid) -> + incr(TPid, {Id, Dir, error}); + +incr_error(_, _, _) -> + false. + +%% --------------------------------------------------------------------------- +%% incr_rc/4 +%% --------------------------------------------------------------------------- + +-spec incr_rc(send|recv, #diameter_packet{}, TPid, Dict0) -> {Counter, non_neg_integer()} | Reason when TPid :: pid(), @@ -124,9 +150,9 @@ peer_down(TPid) -> | {'Experimental-Result', integer(), integer()}, Reason :: atom(). -incr_A(Dir, Pkt, TPid, Dict0) -> +incr_rc(Dir, Pkt, TPid, Dict0) -> try - incr_A(Dir, Pkt, Dict0, TPid, Dict0) + incr_rc(Dir, Pkt, Dict0, TPid, Dict0) catch exit: {invalid_error_bit = E, _} -> E; @@ -238,6 +264,7 @@ recv_R({#diameter_app{id = Id, dictionary = Dict} = App, Caps}, Dict0, RecvData) -> Pkt = errors(Id, diameter_codec:decode(Id, Dict, Pkt0)), + incr_error(recv, Pkt, TPid), {Caps, Pkt, App, recv_R(App, TPid, Dict0, Caps, RecvData, Pkt)}; %% Note that the decode is different depending on whether or not Id is %% ?APP_ID_RELAY. @@ -621,9 +648,10 @@ reply([Msg], Dict, TPid, Dict0, Fs, ReqPkt) reply(Msg, Dict, TPid, Dict0, Fs, ReqPkt) -> Pkt = encode(Dict, + TPid, reset(make_answer_packet(Msg, ReqPkt), Dict, Dict0), Fs), - incr_A(send, Pkt, Dict, TPid, Dict0), %% count outgoing result codes + incr_rc(send, Pkt, Dict, TPid, Dict0), %% count outgoing send(TPid, Pkt). %% reset/3 @@ -988,28 +1016,30 @@ find(Pred, [H|T]) -> %% code, the missing vendor id, and a zero filled payload of the minimum %% required length for the omitted AVP will be added. -%% incr_A/5 +%% incr_rc/5 %% %% Increment a stats counter for result codes in incoming and outgoing %% answers. %% Outgoing message as binary: don't count. (Sending binaries is only %% partially supported.) -incr_A(_, #diameter_packet{msg = undefined = No}, _, _, _) -> +incr_rc(_, #diameter_packet{msg = undefined = No}, _, _, _) -> No; -%% Incoming with decode errors. -incr_A(recv = D, #diameter_packet{header = H, errors = [_|_]}, _, TPid, _) -> - incr(TPid, {diameter_codec:msg_id(H), D, error}); - -%% Incoming without errors or outgoing. Outgoing with encode errors -%% never gets here since encode fails. -incr_A(Dir, Pkt, Dict, TPid, Dict0) -> +%% Incoming or outgoing. Outgoing with encode errors never gets here +%% since encode fails. +incr_rc(Dir, Pkt, Dict, TPid, Dict0) -> #diameter_packet{header = #diameter_header{is_error = E} = Hdr, - msg = Msg} + msg = Msg, + errors = Es} = Pkt, + Id = diameter_codec:msg_id(Hdr), + + %% Count incoming decode errors. + recv /= Dir orelse [] == Es orelse incr_error(Dir, Id, TPid), + %% Exit on a missing result code. T = rc_counter(Dict, Msg), T == false andalso x(no_result_code, answer, [Dir, Pkt]), @@ -1019,7 +1049,7 @@ incr_A(Dir, Pkt, Dict, TPid, Dict0) -> is_result(RC, E, Dict0) orelse x({invalid_error_bit, RC}, answer, [Dir, Pkt]), - incr(TPid, {diameter_codec:msg_id(Hdr), Dir, Ctr}). + incr(TPid, {Id, Dir, Ctr}). %% No E-bit: can't be 3xxx. is_result(RC, false, _Dict0) -> @@ -1330,7 +1360,7 @@ send_R(Pkt0, {Pid, Ref}, SvcName, Fs) -> - Pkt = encode(Dict, Pkt0, Fs), + Pkt = encode(Dict, TPid, Pkt0, Fs), #options{timeout = Timeout} = Opts, @@ -1396,7 +1426,7 @@ handle_answer(SvcName, handle_A(Pkt, SvcName, Dict, Dict0, App, #request{transport = TPid} = Req) -> try - incr_A(recv, Pkt, Dict, TPid, Dict0) %% count incoming result codes + incr_rc(recv, Pkt, Dict, TPid, Dict0) %% count incoming of _ -> answer(Pkt, SvcName, App, Req) catch @@ -1494,10 +1524,10 @@ msg(#diameter_packet{msg = undefined, bin = Bin}) -> msg(#diameter_packet{msg = Msg}) -> Msg. -%% encode/3 +%% encode/4 -encode(Dict, Pkt, Fs) -> - P = encode(Dict, Pkt), +encode(Dict, TPid, Pkt, Fs) -> + P = encode(Dict, TPid, Pkt), eval_packet(P, Fs), P. @@ -1509,11 +1539,17 @@ encode(Dict, Pkt, Fs) -> %% support retransmission but is useful for test. %% A message to be encoded. -encode(Dict, #diameter_packet{bin = undefined} = Pkt) -> - diameter_codec:encode(Dict, Pkt); +encode(Dict, TPid, #diameter_packet{bin = undefined} = Pkt) -> + try + diameter_codec:encode(Dict, Pkt) + catch + exit: {diameter_codec, encode, T} = Reason -> + incr_error(send, T, TPid), + exit(Reason) + end; %% An encoded binary: just send. -encode(_, #diameter_packet{} = Pkt) -> +encode(_, _, #diameter_packet{} = Pkt) -> Pkt. %% send_request/5 @@ -1610,7 +1646,7 @@ resend_request(Pkt0, SvcName, Tmo, Fs) -> - Pkt = encode(Dict, Pkt0, Fs), + Pkt = encode(Dict, TPid, Pkt0, Fs), Req = Req0#request{transport = TPid, packet = Pkt0, diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index 079e1c0bc2..dbfe087659 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -562,17 +562,20 @@ recv(Name, Pkt, S) -> rcv('DWR', Pkt, #watchdog{transport = TPid, dictionary = Dict0}) -> + DPkt = diameter_codec:decode(Dict0, Pkt), + diameter_traffic:incr_error(recv, DPkt, TPid), EPkt = encode(dwa, Dict0, Pkt), - diameter_traffic:incr_A(send, EPkt, TPid, Dict0), + diameter_traffic:incr_rc(send, EPkt, TPid, Dict0), + send(TPid, {send, EPkt}), ?LOG(send, 'DWA'); rcv('DWA', Pkt, #watchdog{transport = TPid, dictionary = Dict0}) -> - diameter_traffic:incr_A(recv, - diameter_codec:decode(Dict0, Pkt), - TPid, - Dict0); + diameter_traffic:incr_rc(recv, + diameter_codec:decode(Dict0, Pkt), + TPid, + Dict0); rcv(N, _, _) when N == 'CER'; |