aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter
diff options
context:
space:
mode:
authorAnders Svensson <[email protected]>2014-05-22 02:09:23 +0200
committerAnders Svensson <[email protected]>2014-05-23 12:04:05 +0200
commit58a070c491e7f2f87a3c6bb09a5c05208a9aa333 (patch)
tree5950784baf1724298ff3a6eb0cdcbc33f00af5b7 /lib/diameter
parent6642bfc89b9a9863ea1f4864d28b96b075beedd8 (diff)
downloadotp-58a070c491e7f2f87a3c6bb09a5c05208a9aa333.tar.gz
otp-58a070c491e7f2f87a3c6bb09a5c05208a9aa333.tar.bz2
otp-58a070c491e7f2f87a3c6bb09a5c05208a9aa333.zip
Count encode errors in outgoing messages
Only decode errors were counted previously. Keys are of the form {Id, send, error}, where Id is: {ApplicationId, CommandCode, Rbit} | unknown The latter will be the case if not even a #diameter_header{} can be constructed.
Diffstat (limited to 'lib/diameter')
-rw-r--r--lib/diameter/src/base/diameter_codec.erl99
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl44
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl89
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl14
4 files changed, 143 insertions, 103 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 4978c1e049..74086e75b0 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -296,7 +296,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.
@@ -619,7 +620,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};
@@ -627,10 +628,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
@@ -650,7 +656,7 @@ handle_request(Type, #diameter_packet{} = Pkt, #state{dictionary = D} = S) ->
%% send_answer/3
send_answer(Type, ReqPkt, #state{transport = TPid, dictionary = Dict} = S) ->
- diameter_traffic:incr_R(recv, ReqPkt, TPid),
+ incr_error(recv, ReqPkt),
#diameter_packet{header = H,
transport_data = TD}
@@ -660,18 +666,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) ->
@@ -884,7 +890,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 29d21fa7dc..f113d95b2e 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -32,8 +32,8 @@
-export([receive_message/4]).
%% towards diameter_peer_fsm and diameter_watchdog
--export([incr_A/4,
- incr_R/3]).
+-export([incr_error/3,
+ incr_rc/4]).
%% towards diameter_service
-export([make_recvdata/1,
@@ -116,10 +116,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(),
@@ -128,9 +153,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;
@@ -139,18 +164,6 @@ incr_A(Dir, Pkt, TPid, Dict0) ->
end.
%% ---------------------------------------------------------------------------
-%% incr_R/3
-%% ---------------------------------------------------------------------------
-
-%% incr_R/3
-
-incr_R(recv = D, #diameter_packet{header = H, errors = [_|_]}, TPid) ->
- incr_error(diameter_codec:msg_id(H), D, TPid);
-
-incr_R(_, _, _) ->
- ok.
-
-%% ---------------------------------------------------------------------------
%% pending/1
%% ---------------------------------------------------------------------------
@@ -254,7 +267,7 @@ recv_R({#diameter_app{id = Id, dictionary = Dict} = App, Caps},
Dict0,
RecvData) ->
Pkt = errors(Id, diameter_codec:decode(Id, Dict, Pkt0)),
- incr_R(recv, Pkt, TPid),
+ 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.
@@ -647,9 +660,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
+ incr_rc(send, Pkt, Dict, TPid, Dict0), %% count outgoing
send(TPid, Pkt).
%% reset/3
@@ -1014,19 +1028,19 @@ 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 or outgoing. Outgoing with encode errors never gets here
%% since encode fails.
-incr_A(Dir, Pkt, Dict, TPid, Dict0) ->
+incr_rc(Dir, Pkt, Dict, TPid, Dict0) ->
#diameter_packet{header = #diameter_header{is_error = E}
= Hdr,
msg = Msg,
@@ -1036,7 +1050,7 @@ incr_A(Dir, Pkt, Dict, TPid, Dict0) ->
Id = diameter_codec:msg_id(Hdr),
%% Count incoming decode errors.
- recv /= Dir orelse [] == Es orelse incr_error(Id, Dir, TPid),
+ recv /= Dir orelse [] == Es orelse incr_error(Dir, Id, TPid),
%% Exit on a missing result code.
T = rc_counter(Dict, Msg),
@@ -1120,9 +1134,6 @@ x(Reason, F, A) ->
x(T) ->
exit(T).
-incr_error(Id, Dir, TPid) ->
- incr(TPid, {Id, Dir, error}).
-
%% ---------------------------------------------------------------------------
%% # send_request/4
%%
@@ -1361,7 +1372,7 @@ send_R(Pkt0,
{Pid, Ref},
SvcName,
Fs) ->
- Pkt = encode(Dict, Pkt0, Fs),
+ Pkt = encode(Dict, TPid, Pkt0, Fs),
#options{timeout = Timeout}
= Opts,
@@ -1427,7 +1438,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
+ incr_rc(recv, Pkt, Dict, TPid, Dict0) %% count incoming
of
_ -> answer(Pkt, SvcName, App, Req)
catch
@@ -1525,10 +1536,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.
@@ -1540,11 +1551,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
@@ -1641,7 +1658,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 710017e62f..87b69cc60d 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -559,18 +559,20 @@ recv(Name, Pkt, S) ->
rcv('DWR', Pkt, #watchdog{transport = TPid,
dictionary = Dict0}) ->
- diameter_traffic:incr_R(recv, diameter_codec:decode(Pkt), TPid),
+ 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';