aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/diameter/src')
-rw-r--r--lib/diameter/src/Makefile24
-rw-r--r--lib/diameter/src/app.sed40
-rw-r--r--lib/diameter/src/base/diameter_codec.erl99
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl53
-rw-r--r--lib/diameter/src/base/diameter_service.erl19
-rw-r--r--lib/diameter/src/base/diameter_stats.erl5
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl165
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl35
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl8
-rw-r--r--lib/diameter/src/compiler/diameter_dict_util.erl37
-rw-r--r--lib/diameter/src/compiler/diameter_forms.hrl6
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl46
-rw-r--r--lib/diameter/src/diameter.app.src26
-rw-r--r--lib/diameter/src/diameter.appup.src83
-rw-r--r--lib/diameter/src/info/diameter_dbg.erl (renamed from lib/diameter/src/base/diameter_dbg.erl)163
-rw-r--r--lib/diameter/src/info/diameter_info.erl (renamed from lib/diameter/src/base/diameter_info.erl)14
-rw-r--r--lib/diameter/src/modules.mk12
-rw-r--r--lib/diameter/src/transport/diameter_sctp.erl52
18 files changed, 525 insertions, 362 deletions
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 578bbaee2e..9afccf298c 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -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
@@ -41,7 +41,7 @@ INCDIR = ../include
ABS_EBIN := $(shell cd $(EBIN) && pwd)
# Where make should look for dependencies.
-VPATH = .:base:compiler:transport:gen
+VPATH = .:base:compiler:transport:gen:info
# ----------------------------------------------------
# Target specs
@@ -55,13 +55,13 @@ DICT_ERLS = $(DICT_MODULES:%=%.erl)
DICT_HRLS = $(DICT_MODULES:%=%.hrl)
# Modules to build before compiling dictionaries.
-COMPILER_MODULES = $(notdir $(filter compiler/%, $(CT_MODULES))) \
- $(DICT_YRL)
+COMPILER_MODULES = $(notdir $(CT_MODULES)) $(DICT_YRL)
# All handwritten modules from which a depend.mk is generated.
MODULES = \
$(RT_MODULES) \
- $(CT_MODULES)
+ $(CT_MODULES) \
+ $(INFO_MODULES)
# Modules whose names are inserted into the app file.
APP_MODULES = \
@@ -72,6 +72,7 @@ APP_MODULES = \
TARGET_MODULES = \
$(APP_MODULES) \
$(CT_MODULES) \
+ $(INFO_MODULES) \
$(DICT_YRL:%=gen/%)
# What to build for the 'opt' target.
@@ -147,14 +148,19 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl
$(ERLC) -Werror -o $(@D) $<
# Generate the app file.
-$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
+$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed
$(gen_verbose) \
M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
+ C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \
+ I=`echo $(notdir $(INFO_MODULES)) | tr ' ' ,`; \
R=`echo $(REGISTERED) | tr ' ' ,`; \
sed -e 's;%VSN%;$(VSN);' \
-e "s;%MODULES%;$$M;" \
+ -e "s;%COMPILER%;$$C;" \
+ -e "s;%INFO%;$$I;" \
-e "s;%REGISTERED%;$$R;" \
- $< > $@
+ $< \
+ | sed -f app.sed > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
$(vsn_verbose) \
@@ -177,6 +183,8 @@ info:
@echo
@$(call list,CT_MODULES)
@echo
+ @$(call list,INFO_MODULES)
+ @echo
@$(call list,TARGET_MODULES)
@echo
@$(call list,TARGET_DIRS)
@@ -216,7 +224,7 @@ dialyze: opt $(PLT)
-Wno_improper_lists \
$(EBIN)/diameter_gen_base_rfc3588.$(EMULATOR) \
$(patsubst %, $(EBIN)/%.$(EMULATOR), \
- $(notdir $(RT_MODULES) $(CT_MODULES)))
+ $(notdir $(RT_MODULES) $(CT_MODULES) $(INFO_MODULES)))
# Omit all but the common dictionary module since these
# (diameter_gen_relay in particular) generate warning depending on how
# much of the included diameter_gen.hrl they use.
diff --git a/lib/diameter/src/app.sed b/lib/diameter/src/app.sed
new file mode 100644
index 0000000000..7916f65002
--- /dev/null
+++ b/lib/diameter/src/app.sed
@@ -0,0 +1,40 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 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
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+#
+# Generate runtime_dependencies from applications to avoid having to
+# specify the same application more than once.
+#
+
+/{runtime_dependencies,/b v
+/{[-a-z]*, "[0-9.]*"}/!b
+/{vsn,/b
+
+/%%/!H
+s/{\([^,]*\)[^}]*}/\1/g
+s/%%/%,/
+b
+
+:v
+
+p
+x
+s/\n//
+s/%//g
+s/\n */ /g
+s/{\([^,]*\), "\([^"]*"\)}/"\1-\2/g
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 912c1b70b4..32e1b91966 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -189,11 +189,7 @@ i({Ack, WPid, {M, Ref} = T, Opts, {Mask, Nodes, Dict0, Svc}}) ->
putr(?RESTRICT_KEY, Nodes),
Tmo = proplists:get_value(capx_timeout, Opts, ?EVENT_TIMEOUT),
- ?IS_TIMEOUT(Tmo) orelse ?ERROR({invalid, {capx_timeout, Tmo}}),
OnLengthErr = proplists:get_value(length_errors, Opts, exit),
- lists:member(OnLengthErr, [exit, handle, discard])
- orelse ?ERROR({invalid, {length_errors, OnLengthErr}}),
- %% Error checking is for configuration added in old code.
{TPid, Addrs} = start_transport(T, Rest, Svc),
@@ -296,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.
@@ -613,9 +610,13 @@ rcv('DPR' = N, Pkt, S) ->
%% DPA in response to DPR and with the expected identifiers.
rcv('DPA' = N,
#diameter_packet{header = #diameter_header{end_to_end_id = Eid,
- hop_by_hop_id = Hid}},
- #state{transport = TPid,
+ hop_by_hop_id = Hid}}
+ = Pkt,
+ #state{dictionary = Dict0,
+ transport = TPid,
dpr = {Hid, Eid}}) ->
+
+ incr_rc(recv, diameter_codec:decode(Dict0, Pkt), Dict0),
diameter_peer:close(TPid),
{stop, N};
@@ -623,6 +624,16 @@ rcv('DPA' = N,
rcv(_, _, _) ->
ok.
+%% incr_rc/3
+
+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
%% Msg here could be a #diameter_packet or a binary depending on who's
@@ -641,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,
@@ -657,7 +670,10 @@ send_answer(Type, ReqPkt, #state{transport = TPid, dictionary = Dict} = S) ->
msg = Msg,
transport_data = TD},
- send(TPid, diameter_codec:encode(Dict, Pkt)),
+ AnsPkt = diameter_codec:encode(Dict, Pkt),
+
+ incr_rc(send, AnsPkt, Dict),
+ send(TPid, AnsPkt),
eval(PostF, S).
eval([F|A], S) ->
@@ -736,7 +752,7 @@ rejected(discard, T, _) ->
rejected({N, Es}, T, S) ->
{answer('CER', N, failed_avp(N, Es), S), T};
rejected(N, T, S) ->
- rejected({N, []}, T, S).
+ {answer('CER', N, [], S), T}.
failed_avp(RC, [{RC, Avp} | _]) ->
[{'Failed-AVP', [[{'AVP', [Avp]}]]}];
@@ -780,10 +796,6 @@ set([_|_] = Ans, FailedAvp) ->
result_code(#diameter_header{is_error = true}, _) ->
{3008, []}; %% DIAMETER_INVALID_HDR_BITS
-result_code(_, [Bs|_])
- when is_bitstring(Bs) -> %% from old code
- {3009, []}; %% DIAMETER_INVALID_HDR_BITS
-
result_code(#diameter_header{version = ?DIAMETER_VERSION}, Es) ->
rc(Es);
@@ -854,7 +866,7 @@ recv_CER(CER, #state{service = Svc, dictionary = Dict}) ->
close({'CER', CER, Svc, Dict, Reason})
end.
-%% handle_CEA/1
+%% handle_CEA/2
handle_CEA(#diameter_packet{bin = Bin}
= Pkt,
@@ -864,18 +876,18 @@ handle_CEA(#diameter_packet{bin = Bin}
when is_binary(Bin) ->
?LOG(recv, 'CEA'),
- #diameter_packet{msg = CEA}
+ #diameter_packet{}
= DPkt
= diameter_codec:decode(Dict0, Pkt),
+ RC = result_code(incr_rc(recv, DPkt, Dict0)),
+
{SApps, IS, RCaps} = recv_CEA(DPkt, S),
#diameter_caps{origin_host = {OH, DH}}
= Caps
= capz(LCaps, RCaps),
- RC = Dict0:'#get-'('Result-Code', CEA),
-
%% Ensure that we don't already have a connection to the peer in
%% question. This isn't the peer election of 3588 except in the
%% sense that, since we don't know who we're talking to until we
@@ -883,6 +895,8 @@ handle_CEA(#diameter_packet{bin = Bin}
%% connection with the peer.
try
+ is_integer(RC)
+ orelse ?THROW(no_result_code),
?IS_SUCCESS(RC)
orelse ?THROW(RC),
[] == SApps
@@ -903,6 +917,11 @@ handle_CEA(#diameter_packet{bin = Bin}
%% capabilities exchange could send DIAMETER_LIMITED_SUCCESS = 2002,
%% even if this isn't required by RFC 3588.
+result_code({{'Result-Code', N}, _}) ->
+ N;
+result_code(_) ->
+ undefined.
+
%% recv_CEA/2
recv_CEA(#diameter_packet{header = #diameter_header{version
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index afe77962af..0dc3eb7123 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -499,9 +499,21 @@ transition(Req, S) ->
%% # terminate/2
%% ---------------------------------------------------------------------------
-terminate(Reason, #state{service_name = Name} = S) ->
+terminate(Reason, #state{service_name = Name, peerT = PeerT} = S) ->
send_event(Name, stop),
ets:delete(?STATE_TABLE, Name),
+
+ %% Communicate pending loss of any peers that connection_down/3
+ %% won't. This is needed when stopping a service since we don't
+ %% wait for watchdog state changes to take care of if. That this
+ %% takes place after deleting the state entry ensures that the
+ %% resulting failover by request processes accomplishes nothing.
+ ets:foldl(fun(#peer{pid = TPid}, _) ->
+ diameter_traffic:peer_down(TPid)
+ end,
+ ok,
+ PeerT),
+
shutdown == Reason %% application shutdown
andalso shutdown(application, S).
@@ -701,8 +713,7 @@ notify(Share, SvcName, T) ->
Nodes = remotes(Share),
[] /= Nodes andalso diameter_peer:notify(Nodes, SvcName, T).
%% Test for the empty list for upgrade reasons: there's no
-%% diameter_peer:notify/3 in old code so no call means no load order
-%% requirement.
+%% diameter_peer:notify/3 in old code.
remotes(false) ->
[];
@@ -1380,6 +1391,8 @@ pick_peer(Local, Remote, Pid, _SvcName, #diameter_app{mutable = true} = App)
case call_service(Pid, {pick_peer, Local, Remote, App}) of
{TPid, _} = T when is_pid(TPid) ->
T;
+ false = No ->
+ No;
{error, _} ->
false
end;
diff --git a/lib/diameter/src/base/diameter_stats.erl b/lib/diameter/src/base/diameter_stats.erl
index b68d4af11f..8353613d32 100644
--- a/lib/diameter/src/base/diameter_stats.erl
+++ b/lib/diameter/src/base/diameter_stats.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
@@ -245,9 +245,6 @@ handle_call({read, Refs, Del}, _From, State) ->
handle_call({read, Refs}, _, State) ->
{reply, read_refs(Refs), State};
-handle_call({flush, Refs}, _From, State) -> %% from old code
- {reply, to_refdict(read(Refs, true)), State};
-
handle_call(Req, From, State) ->
?UNEXPECTED([Req, From]),
{reply, nok, State}.
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index 8b6f026b34..f2ac745053 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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
@@ -31,6 +31,10 @@
%% towards diameter_watchdog
-export([receive_message/4]).
+%% towards diameter_peer_fsm and diameter_watchdog
+-export([incr_error/3,
+ incr_rc/4]).
+
%% towards diameter_service
-export([make_recvdata/1,
peer_up/1,
@@ -90,9 +94,6 @@ make_recvdata([SvcName, PeerT, Apps, Mask | _]) ->
peerT = PeerT,
apps = Apps,
sequence = Mask}.
-%% Take a list so that the caller (diameter_service) can be upgraded
-%% first if new members are added. Note that receive_message/4 might
-%% still get an old term from any watchdog started in old code.
%% ---------------------------------------------------------------------------
%% peer_up/1
@@ -112,6 +113,54 @@ peer_down(TPid) ->
failover(TPid).
%% ---------------------------------------------------------------------------
+%% incr_error/3
+%% ---------------------------------------------------------------------------
+
+%% 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(),
+ Dict0 :: module(),
+ Counter :: {'Result-Code', integer()}
+ | {'Experimental-Result', integer(), integer()},
+ Reason :: atom().
+
+incr_rc(Dir, Pkt, TPid, Dict0) ->
+ try
+ incr_rc(Dir, Pkt, Dict0, TPid, Dict0)
+ catch
+ exit: {invalid_error_bit = E, _} ->
+ E;
+ exit: no_result_code = E ->
+ E
+ end.
+
+%% ---------------------------------------------------------------------------
%% pending/1
%% ---------------------------------------------------------------------------
@@ -215,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.
@@ -305,15 +355,6 @@ errors(_, #diameter_packet{header = #diameter_header{version = V},
when V /= ?DIAMETER_VERSION ->
Pkt#diameter_packet{errors = [5011 | Es]};
-%% DIAMETER_INVALID_AVP_BITS 3009
-%% A request was received that included an AVP whose flag bits are
-%% set to an unrecognized value, or that is inconsistent with the
-%% AVP's definition.
-
-errors(_, #diameter_packet{errors = [Bs | Es]} = Pkt)
- when is_bitstring(Bs) -> %% from old code
- Pkt#diameter_packet{errors = [3009 | Es]};
-
%% DIAMETER_COMMAND_UNSUPPORTED 3001
%% The Request contained a Command-Code that the receiver did not
%% recognize or support. This MUST be used when a Diameter node
@@ -607,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(send, Pkt, Dict, TPid, Dict0), %% count outgoing result codes
+ incr_rc(send, Pkt, Dict, TPid, Dict0), %% count outgoing
send(TPid, Pkt).
%% reset/3
@@ -974,35 +1016,40 @@ 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/4
+%% 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(_, #diameter_packet{msg = undefined}, _, _, _) ->
- ok;
-
-%% Incoming with decode errors.
-incr(recv = D, #diameter_packet{header = H, errors = [_|_]}, _, TPid, _) ->
- incr(TPid, {diameter_codec:msg_id(H), D, error});
+incr_rc(_, #diameter_packet{msg = undefined = No}, _, _, _) ->
+ No;
-%% Incoming without errors or outgoing. Outgoing with encode errors
-%% never gets here since encode fails.
-incr(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 = Rec}
+ msg = Msg,
+ errors = Es}
= Pkt,
- RC = int(get_avp_value(Dict, 'Result-Code', Rec)),
+ 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]),
+ {Ctr, RC} = T,
- %% Exit on an improper Result-Code.
+ %% Or on an inappropriate value.
is_result(RC, E, Dict0)
orelse x({invalid_error_bit, RC}, answer, [Dir, Pkt]),
- irc(TPid, Hdr, Dir, rc_counter(Dict, Rec, RC)).
+ incr(TPid, {Id, Dir, Ctr}).
%% No E-bit: can't be 3xxx.
is_result(RC, false, _Dict0) ->
@@ -1018,16 +1065,10 @@ is_result(RC, true, _) ->
orelse
5000 =< RC andalso RC < 6000.
-irc(_, _, _, undefined) ->
- false;
-
-irc(TPid, Hdr, Dir, Ctr) ->
- incr(TPid, {diameter_codec:msg_id(Hdr), Dir, Ctr}).
-
%% incr/2
-incr(TPid, Counter) ->
- diameter_stats:incr(Counter, TPid, 1).
+incr(TPid, {_, _, T} = Counter) ->
+ {T, diameter_stats:incr(Counter, TPid, 1)}.
%% rc_counter/2
@@ -1036,14 +1077,16 @@ incr(TPid, Counter) ->
%% All Diameter answer messages defined in vendor-specific
%% applications MUST include either one Result-Code AVP or one
%% Experimental-Result AVP.
-%%
-%% Maintain statistics assuming one or the other, not both, which is
-%% surely the intent of the RFC.
-rc_counter(Dict, Rec, undefined) ->
- rcc(get_avp_value(Dict, 'Experimental-Result', Rec));
-rc_counter(_, _, RC) ->
- {'Result-Code', RC}.
+rc_counter(Dict, Msg) ->
+ rcc(Dict, Msg, int(get_avp_value(Dict, 'Result-Code', Msg))).
+
+rcc(Dict, Msg, undefined) ->
+ rcc(get_avp_value(Dict, 'Experimental-Result', Msg));
+
+rcc(_, _, N)
+ when is_integer(N) ->
+ {{'Result-Code', N}, N}.
%% Outgoing answers may be in any of the forms messages can be sent
%% in. Incoming messages will be records. We're assuming here that the
@@ -1051,12 +1094,12 @@ rc_counter(_, _, RC) ->
rcc([{_,_,N} = T | _])
when is_integer(N) ->
- T;
+ {T,N};
rcc({_,_,N} = T)
when is_integer(N) ->
- T;
+ {T,N};
rcc(_) ->
- undefined.
+ false.
%% Extract the first good looking integer. There's no guarantee
%% that what we're looking for has arity 1.
@@ -1317,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,
@@ -1383,10 +1426,16 @@ handle_answer(SvcName,
handle_A(Pkt, SvcName, Dict, Dict0, App, #request{transport = TPid} = Req) ->
try
- incr(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
+ exit: no_result_code ->
+ %% RFC 6733 requires one of Result-Code or
+ %% Experimental-Result, but the decode will have detected
+ %% a missing AVP. If both are optional in the dictionary
+ %% then this isn't a decode error: just continue on.
+ answer(Pkt, SvcName, App, Req);
exit: {invalid_error_bit, RC} ->
#diameter_packet{errors = Es}
= Pkt,
@@ -1475,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.
@@ -1490,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
@@ -1591,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 fb6e9f700d..e89b1394ee 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -155,8 +155,7 @@ wait(Ref, Pid) ->
config(Opts) ->
Config = proplists:get_value(watchdog_config, Opts, []),
- is_list(Config) orelse config_error({watchdog_config, Config}),
- lists:foldl(fun config/2, #config{}, Config). %% ^ added in old code
+ lists:foldl(fun config/2, #config{}, Config).
config({suspect, N}, Rec)
when ?IS_NATURAL(N) ->
@@ -164,10 +163,7 @@ config({suspect, N}, Rec)
config({okay, N}, Rec)
when ?IS_NATURAL(N) ->
- Rec#config{okay = N};
-
-config(T, _) -> %% added in old code
- config_error(T).
+ Rec#config{okay = N}.
%% start/5
@@ -250,17 +246,6 @@ handle_info(T, #watchdog{} = State) ->
?LOG(stop, T),
event(T, State, State#watchdog{status = down}),
{stop, {shutdown, T}, State}
- end;
-
-handle_info(T, State) -> %% started in old code
- handle_info(T, upgrade(State)).
-
-upgrade(State) ->
- case erlang:append_element(State, #config{}) of
- #watchdog{status = okay, config = #config{suspect = OS}} = S ->
- S#watchdog{num_dwa = OS};
- #watchdog{} = S ->
- S
end.
close({'DOWN', _, process, TPid, {shutdown, Reason}},
@@ -495,7 +480,6 @@ encode(dwr = M, Dict0, Mask) ->
#diameter_packet{bin = Bin} = diameter_codec:encode(Dict0, Pkt),
Bin;
-
encode(dwa, Dict0, #diameter_packet{header = H, transport_data = TD}
= ReqPkt) ->
AnsPkt = #diameter_packet{header
@@ -583,13 +567,24 @@ recv(Name, Pkt, S) ->
rcv('DWR', Pkt, #watchdog{transport = TPid,
dictionary = Dict0}) ->
- send(TPid, {send, encode(dwa, Dict0, Pkt)}),
+ DPkt = diameter_codec:decode(Dict0, Pkt),
+ diameter_traffic:incr_error(recv, DPkt, TPid),
+ EPkt = encode(dwa, Dict0, Pkt),
+ 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_rc(recv,
+ diameter_codec:decode(Dict0, Pkt),
+ TPid,
+ Dict0);
+
rcv(N, _, _)
when N == 'CER';
N == 'CEA';
- N == 'DWA';
N == 'DPR';
N == 'DPA' ->
false;
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 22422f2ef2..5a068c1a25 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.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
@@ -31,7 +31,8 @@
%% on the beam file of another dictionary.
%%
--export([from_dict/4]).
+-export([from_dict/4,
+ is_printable_ascii/1]). %% used by ?TERM/1 in diameter_forms.hrl
-include("diameter_forms.hrl").
-include("diameter_vsn.hrl").
@@ -121,6 +122,9 @@ eraser(Key) ->
%% ===========================================================================
%% ===========================================================================
+is_printable_ascii(C) ->
+ 16#20 =< C andalso C =< 16#7F.
+
get_value(Key, Plist) ->
proplists:get_value(Key, Plist, []).
diff --git a/lib/diameter/src/compiler/diameter_dict_util.erl b/lib/diameter/src/compiler/diameter_dict_util.erl
index 3941f30e03..136bba16cb 100644
--- a/lib/diameter/src/compiler/diameter_dict_util.erl
+++ b/lib/diameter/src/compiler/diameter_dict_util.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
@@ -155,6 +155,8 @@ fmt(grouped_avp_has_wrong_type) ->
"Grouped AVP ~s at line ~p defined with type ~s at line ~p";
fmt(grouped_avp_not_defined) ->
"Grouped AVP ~s on line ~p not defined in @avp_types";
+fmt(grouped_avp_not_grouped) ->
+ "Grouped AVP ~s on line ~p not defined in @grouped";
fmt(grouped_vendor_id_without_flag) ->
"Grouped AVP ~s at line ~p has vendor id "
"but definition at line ~p does not specify V flag";
@@ -401,9 +403,9 @@ read(File) ->
{ok, iolist_to_binary([File])}.
make_dict(Parse, Opts) ->
- make_orddict(pass4(pass3(pass2(pass1(reset(make_dict(Parse),
- Opts))),
- Opts))).
+ Dict = pass3(pass2(pass1(reset(make_dict(Parse), Opts))), Opts),
+ ok = examine(Dict),
+ make_orddict(Dict).
%% make_orddict/1
@@ -1168,7 +1170,7 @@ import_avps(Dict, Opts) ->
Import = inherit(Dict, Opts),
report(imported, Import),
- %% pass4/1 tests that all referenced AVP's are either defined
+ %% examine/1 tests that all referenced AVP's are either defined
%% or imported.
dict:store(import_avps,
@@ -1276,21 +1278,21 @@ dict(Mod) ->
end.
%% ===========================================================================
-%% pass4/1
+%% examine/1
%%
%% Sanity checks.
-pass4(Dict) ->
- dict:fold(fun(K, V, _) -> p4(K, V, Dict) end, ok, Dict),
- Dict.
+examine(Dict) ->
+ dict:fold(fun(K, V, _) -> x(K, V, Dict) end, ok, Dict),
+ ok.
%% Ensure enum AVP's have type Enumerated.
-p4({enum, Name}, [Line | _], Dict)
+x({enum, Name}, [Line | _], Dict)
when is_list(Name) ->
true = is_enumerated_avp(Name, Dict, Line);
%% Ensure all referenced AVP's are either defined locally or imported.
-p4({K, {Name, AvpName}}, [Line | _], Dict)
+x({K, {Name, AvpName}}, [Line | _], Dict)
when (K == grouped orelse K == messages),
is_list(Name),
is_list(AvpName),
@@ -1298,13 +1300,22 @@ p4({K, {Name, AvpName}}, [Line | _], Dict)
true = avp_is_defined(AvpName, Dict, Line);
%% Ditto.
-p4({K, AvpName}, [Line | _], Dict)
+x({K, AvpName}, [Line | _], Dict)
when K == avp_vendor_id;
K == custom_types;
K == codecs ->
true = avp_is_defined(AvpName, Dict, Line);
-p4(_, _, _) ->
+%% Ensure that all local AVP's of type Grouped are also present in @grouped.
+x({avp_types, Name}, [Line | Toks], Dict)
+ when 0 < Line, is_list(Name) ->
+ [{number, _, _Code}, {word, _, Type}, {word, _, _Flags}] = Toks,
+ "Grouped" == Type
+ andalso error == dict:find({grouped, Name}, Dict)
+ andalso ?RETURN(grouped_avp_not_grouped, [Name, Line]),
+ ok;
+
+x(_, _, _) ->
ok.
%% has_enumerated_type/3
diff --git a/lib/diameter/src/compiler/diameter_forms.hrl b/lib/diameter/src/compiler/diameter_forms.hrl
index 9b14c1715a..dd03401b9e 100644
--- a/lib/diameter/src/compiler/diameter_forms.hrl
+++ b/lib/diameter/src/compiler/diameter_forms.hrl
@@ -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
@@ -57,4 +57,6 @@
-define(FIELDS(Fs), [{?record_field, ?ATOM(F), V} || {F,V} <- Fs]).
%% Literal term.
--define(TERM(T), erl_parse:abstract(T, ?LINE)).
+-define(TERM(T), erl_parse:abstract(T, [
+ {line, ?LINE},
+ {encoding, fun diameter_codegen:is_printable_ascii/1}])).
diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl
index 2f314b7e57..72f5d36da4 100644
--- a/lib/diameter/src/compiler/diameter_make.erl
+++ b/lib/diameter/src/compiler/diameter_make.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
@@ -33,7 +33,8 @@
-export([codec/2,
codec/1,
format/1,
- flatten/1]).
+ flatten/1,
+ format_error/1]).
-export_type([opt/0]).
@@ -81,8 +82,8 @@ codec(File, Opts) ->
case parse(Dict, Opts) of
{ok, ParseD} ->
make(Path, default(Opts), ParseD);
- {error = E, Reason} ->
- {E, diameter_dict_util:format_error(Reason)}
+ {error, _} = E ->
+ E
end.
codec(File) ->
@@ -115,6 +116,11 @@ flatten([?VERSION = V | Dict]) ->
[grouped, import_groups],
[enum, import_enums]])].
+%% format_error/1
+
+format_error(T) ->
+ diameter_dict_util:format_error(T).
+
%% ===========================================================================
%% flatten/2
@@ -226,21 +232,29 @@ identify([Vsn | [T|_] = ParseD])
identify({path, File} = T) ->
{T, File};
identify(File) ->
- Bin = iolist_to_binary([File]),
- case is_path(Bin) of
+ case is_path([File]) of
true -> {{path, File}, File};
- false -> {Bin, ?DEFAULT_DICT_FILE}
+ false -> {File, ?DEFAULT_DICT_FILE}
end.
-%% Interpret anything containing \n or \r as a literal dictionary,
-%% otherwise a path. (Which might be the wrong guess in the worst case.)
-is_path(Bin) ->
- try
- [throw(C) || <<C>> <= Bin, $\n == C orelse $\r == C],
- true
- catch
- throw:_ -> false
- end.
+%% Interpret anything containing \n or \r as a literal dictionary.
+
+is_path([<<C,B/binary>> | T]) ->
+ is_path([C, B | T]);
+
+is_path([[C|L] | T]) ->
+ is_path([C, L | T]);
+
+is_path([C|_])
+ when $\n == C;
+ $\r == C ->
+ false;
+
+is_path([_|T]) ->
+ is_path(T);
+
+is_path([]) ->
+ true.
make(File, Opts, Dict) ->
ok(lists:foldl(fun(M,A) -> [make(File, Opts, Dict, M) | A] end,
diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src
index ceefb9b398..ac1d847753 100644
--- a/lib/diameter/src/diameter.app.src
+++ b/lib/diameter/src/diameter.app.src
@@ -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
@@ -20,9 +20,27 @@
{application, diameter,
[{description, "Diameter protocol"},
{vsn, "%VSN%"},
- {modules, [%MODULES%]},
+ {modules, [
+ %MODULES%
+ %,%COMPILER%
+ %,%INFO%
+ ]},
{registered, [%REGISTERED%]},
- {applications, [stdlib, kernel]},
+ {applications, [
+ {stdlib, "2.0"}, {kernel, "3.0"}%, {erts, "6.0"}
+ %% {syntax-tools, "1.6.14"}
+ %% {runtime-tools, "1.8.14"}
+ %, {ssl, "5.3.4"}
+ ]},
{env, []},
- {mod, {diameter_app, []}}
+ {mod, {diameter_app, []}},
+ {runtime_dependencies, [
+ ]}
+ %%
+ %% Note that ssl is only required if configured on TCP transports,
+ %% and syntax-tools and runtime-tools are only required if the
+ %% dictionary compiler and debug modules (respectively) are
+ %% needed/wanted at runtime, which they typically aren't. These
+ %% modules are the two commented lines in the 'modules' tuple.
+ %%
]}.
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index c7ae8a2828..0d421c229e 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -2,7 +2,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
@@ -20,62 +20,37 @@
{"%VSN%",
[
- {"0.9", [{restart_application, diameter}]}, %% R14B03
- {"0.10", [{restart_application, diameter}]}, %% R14B04
- {"1.0", [{restart_application, diameter}]}, %% R15B
- {"1.1", [{restart_application, diameter}]}, %% R15B01
- {"1.2", [{restart_application, diameter}]}, %% R15B02
- {"1.2.1", [{restart_application, diameter}]},
- {"1.3", [{restart_application, diameter}]}, %% R15B03
- {"1.3.1", [{restart_application, diameter}]},
- {"1.4", [{restart_application, diameter}]}, %% R16A
- {"1.4.1", [{restart_application, diameter}]}, %% R16B
+ {"0.9", [{restart_application, diameter}]}, %% R14B03
+ {"0.10", [{restart_application, diameter}]}, %% R14B04
+ {"1.0", [{restart_application, diameter}]}, %% R15B
+ {"1.1", [{restart_application, diameter}]}, %% R15B01
+ {"1.2", [{restart_application, diameter}]}, %% R15B02
+ {"1.2.1", [{restart_application, diameter}]},
+ {"1.3", [{restart_application, diameter}]}, %% R15B03
+ {"1.3.1", [{restart_application, diameter}]},
+ {"1.4", [{restart_application, diameter}]}, %% R16A
+ {"1.4.1", [{restart_application, diameter}]}, %% R16B
{"1.4.1.1", [{restart_application, diameter}]},
- {"1.4.2", [{load_module, diameter_codec}, %% R16B01
- {load_module, diameter_types},
- {load_module, diameter_config},
- {load_module, diameter_capx},
- {load_module, diameter_service},
- {load_module, diameter_peer_fsm},
- {load_module, diameter_watchdog},
- {load_module, diameter}]},
- {"1.4.3", [{load_module, diameter_capx}, %% R16B02
- {load_module, diameter_service},
- {load_module, diameter_watchdog},
- {load_module, diameter_codec},
- {load_module, diameter_types},
- {load_module, diameter_config},
- {load_module, diameter}]},
- {"1.4.4", [{load_module, diameter_capx},
- {load_module, diameter_service},
- {load_module, diameter_watchdog},
- {load_module, diameter_config},
- {load_module, diameter}]}
+ {"1.4.2", [{restart_application, diameter}]}, %% R16B01
+ {"1.4.3", [{restart_application, diameter}]}, %% R16B02
+ {"1.4.4", [{restart_application, diameter}]},
+ {"1.5", [{restart_application, diameter}]} %% R16B03
],
[
- {"0.9", [{restart_application, diameter}]},
- {"0.10", [{restart_application, diameter}]},
- {"1.0", [{restart_application, diameter}]},
- {"1.1", [{restart_application, diameter}]},
- {"1.2", [{restart_application, diameter}]},
- {"1.2.1", [{restart_application, diameter}]},
- {"1.3", [{restart_application, diameter}]},
- {"1.3.1", [{restart_application, diameter}]},
- {"1.4", [{restart_application, diameter}]},
- {"1.4.1", [{restart_application, diameter}]},
+ {"0.9", [{restart_application, diameter}]},
+ {"0.10", [{restart_application, diameter}]},
+ {"1.0", [{restart_application, diameter}]},
+ {"1.1", [{restart_application, diameter}]},
+ {"1.2", [{restart_application, diameter}]},
+ {"1.2.1", [{restart_application, diameter}]},
+ {"1.3", [{restart_application, diameter}]},
+ {"1.3.1", [{restart_application, diameter}]},
+ {"1.4", [{restart_application, diameter}]},
+ {"1.4.1", [{restart_application, diameter}]},
{"1.4.1.1", [{restart_application, diameter}]},
- {"1.4.2", [{restart_application, diameter}]},
- {"1.4.3", [{load_module, diameter_types},
- {load_module, diameter_config},
- {load_module, diameter_codec},
- {load_module, diameter_service},
- {load_module, diameter_watchdog},
- {load_module, diameter_capx},
- {load_module, diameter}]},
- {"1.4.4", [{load_module, diameter_capx},
- {load_module, diameter_config},
- {load_module, diameter_service},
- {load_module, diameter_watchdog},
- {load_module, diameter}]}
+ {"1.4.2", [{restart_application, diameter}]},
+ {"1.4.3", [{restart_application, diameter}]},
+ {"1.4.4", [{restart_application, diameter}]},
+ {"1.5", [{restart_application, diameter}]}
]
}.
diff --git a/lib/diameter/src/base/diameter_dbg.erl b/lib/diameter/src/info/diameter_dbg.erl
index 5b0ac3a3b6..b5b3983afa 100644
--- a/lib/diameter/src/base/diameter_dbg.erl
+++ b/lib/diameter/src/info/diameter_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. 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
@@ -17,20 +17,22 @@
%% %CopyrightEnd%
%%
+%%
+%% Information and debug functions.
+%%
+
-module(diameter_dbg).
-export([table/1,
tables/0,
fields/1,
- help/0,
modules/0,
versions/0,
version_info/0,
compiled/0,
procs/0,
latest/0,
- nl/0,
- log/4]).
+ nl/0]).
-export([diameter_config/0,
diameter_peer/0,
@@ -52,11 +54,9 @@
tp/1]).
-include_lib("diameter/include/diameter.hrl").
--include("diameter_internal.hrl").
-
--define(INFO, diameter_info).
--define(SEP(), ?INFO:sep()).
+-define(APP, diameter).
+-define(I, diameter_info).
-define(LOCAL, [diameter_config,
diameter_peer,
@@ -68,27 +68,16 @@
-define(VALUES(Rec), tl(tuple_to_list(Rec))).
-log(_Slogan, _Mod, _Line, _Details) ->
- ok.
-
-%%% ----------------------------------------------------------
-%%% # help()
-%%% ----------------------------------------------------------
-
-help() ->
- not_yet_implemented.
-
-%%% ----------------------------------------------------------
-%%% # table(TableName)
-%%%
-%%% Input: TableName = diameter table containing record entries.
-%%%
-%%% Output: Count | undefined
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # table(TableName)
+%%
+%% Pretty-print a diameter table. Returns the number of records
+%% printed, or undefined.
+%% ----------------------------------------------------------
table(T)
when (T == diameter_peer) orelse (T == diameter_reg) ->
- ?INFO:format(collect(T), fields(T), fun ?INFO:split/2);
+ ?I:format(collect(T), fields(T), fun ?I:split/2);
table(Table)
when is_atom(Table) ->
@@ -96,7 +85,7 @@ table(Table)
undefined = No ->
No;
Fields ->
- ?INFO:format(Table, Fields, fun split/2)
+ ?I:format(Table, Fields, fun split/2)
end.
split([started, name | Fs], [S, N | Vs]) ->
@@ -107,9 +96,9 @@ split([[F|FT]|Fs], [Rec|Vs]) ->
split([F|Fs], [V|Vs]) ->
{F, Fs, V, Vs}.
-%%% ----------------------------------------------------------
-%%% # TableName()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # TableName()
+%% ----------------------------------------------------------
-define(TABLE(Name), Name() -> table(Name)).
@@ -121,16 +110,15 @@ split([F|Fs], [V|Vs]) ->
?TABLE(diameter_service).
?TABLE(diameter_stats).
-%%% ----------------------------------------------------------
-%%% # tables()
-%%%
-%%% Output: Number of records output.
-%%%
-%%% Description: Pretty-print records in diameter tables from all nodes.
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # tables()
+%%
+%% Pretty-print diameter tables from all nodes. Returns the number of
+%% records printed.
+%% ----------------------------------------------------------
tables() ->
- ?INFO:format(field(?LOCAL), fun split/3, fun collect/1).
+ ?I:format(field(?LOCAL), fun split/3, fun collect/1).
field(Tables) ->
lists:map(fun(T) -> {T, fields(T)} end, lists:sort(Tables)).
@@ -138,66 +126,66 @@ field(Tables) ->
split(_, Fs, Vs) ->
split(Fs, Vs).
-%%% ----------------------------------------------------------
-%%% # modules()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # modules()
+%% ----------------------------------------------------------
modules() ->
- Path = filename:join([appdir(), atom_to_list(?APPLICATION) ++ ".app"]),
- {ok, [{application, ?APPLICATION, Attrs}]} = file:consult(Path),
+ Path = filename:join([appdir(), atom_to_list(?APP) ++ ".app"]),
+ {ok, [{application, ?APP, Attrs}]} = file:consult(Path),
{modules, Mods} = lists:keyfind(modules, 1, Attrs),
Mods.
appdir() ->
- [_|_] = code:lib_dir(?APPLICATION, ebin).
+ [_|_] = code:lib_dir(?APP, ebin).
-%%% ----------------------------------------------------------
-%%% # versions()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # versions()
+%% ----------------------------------------------------------
versions() ->
- ?INFO:versions(modules()).
+ ?I:versions(modules()).
-%%% ----------------------------------------------------------
-%%% # versions()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # versions()
+%% ----------------------------------------------------------
version_info() ->
- ?INFO:version_info(modules()).
+ ?I:version_info(modules()).
-%%% ----------------------------------------------------------
-%%% # compiled()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # compiled()
+%% ----------------------------------------------------------
compiled() ->
- ?INFO:compiled(modules()).
+ ?I:compiled(modules()).
-%%% ----------------------------------------------------------
-%%% procs()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% procs()
+%% ----------------------------------------------------------
procs() ->
- ?INFO:procs(?APPLICATION).
+ ?I:procs(?APP).
-%%% ----------------------------------------------------------
-%%% # latest()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # latest()
+%% ----------------------------------------------------------
latest() ->
- ?INFO:latest(modules()).
+ ?I:latest(modules()).
-%%% ----------------------------------------------------------
-%%% # nl()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # nl()
+%% ----------------------------------------------------------
nl() ->
lists:foreach(fun(M) -> abcast = c:nl(M) end, modules()).
-%%% ----------------------------------------------------------
-%%% # pp(Bin)
-%%%
-%%% Description: Pretty-print a message binary.
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # pp(Bin)
+%%
+%% Description: Pretty-print a message binary.
+%% ----------------------------------------------------------
%% Network byte order = big endian.
@@ -207,7 +195,7 @@ pp(<<Version:8, MsgLength:24,
HbHid:32,
E2Eid:32,
AVPs/binary>>) ->
- ?SEP(),
+ ?I:sep(),
ppp(["Version",
"Message length",
"[Actual length]",
@@ -227,7 +215,7 @@ pp(<<Version:8, MsgLength:24,
HbHid,
E2Eid]),
N = avp_loop({AVPs, MsgLength - 20}, 0),
- ?SEP(),
+ ?I:sep(),
N;
pp(<<_Version:8, MsgLength:24, _/binary>> = Bin) ->
@@ -328,23 +316,23 @@ ppp(Fields, Values) ->
ppp({Field, Value}) ->
io:format(": ~-22s : ~p~n", [Field, Value]).
-%%% ----------------------------------------------------------
-%%% # subscriptions()
-%%%
-%%% Output: list of {SvcName, Pid}
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # subscriptions()
+%%
+%% Returns a list of {SvcName, Pid}.
+%% ----------------------------------------------------------
subscriptions() ->
diameter_service:subscriptions().
-%%% ----------------------------------------------------------
-%%% # children()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # children()
+%% ----------------------------------------------------------
children() ->
diameter_sup:tree().
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
%% tracer/[12]
@@ -430,7 +418,7 @@ peers(Name, Ts) ->
mk_peers(Name, [_, {type, connect} | _] = Ts) ->
[[Name | mk_peer(Ts)]];
-mk_peers(Name, [R, {type, listen}, O, {accept = A, As}]) ->
+mk_peers(Name, [R, {type, listen}, O, {accept = A, As} | _]) ->
[[Name | mk_peer([R, {type, A}, O | Ts])] || Ts <- As].
%% This is a bit lame: service_info works to build this list and out
%% of something like what we want here and then we take it apart.
@@ -485,13 +473,12 @@ fields(diameter_service) ->
[started,
name,
record_info(fields, diameter_service),
+ watchdogT,
peerT,
- connT,
- share_peers,
- use_shared_peers,
shared_peers,
local_peers,
- monitor];
+ monitor,
+ options];
?FIELDS(diameter_event);
?FIELDS(diameter_uri);
diff --git a/lib/diameter/src/base/diameter_info.erl b/lib/diameter/src/info/diameter_info.erl
index 39d32d07cd..10972f3231 100644
--- a/lib/diameter/src/base/diameter_info.erl
+++ b/lib/diameter/src/info/diameter_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. 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
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
+%%
+%% Generic functions for formatting table listings and more. Used by
+%% diameter_dbg.
+%%
+
-module(diameter_info).
-export([usage/1,
@@ -573,12 +578,7 @@ sys_info() ->
{A,V}.
os_info() ->
- {os:version(), case os:type() of
- {_Fam, _Name} = T ->
- T;
- Fam ->
- {Fam, ""}
- end}.
+ {os:version(), os:type()}.
chomp(S) ->
string:strip(S, right, $\n).
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
index f8d3cf1d6f..a2a7a51892 100644
--- a/lib/diameter/src/modules.mk
+++ b/lib/diameter/src/modules.mk
@@ -1,8 +1,7 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
# %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
@@ -64,16 +63,19 @@ RT_MODULES = \
transport/diameter_transport \
transport/diameter_transport_sup
-# Handwritten (compile time) modules not included in the app file.
+# Handwritten compiler modules not included in the app file.
CT_MODULES = \
- base/diameter_dbg \
- base/diameter_info \
compiler/diameter_codegen \
compiler/diameter_exprecs \
compiler/diameter_dict_scanner \
compiler/diameter_dict_util \
compiler/diameter_make
+# Info/debug modules, also not included in the app file.
+INFO_MODULES = \
+ info/diameter_dbg \
+ info/diameter_info
+
# Released hrl files in ../include intended for public consumption.
EXTERNAL_HRLS = \
diameter.hrl \
diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl
index 49a530b4eb..32e7aaca39 100644
--- a/lib/diameter/src/transport/diameter_sctp.erl
+++ b/lib/diameter/src/transport/diameter_sctp.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,14 +70,14 @@
-type connect_option() :: {raddr, inet:ip_address()}
| {rport, inet:port_number()}
- | gen_sctp:open_option().
+ | term(). %% gen_sctp:open_option().
-type match() :: inet:ip_address()
| string()
| [match()].
-type listen_option() :: {accept, match()}
- | gen_sctp:open_option().
+ | term(). %% gen_sctp:open_option().
-type uint() :: non_neg_integer().
@@ -171,18 +171,33 @@ start_link(T) ->
info({gen_sctp, Sock}) ->
lists:flatmap(fun(K) -> info(K, Sock) end,
- [{socket, sockname},
- {peer, peername},
+ [{socket, socknames},
+ {peer, peernames},
{statistics, getstat}]).
info({K,F}, Sock) ->
case inet:F(Sock) of
{ok, V} ->
- [{K,V}];
+ [{K, map(F,V)}];
_ ->
[]
end.
+%% inet:{sock,peer}names/1 returns [{Addr, Port}] but the port number
+%% should be the same in each tuple. Map to a {[Addr], Port} tuple if
+%% so.
+map(K, [{_, Port} | _] = APs)
+ when K == socknames;
+ K == peernames ->
+ try [A || {A,P} <- APs, P == Port orelse throw(?MODULE)] of
+ As -> {As, Port}
+ catch
+ ?MODULE -> APs
+ end;
+
+map(_, V) ->
+ V.
+
%% ---------------------------------------------------------------------------
%% # init/1
%% ---------------------------------------------------------------------------
@@ -338,9 +353,6 @@ handle_call({{accept, Ref}, Pid}, _, #listener{ref = Ref,
{TPid, NewS} = accept(Ref, Pid, S),
{reply, {ok, TPid}, NewS#listener{count = N+1}};
-handle_call(T, From, {listener,_,_,_,_,_,_} = S) -> % started in old code
- handle_call(T, From, upgrade(S));
-
handle_call(_, _, State) ->
{reply, nok, State}.
@@ -359,10 +371,7 @@ handle_info(T, #transport{} = S) ->
{noreply, #transport{} = t(T,S)};
handle_info(T, #listener{} = S) ->
- {noreply, #listener{} = l(T,S)};
-
-handle_info(T, {listener,_,_,_,_,_,_} = S) -> % started in old code
- handle_info(T, upgrade(S)).
+ {noreply, #listener{} = l(T,S)}.
%% ---------------------------------------------------------------------------
%% # code_change/3
@@ -396,9 +405,6 @@ terminate(_, #listener{socket = Sock}) ->
%% ---------------------------------------------------------------------------
-upgrade(S) ->
- #listener{} = erlang:append_element(S, ?DEFAULT_ACCEPT).
-
putr(Key, Val) ->
put({?MODULE, Key}, Val).
@@ -502,8 +508,6 @@ transition({peeloff, Sock, {sctp, LSock, _RA, _RP, _Data} = Msg, Matches},
= S) ->
ok = accept_peer(Sock, Matches),
transition(Msg, S#transport{socket = Sock});
-transition({peeloff = T, _Sock, _Msg} = T, #transport{} = S) ->% from old code
- transition(erlang:append_element(T, ?DEFAULT_ACCEPT), S);
%% Incoming message.
transition({sctp, _Sock, _RA, _RP, Data}, #transport{socket = Sock} = S) ->
@@ -560,7 +564,7 @@ accept_peer(_, []) ->
ok;
accept_peer(Sock, Matches) ->
- {RAddrs, _} = ok(inet:peername(Sock)),
+ RAddrs = [A || {A,_} <- ok(inet:peernames(Sock))],
diameter_peer:match(RAddrs, Matches)
orelse x({accept, RAddrs, Matches}),
ok.
@@ -605,11 +609,15 @@ accept(_, Pid, #listener{ref = Ref, pending = {N,Q}} = S) ->
%% send/2
%% Outbound Diameter message on a specified stream ...
-send(#diameter_packet{bin = Bin, transport_data = {stream, SId}}, S) ->
- send(SId, Bin, S),
+send(#diameter_packet{bin = Bin, transport_data = {outstream, SId}},
+ #transport{streams = {_, OS}}
+ = S) ->
+ send(SId rem OS, Bin, S),
S;
-%% ... or not: rotate through all steams.
+%% ... or not: rotate through all streams.
+send(#diameter_packet{bin = Bin}, S) ->
+ send(Bin, S);
send(Bin, #transport{streams = {_, OS},
os = N}
= S)