aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter
diff options
context:
space:
mode:
Diffstat (limited to 'lib/diameter')
-rw-r--r--lib/diameter/doc/src/diameter.xml37
-rw-r--r--lib/diameter/doc/src/diameter_app.xml47
-rw-r--r--lib/diameter/doc/src/diameter_sctp.xml10
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml13
-rw-r--r--lib/diameter/include/diameter_gen.hrl4
-rw-r--r--lib/diameter/src/app/Makefile4
-rw-r--r--lib/diameter/src/app/diameter_codec.erl22
-rw-r--r--lib/diameter/src/app/diameter_config.erl11
-rw-r--r--lib/diameter/src/app/diameter_internal.hrl23
-rw-r--r--lib/diameter/src/app/diameter_lib.erl28
-rw-r--r--lib/diameter/src/app/diameter_peer.erl11
-rw-r--r--lib/diameter/src/app/diameter_reg.erl12
-rw-r--r--lib/diameter/src/app/diameter_service.erl200
-rw-r--r--lib/diameter/src/app/diameter_stats.erl11
-rw-r--r--lib/diameter/src/app/diameter_sync.erl35
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl1
16 files changed, 215 insertions, 254 deletions
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index 36b6cbf0cf..2cad70e3bc 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -277,6 +277,10 @@ callback.</p>
</taglist>
+<p>
+An invalid option will cause <seealso marker="#call">call/4</seealso>
+to fail.</p>
+
<marker id="capability"/>
</item>
@@ -405,6 +409,8 @@ sense.</p>
<code>
eval([{M,F,A} | T]) ->
apply(M, F, T ++ A);
+eval([[F|A] | T]) ->
+ eval([F | T ++ A]);
eval([F|A]) ->
apply(F, A);
eval(F) ->
@@ -461,14 +467,14 @@ or any peer if the request does not contain
a <c>Destination-Realm</c> AVP.</p>
</item>
-<tag><c>{host, any|UTF8String()}</c></tag>
+<tag><c>{host, any|DiameterIdentity()}</c></tag>
<item>
<p>
Matches only those peers whose <c>Origin-Host</c> has the
specified value, or all peers if the atom <c>any</c>.</p>
</item>
-<tag><c>{realm, any|UTF8String()</c></tag>
+<tag><c>{realm, any|DiameterIdentity()</c></tag>
<item>
<p>
Matches only those peers whose <c>Origin-Realm</c> has the
@@ -478,8 +484,9 @@ value, or all peers if the atom <c>any</c>.</p>
<tag><c>{eval, evaluable()}</c></tag>
<item>
<p>
-Matches only those peers for which the specified evaluable() evaluates
-to true on the peer's <c>diameter_caps</c> record.</p>
+Matches only those peers for which the specified evaluable() returns
+<c>true</c> on the connection's <c>diameter_caps</c> record.
+Any other return value or exception is equivalent to <c>false</c>.</p>
</item>
<tag><c>{neg, peer_filter()}</c></tag>
@@ -503,6 +510,21 @@ specified list.</p>
</taglist>
+<p>
+Note that the <c>host</c> and <c>realm</c> filters examine the
+outgoing request as passed to <seealso marker="#call">call/4</seealso>,
+assuming that this is a record- or list-valued message() as documented
+in <seealso marker="diameter_app">diameter_app(3)</seealso>, and that
+the message contains at most one of each AVP.
+If this is not the case then the <c>{host|realm, DiameterIdentity()}</c>
+filters must be used to achieve the desired result.
+Note also that an empty host/realm (which should not be typical)
+is equivalent to an unspecified one for the purposes of filtering.</p>
+
+<p>
+An invalid filter is equivalent to <c>{any, []}</c>, a filter
+that matches no peer.</p>
+
<marker id="service_event"/>
</item>
@@ -787,7 +809,7 @@ transports.</p>
<type>
<v>SvcName = service_name()</v>
<v>App = application_alias()</v>
-<v>Request = diameter_app:message()</v>
+<v>Request = diameter_app:message() | term()</v>
<v>Answer = term()</v>
<v>Options = [call_opt()]</v>
</type>
@@ -819,9 +841,8 @@ If there are no suitable peers, or if
<seealso marker="diameter_app#pick_peer">pick_peer/4</seealso>
rejects them by returning 'false', then <c>{error, no_connection}</c>
is returned.
-If <seealso marker="diameter_app#pick_peer">pick_peer/4</seealso>
-selects a candidate peer then a request process is spawned for the
-outgoing request, in which there is a
+Otherwise <seealso marker="diameter_app#pick_peer">pick_peer/4</seealso>
+is followed by a
<seealso
marker="diameter_app#prepare_request">prepare_request/3</seealso>
callback, the message is encoded and sent.</p>
diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml
index fc359b9d1d..a9ae0ebbec 100644
--- a/lib/diameter/doc/src/diameter_app.xml
+++ b/lib/diameter/doc/src/diameter_app.xml
@@ -269,7 +269,12 @@ The candidate peers list will only include those
which are selected by any <c>filter</c> option specified in the call to
<seealso marker="diameter#call">diameter:call/4</seealso>, and only
those which have indicated support for the Diameter application in
-question.</p>
+question.
+The order of the elements is unspecified except that any
+peers whose Origin-Host and Origin-Realm matches that of the
+outgoing request (in the sense of a <c>{filter, {all, [host, realm]}}</c>
+option to <seealso marker="diameter#call">diameter:call/4</seealso>)
+will be placed at the head of the list.</p>
<p>
The return values <c>false</c> and <c>{false, State}</c> are
@@ -467,11 +472,11 @@ callback returned false.</p>
<v>Packet = packet()</v>
<v>SvcName = term()</v>
<v>Peer = peer()</v>
-<v>Action = Reply | {relay, Opts} | discard | {eval, Action, ContF}</v>
+<v>Action = Reply | {relay, Opts} | discard | {eval, Action, PostF}</v>
<v>Reply = {reply, message()}
| {protocol_error, 3000..3999}</v>
<v>Opts = diameter:call_opts()</v>
-<v>ContF = diameter:evaluable()</v>
+<v>PostF = diameter:evaluable()</v>
</type>
<desc>
<p>
@@ -559,26 +564,28 @@ will cause the request process in question to fail.</p>
<tag><c>{relay, Opts}</c></tag>
<item>
<p>
-Relay a request to another peer.
-The appropriate Route-Record AVP will be added to the relayed request
-by diameter and <seealso marker="#pick_peer">pick_peer/4</seealso>
-and <seealso marker="#prepare_request">prepare_request/3</seealso>
-callback will take place just as if <seealso
+Relay a request to another peer in the role of a Diameter relay agent.
+If a routing loop is detected then the request is answered with
+3005 (DIAMETER_LOOP_DETECTED).
+Otherwise a Route-Record AVP (containing the sending peer's Origin-Host) is
+added to the request and <seealso marker="#pick_peer">pick_peer/4</seealso>
+and subsequent callbacks take place just as if <seealso
marker="diameter#call">diameter:call/4</seealso> had been called
explicitly.
-However, returning a <c>relay</c> tuple also causes the End-to-End
-Identifier to be preserved in the header of the relayed request as
-required by RFC 3588.</p>
+The End-to-End Identifier of the incoming request is preserved in the
+header of the relayed request.</p>
<p>
-The returned <c>Opts</c> should not specify <c>detach</c> and
-the <seealso marker="#handle_answer">handle_answer/4</seealso>
-callback following from a relayed request must return its first
+The returned <c>Opts</c> should not specify <c>detach</c>.
+A subsequent <seealso marker="#handle_answer">handle_answer/4</seealso>
+callback for the relayed request must return its first
argument, the <c>diameter_packet</c> record containing the answer
message.
Note that the <c>extra</c> option can be specified to supply arguments
-that can distinguish the relay case from others if so desired,
-although the form of the request message may be sufficient.</p>
+that can distinguish the relay case from others if so desired.
+Any other return value (for example, from a
+<seealso marker="#handle_error">handle_error/4</seealso> callback)
+causes the request to be answered with 3002 (DIAMETER_UNABLE_TO_DELIVER).</p>
</item>
<tag><c>discard</c></tag>
@@ -587,18 +594,18 @@ although the form of the request message may be sufficient.</p>
Discard the request.</p>
</item>
-<tag><c>{eval, Action, ContF}</c></tag>
+<tag><c>{eval, Action, PostF}</c></tag>
<item>
<p>
Handle the request as if <c>Action</c> has been returned and then
-evaluate <c>ContF</c> in the request process.</p>
+evaluate <c>PostF</c> in the request process.</p>
</item>
</taglist>
<p>
-Note that diameter will respond to protocol errors in an incoming
-request without invoking <c>handle_request/3</c>.</p>
+Note that protocol errors detected by diameter will result in an
+answer message without <c>handle_request/3</c> being invoked.</p>
</desc>
</func>
diff --git a/lib/diameter/doc/src/diameter_sctp.xml b/lib/diameter/doc/src/diameter_sctp.xml
index d0377f4b38..c1e839b8e1 100644
--- a/lib/diameter/doc/src/diameter_sctp.xml
+++ b/lib/diameter/doc/src/diameter_sctp.xml
@@ -74,11 +74,12 @@ marker="diameter_transport#start">diameter_transport(3)</seealso>.</p>
<p>
The only diameter_sctp-specific argument is the options list.
Options <c>raddr</c> and <c>rport</c> specify the remote address
-and port for a connector and not valid for a listener.
+and port for a connecting transport and not valid for a listening
+transport.
The former is required while latter defaults to 3868 if unspecified.
More than one <c>raddr</c> option can be specified, in which case the
-connector in question attempts each in sequence until an association
-is established.
+connecting transport in question attempts each in sequence until
+an association is established.
Remaining options are any accepted by gen_sctp:open/1, with the exception
of options <c>mode</c>, <c>binary</c>, <c>list</c>, <c>active</c>
and <c>sctp_events</c>.
@@ -89,7 +90,8 @@ and port respectively.</p>
Multiple <c>ip</c> options can be specified for a multihomed peer.
If none are specified then the values of Host-IP-Address
on the service are used. (In particular, one of these must be specified.)
-Option <c>port</c> defaults to 3868 for a listener and 0 for a connector.</p>
+Option <c>port</c> defaults to 3868 for a listening transport and 0 for a
+connecting transport.</p>
<p>
diameter_sctp uses the <c>transport_data</c> field of
diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml
index 5d6e07b1b8..a502e53972 100644
--- a/lib/diameter/doc/src/diameter_tcp.xml
+++ b/lib/diameter/doc/src/diameter_tcp.xml
@@ -74,13 +74,14 @@ marker="diameter_transport#start">diameter_transport(3)</seealso>.</p>
<p>
The only diameter_tcp-specific argument is the options list.
Options <c>raddr</c> and <c>rport</c> specify the remote address
-and port for a connector and not valid for a listener.
+and port for a connecting transport and not valid for a listening
+transport.
Remaining options are any accepted by gen_tcp:connect/3 for
-a connector, or gen_tcp:listen/2 for a listener, with the exception
-of <c>binary</c>, <c>packet</c> and <c>active</c>.
-Also, option <c>port</c> can be specified for a listener to specify the
-local listening port, the default being the standardized 3868 if
-unspecified.
+a connecting transport, or gen_tcp:listen/2 for a listening transport,
+with the exception of <c>binary</c>, <c>packet</c> and <c>active</c>.
+Also, option <c>port</c> can be specified for a listening transport
+to specify the local listening port, the default being the standardized
+3868 if unspecified.
Note that option <c>ip</c> specifies the local address.</p>
<p>
diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl
index 4c91954a21..d037e1044a 100644
--- a/lib/diameter/include/diameter_gen.hrl
+++ b/lib/diameter/include/diameter_gen.hrl
@@ -44,14 +44,14 @@ encode_avps(Name, Rec) ->
?MODULE,
?LINE,
{Reason, Name, Rec}),
- erlang:error(list_to_tuple(Reason ++ [Name, Rec, ?MODULE]));
+ erlang:error(list_to_tuple(Reason ++ [Name]));
error: Reason ->
Stack = erlang:get_stacktrace(),
diameter_dbg:log({encode, failure},
?MODULE,
?LINE,
{Reason, Name, Rec, Stack}),
- erlang:error({encode_failure, Reason, Name, Rec, ?MODULE, Stack})
+ erlang:error({encode_failure, Reason, Name, Stack})
end.
%% encode/2
diff --git a/lib/diameter/src/app/Makefile b/lib/diameter/src/app/Makefile
index 6de220d282..229466e264 100644
--- a/lib/diameter/src/app/Makefile
+++ b/lib/diameter/src/app/Makefile
@@ -181,6 +181,10 @@ release_docs_spec:
# Dependencies
# ----------------------------------------------------
+$(SPEC_FILES:%.dia=$(EBIN)/%.$(EMULATOR)): \
+ $(DIAMETER_TOP)/include/diameter.hrl \
+ $(DIAMETER_TOP)/include/diameter_gen.hrl
+
depend: depend.mk
# Generate dependencies makefile. It's assumed that the compile target
diff --git a/lib/diameter/src/app/diameter_codec.erl b/lib/diameter/src/app/diameter_codec.erl
index f6cbde5446..d88f42fb7c 100644
--- a/lib/diameter/src/app/diameter_codec.erl
+++ b/lib/diameter/src/app/diameter_codec.erl
@@ -140,10 +140,10 @@ make_flags(Flags0, #diameter_header{is_request = R,
mf(undefined, F, _) ->
F;
mf(B, F, N) -> %% reset the affected bit
- (F bxor (F band (1 bsl N))) bor (bit(B) bsl N).
+ (F bxor (F band (1 bsl N))) bor bit(B, N).
-bit(true) -> 1;
-bit(false) -> 0.
+bit(true, N) -> 1 bsl N;
+bit(false, _) -> 0.
%% values/1
@@ -199,25 +199,16 @@ msg_header(Mod, MsgName, Header) ->
p(Flags, #diameter_header{is_request = true,
is_proxiable = P}) ->
- Flags bor choose(P, 2#01000000, 0);
+ Flags band (2#10110000 bor choose(P, 2#01000000, 0));
p(Flags, _) ->
Flags.
-%% The header below is that of the incoming request being answered,
-%% not of the answer (which hasn't been encoded yet).
-
h(Mod, 'answer-message' = MsgName, Header) ->
?BASE = Mod,
- #diameter_header{is_request = true,
- cmd_code = Code}
- = Header,
+ #diameter_header{cmd_code = Code} = Header,
{_, Flags, ApplId} = ?BASE:msg_header(MsgName),
{Code, Flags, ApplId};
-h(Mod, MsgName, #diameter_header{is_request = true,
- cmd_code = Code}) ->
- {Code, _, _} = Mod:msg_header(MsgName); %% ensure Code
-
h(Mod, MsgName, _) ->
Mod:msg_header(MsgName).
@@ -290,7 +281,8 @@ decode_avps(MsgName, Mod, Pkt, {Bs, Avps}) -> %% invalid avp bits ...
decode_avps('', Mod, Pkt, Avps) -> %% unknown message ...
?LOG(unknown, {Mod, Pkt#diameter_packet.header}),
- Pkt#diameter_packet{errors = lists:reverse(Avps)};
+ Pkt#diameter_packet{avps = lists:reverse(Avps),
+ errors = [3001]}; %% DIAMETER_COMMAND_UNSUPPORTED
%% msg = undefined identifies this case.
decode_avps(MsgName, Mod, Pkt, Avps) -> %% ... or not
diff --git a/lib/diameter/src/app/diameter_config.erl b/lib/diameter/src/app/diameter_config.erl
index 42c70890b3..a6b48fe65b 100644
--- a/lib/diameter/src/app/diameter_config.erl
+++ b/lib/diameter/src/app/diameter_config.erl
@@ -267,7 +267,7 @@ handle_call(uptime, _, #state{id = Time} = State) ->
{reply, diameter_lib:now_diff(Time), State};
handle_call(Req, From, State) ->
- warning_msg("received unexpected request from ~p:~n~w", [From, Req]),
+ ?UNEXPECTED([Req, From]),
Reply = {error, {bad_request, Req}},
{reply, Reply, State}.
@@ -276,7 +276,7 @@ handle_call(Req, From, State) ->
%%% ----------------------------------------------------------
handle_cast(Msg, State) ->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -309,7 +309,7 @@ handle_info(restart, State) ->
{noreply, State};
handle_info(Info, State) ->
- warning_msg("received unknown info:~n~w", [Info]),
+ ?UNEXPECTED([Info]),
{noreply, State}.
%%--------------------------------------------------------------------
@@ -674,8 +674,3 @@ cb(M,F) ->
call(Request) ->
gen_server:call(?SERVER, Request, infinity).
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/diameter_internal.hrl b/lib/diameter/src/app/diameter_internal.hrl
index 9de3914830..78645b1912 100644
--- a/lib/diameter/src/app/diameter_internal.hrl
+++ b/lib/diameter/src/app/diameter_internal.hrl
@@ -37,9 +37,10 @@
%% Failure reports always get a stack trace.
-define(STACK, erlang:get_stacktrace()).
-%% Info report for anything unexpected.
--define(REPORT(Reason, Func, Args),
- diameter_lib:report(Reason, {?MODULE, Func, Args})).
+%% Warning report for unexpected messages in various processes.
+-define(UNEXPECTED(F,A),
+ diameter_lib:warning_report(unexpected, {?MODULE, F, A})).
+-define(UNEXPECTED(A), ?UNEXPECTED(?FUNC, A)).
%% Something to trace on.
-define(LOG(Slogan, Details),
@@ -77,19 +78,3 @@
server_id,
is_dynamic,
expiration}).
-
-%%%----------------------------------------------------------------------
-%%% Error/warning/info message macro(s)
-%%%----------------------------------------------------------------------
-
--define(diameter_info(F, A),
- (catch error_logger:info_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
- [?APPLICATION, ?MODULE, self()|A]))).
-
--define(diameter_warning(F, A),
- (catch error_logger:warning_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
- [?APPLICATION, ?MODULE, self()|A]))).
-
--define(diameter_error(F, A),
- (catch error_logger:error_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
- [?APPLICATION, ?MODULE, self()|A]))).
diff --git a/lib/diameter/src/app/diameter_lib.erl b/lib/diameter/src/app/diameter_lib.erl
index b5c0e1bf6a..f65e356444 100644
--- a/lib/diameter/src/app/diameter_lib.erl
+++ b/lib/diameter/src/app/diameter_lib.erl
@@ -46,14 +46,9 @@
report(Reason, MFA) ->
info_report(Reason, MFA).
-info_report(Reason, {M,F,A}) ->
- error_logger:info_report(" Reason: ~p~n"
- " Pid: ~p~n"
- " Node: ~p~n"
- " Module: ~p~n"
- " Function: ~p~n"
- "Arguments: ~p~n",
- [Reason, self(), node(), M, F, A]).
+info_report(Reason, MFA) ->
+ report(fun error_logger:info_report/1, Reason, MFA),
+ true.
%%% ---------------------------------------------------------------------------
%%% # error_report(Reason, MFA)
@@ -69,7 +64,7 @@ warning_report(Reason, MFA) ->
report(fun error_logger:warning_report/1, Reason, MFA).
report(Fun, Reason, MFA) ->
- Fun([{reason, Reason}, {who, self()}, {where, node()}, {what, MFA}]),
+ Fun([{why, Reason}, {who, self()}, {what, MFA}]),
false.
%%% ---------------------------------------------------------------------------
@@ -255,12 +250,13 @@ w(L) ->
fold_tuple(_, T, undefined) ->
T;
-fold_tuple(N, T0, T) ->
- element(2, lists:foldl(fun(X, {M,_} = A) -> {M+1, ft(X, A)} end,
- {N, T0},
- lists:nthtail(N-1, tuple_to_list(T)))).
+fold_tuple(N, T0, T1) ->
+ {_, T} = lists:foldl(fun(V, {I,_} = IT) -> {I+1, ft(V, IT)} end,
+ {N, T0},
+ lists:nthtail(N-1, tuple_to_list(T1))),
+ T.
-ft(undefined, T) ->
+ft(undefined, {_, T}) ->
T;
-ft(X, {N, T}) ->
- setelement(N, T, X).
+ft(Value, {Idx, T}) ->
+ setelement(Idx, T, Value).
diff --git a/lib/diameter/src/app/diameter_peer.erl b/lib/diameter/src/app/diameter_peer.erl
index 6b8971b8ea..3e78c4caef 100644
--- a/lib/diameter/src/app/diameter_peer.erl
+++ b/lib/diameter/src/app/diameter_peer.erl
@@ -148,7 +148,7 @@ handle_call(uptime, _, #state{id = Time} = State) ->
{reply, diameter_lib:now_diff(Time), State};
handle_call(Req, From, State) ->
- warning_msg("received unexpected request from ~p:~n~w", [From, Req]),
+ ?UNEXPECTED([Req, From]),
{reply, nok, State}.
%%% ----------------------------------------------------------
@@ -156,7 +156,7 @@ handle_call(Req, From, State) ->
%%% ----------------------------------------------------------
handle_cast(Msg, State) ->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -169,7 +169,7 @@ handle_info({notify, SvcName, T}, S) ->
{noreply, S};
handle_info(Info, State) ->
- warning_msg("received unexpected info:~n~w", [Info]),
+ ?UNEXPECTED([Info]),
{noreply, State}.
%% ----------------------------------------------------------
@@ -223,8 +223,3 @@ value([], V) ->
call(Request) ->
gen_server:call(?SERVER, Request, infinity).
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/diameter_reg.erl b/lib/diameter/src/app/diameter_reg.erl
index 8e5f34c2c3..882b9da238 100644
--- a/lib/diameter/src/app/diameter_reg.erl
+++ b/lib/diameter/src/app/diameter_reg.erl
@@ -243,7 +243,8 @@ handle_call(state, _, State) ->
handle_call(uptime, _, #state{id = Time} = State) ->
{reply, diameter_lib:now_diff(Time), State};
-handle_call(_Req, _From, State) ->
+handle_call(Req, From, State) ->
+ ?UNEXPECTED([Req, From]),
{reply, nok, State}.
%%% ----------------------------------------------------------
@@ -251,7 +252,7 @@ handle_call(_Req, _From, State) ->
%%% ----------------------------------------------------------
handle_cast(Msg, State)->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -264,7 +265,7 @@ handle_info({'DOWN', MRef, process, Pid, _}, State) ->
{noreply, State};
handle_info(Info, State) ->
- warning_msg("received unknown info:~n~w", [Info]),
+ ?UNEXPECTED([Info]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -324,8 +325,3 @@ repl([], _, _) ->
call(Request) ->
gen_server:call(?SERVER, Request, infinity).
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/app/diameter_service.erl
index 63b0649dc4..421e36ccf5 100644
--- a/lib/diameter/src/app/diameter_service.erl
+++ b/lib/diameter/src/app/diameter_service.erl
@@ -463,7 +463,7 @@ handle_call(stop, _From, S) ->
%% stating a monitor that waits for DOWN before returning.
handle_call(Req, From, S) ->
- ?REPORT(unknown_request, ?FUNC, [Req, From]),
+ unexpected(handle_call, [Req, From], S),
{reply, nok, S}.
%%% ---------------------------------------------------------------------------
@@ -471,7 +471,7 @@ handle_call(Req, From, S) ->
%%% ---------------------------------------------------------------------------
handle_cast(Req, S) ->
- ?REPORT(unknown_request, ?FUNC, [Req]),
+ unexpected(handle_cast, [Req], S),
{noreply, S}.
%%% ---------------------------------------------------------------------------
@@ -553,8 +553,8 @@ transition({failover, TRef, Seqs}, S) ->
failover(TRef, Seqs, S),
ok;
-transition(Req, _) ->
- ?REPORT(unknown_request, ?FUNC, [Req]),
+transition(Req, S) ->
+ unexpected(handle_info, [Req], S),
ok.
%%% ---------------------------------------------------------------------------
@@ -591,6 +591,9 @@ code_change(FromVsn, SvcName, Extra, #diameter_app{alias = Alias} = A) ->
%% ===========================================================================
%% ===========================================================================
+unexpected(F, A, #state{service_name = Name}) ->
+ ?UNEXPECTED(F, A ++ [Name]).
+
cb([_|_] = M, F, A) ->
eval(M, F, A);
cb(Rec, F, A) ->
@@ -1398,15 +1401,15 @@ recv_answer(Timeout,
%% is, from the last peer to which we've transmitted.
receive
- {answer = A, Ref, Rq, Pkt} -> %% Answer from peer.
+ {answer = A, Ref, Rq, Pkt} -> %% Answer from peer
{A, Rq, Pkt};
- {timeout = Reason, TRef, _} -> %% No timely reply
+ {timeout = Reason, TRef, _} -> %% No timely reply
{error, Req, Reason};
- {failover = Reason, TRef, false} -> %% No alternative peer.
+ {failover = Reason, TRef, false} -> %% No alternate peer
{error, Req, Reason};
- {failover, TRef, Transport} -> %% Resend to alternate peer.
+ {failover, TRef, Transport} -> %% Resend to alternate peer
try_retransmit(Timeout, SvcName, Req, Transport);
- {failover, TRef} -> %% May have missed failover notification.
+ {failover, TRef} -> %% May have missed failover notification
Seqs = diameter_codec:sequence_numbers(RPkt),
Pid = whois(SvcName),
is_pid(Pid) andalso (Pid ! {failover, TRef, Seqs}),
@@ -1685,9 +1688,9 @@ recv_request({Id, Alias}, T, TPid, Apps, Caps, Pkt) ->
%% DIAMETER_APPLICATION_UNSUPPORTED 3007
%% A request was sent for an application that is not supported.
-recv_request(false, {_, OH, OR}, TPid, _, _, Pkt) ->
- ?LOG({error, application}, Pkt),
- reply(answer_message({OH, OR, 3007}, collect_avps(Pkt)), ?BASE, TPid, Pkt).
+recv_request(false, T, TPid, _, _, Pkt) ->
+ As = collect_avps(Pkt),
+ protocol_error(3007, T, TPid, Pkt#diameter_packet{avps = As}).
collect_avps(Pkt) ->
case diameter_codec:collect_avps(Pkt) of
@@ -1706,13 +1709,9 @@ collect_avps(Pkt) ->
%% set to an unrecognized value, or that is inconsistent with the
%% AVP's definition.
%%
-recv_request({_, OH, OR}, {TPid, _}, _, #diameter_packet{errors = [Bs | _],
- bin = Bin,
- avps = Avps}
- = Pkt)
+recv_request(T, {TPid, _}, _, #diameter_packet{errors = [Bs | _]} = Pkt)
when is_bitstring(Bs) ->
- ?LOG({error, invalid_avp_bits}, Bin),
- reply(answer_message({OH, OR, 3009}, Avps), ?BASE, TPid, Pkt);
+ protocol_error(3009, T, TPid, Pkt);
%% Either we support this application but don't recognize the command
%% or we're a relay and the command isn't proxiable.
@@ -1722,18 +1721,15 @@ recv_request({_, OH, OR}, {TPid, _}, _, #diameter_packet{errors = [Bs | _],
%% recognize or support. This MUST be used when a Diameter node
%% receives an experimental command that it does not understand.
%%
-recv_request({_, OH, OR},
+recv_request(T,
{TPid, _},
#diameter_app{id = Id},
#diameter_packet{header = #diameter_header{is_proxiable = P},
- msg = M,
- avps = Avps,
- bin = Bin}
+ msg = M}
= Pkt)
when ?APP_ID_RELAY /= Id, undefined == M;
?APP_ID_RELAY == Id, not P ->
- ?LOG({error, command_unsupported}, Bin),
- reply(answer_message({OH, OR, 3001}, Avps), ?BASE, TPid, Pkt);
+ protocol_error(3001, T, TPid, Pkt);
%% Error bit was set on a request.
%%
@@ -1742,15 +1738,12 @@ recv_request({_, OH, OR},
%% either set to an invalid combination, or to a value that is
%% inconsistent with the command code's definition.
%%
-recv_request({_, OH, OR},
+recv_request(T,
{TPid, _},
_,
- #diameter_packet{header = #diameter_header{is_error = true},
- avps = Avps,
- bin = Bin}
+ #diameter_packet{header = #diameter_header{is_error = true}}
= Pkt) ->
- ?LOG({error, error_bit}, Bin),
- reply(answer_message({OH, OR, 3008}, Avps), ?BASE, TPid, Pkt);
+ protocol_error(3008, T, TPid, Pkt);
%% A message in a locally supported application or a proxiable message
%% in the relay application. Don't distinguish between the two since
@@ -1878,7 +1871,7 @@ resend(true, _, _, T, {TPid, _}, Pkt) -> %% Route-Record loop
resend(false,
Opts,
App,
- {SvcName, _, _},
+ {SvcName, _, _} = T,
{TPid, #diameter_caps{origin_host = {_, OH}}},
#diameter_packet{header = Hdr0,
avps = Avps}
@@ -1887,46 +1880,41 @@ resend(false,
Seq = diameter_session:sequence(),
Hdr = Hdr0#diameter_header{hop_by_hop_id = Seq},
Msg = [Hdr, Route | Avps],
- %% Filter sender as ineligible receiver.
- reply(call(SvcName, App, Msg, [{filter, {neg, {host, OH}}} | Opts]),
- TPid,
- Pkt).
+ resend(call(SvcName, App, Msg, Opts), T, TPid, Pkt).
%% The incoming request is relayed with the addition of a
-%% Route-Record. Note the requirement on the return from call/4.
-%% This places a requirement on the values returned by the
-%% handle_answer and handle_error callbacks of the application module
-%% in question.
+%% Route-Record. Note the requirement on the return from call/4 below,
+%% which places a requirement on the value returned by the
+%% handle_answer callback of the application module in question.
+%%
+%% Note that there's nothing stopping the request from being relayed
+%% back to the sender. A pick_peer callback may want to avoid this but
+%% a smart peer might recognize the potential loop and choose another
+%% route. A less smart one will probably just relay the request back
+%% again and force us to detect the loop. A pick_peer that wants to
+%% avoid this can specify filter to avoid the possibility.
+%% Eg. {neg, {host, OH} where #diameter_caps{origin_host = {OH, _}}.
%%
%% RFC 6.3 says that a relay agent does not modify Origin-Host but
%% says nothing about a proxy. Assume it should behave the same way.
-%% reply/3
+%% resend/4
%%
%% Relay a reply to a relayed request.
%% Answer from the peer: reset the hop by hop identifier and send.
-reply(#diameter_packet{bin = B}
- = Pkt,
- TPid,
- #diameter_packet{header = #diameter_header{hop_by_hop_id = Id},
- transport_data = TD}) ->
+resend(#diameter_packet{bin = B}
+ = Pkt,
+ _,
+ TPid,
+ #diameter_packet{header = #diameter_header{hop_by_hop_id = Id},
+ transport_data = TD}) ->
send(TPid, Pkt#diameter_packet{bin = diameter_codec:hop_by_hop_id(Id, B),
transport_data = TD});
%% TODO: counters
-%% Not. Ignoring the error feels harsh but there is no appropriate
-%% Result-Code for a protocol error (which this isn't really anyway)
-%% and the RFC doesn't provide any guidance how to act. A weakness
-%% here is that we don't deal well with a decode error: the request
-%% will simply timeout on the peer's end. Better would be to just send
-%% the answer (with modified hop by hop identifier) on regardless, at
-%% least in the relay case in which there's no examination of the
-%% answer. In the proxy case it's not clear that the callback won't
-%% examine the answer. Just be quiet here since a decode error causes
-%% the request process to crash (or not depending on the error and
-%% config and/or handle_answer callback).
-reply(_, _, _) ->
- ok.
+%% Or not: DIAMETER_UNABLE_TO_DELIVER.
+resend(_, T, TPid, Pkt) ->
+ protocol_error(3002, T, TPid, Pkt).
%% is_loop/4
%%
@@ -1971,24 +1959,20 @@ reply(Msg, Dict, TPid, #diameter_packet{errors = [H|_] = Es} = Pkt) ->
%% make_reply_packet/2
+%% Binaries and header/avp lists are sent as-is.
make_reply_packet(Bin, _)
when is_binary(Bin) ->
#diameter_packet{bin = Bin};
-
make_reply_packet([#diameter_header{} | _] = Msg, _) ->
#diameter_packet{msg = Msg};
+%% Otherwise a reply message clears the R and T flags and retains the
+%% P flag. The E flag will be set at encode.
make_reply_packet(Msg, #diameter_packet{header = ReqHdr}) ->
- #diameter_header{end_to_end_id = EId,
- hop_by_hop_id = Hid,
- is_proxiable = P}
- = ReqHdr,
-
- Hdr = #diameter_header{version = ?DIAMETER_VERSION,
- end_to_end_id = EId,
- hop_by_hop_id = Hid,
- is_proxiable = P,
- is_retransmitted = false},
+ Hdr = ReqHdr#diameter_header{version = ?DIAMETER_VERSION,
+ is_request = false,
+ is_error = undefined,
+ is_retransmitted = false},
#diameter_packet{header = Hdr,
msg = Msg}.
@@ -2126,16 +2110,6 @@ answer_message({OH, OR, RC}, Avps) ->
session_id(Code, Vid, Avps)
when is_list(Avps) ->
try
- {value, #diameter_avp{} = Avp} = find_avp(Code, Vid, Avps),
- Avp
- catch
- error: _ ->
- []
- end;
-
-session_id(Code, Vid, Avps)
- when is_list(Avps) ->
- try
{value, #diameter_avp{data = D}} = find_avp(Code, Vid, Avps),
[{'Session-Id', [?BASE:avp(decode, D, 'Session-Id')]}]
catch
@@ -2482,6 +2456,7 @@ rpd(Pid, Alias, PDict) ->
%%%
%%% Output: {TransportPid, #diameter_caps{}, #diameter_app{}}
%%% | false
+%%% | {error, Reason}
%%% ---------------------------------------------------------------------------
%% Initial call, from an arbitrary process.
@@ -2540,28 +2515,18 @@ get_destination(Msg, Dict) ->
[str(get_avp_value(Dict, 'Destination-Realm', Msg)),
str(get_avp_value(Dict, 'Destination-Host', Msg))].
-%% TODO:
-%%
-%% Should add some way of specifying destination directly so that the
-%% only requirement is that the prepare_request callback returns
-%% something specific. (eg. {host, DH}; that is, let the caller specify.)
-%%
-%% Also, there is no longer any need to call get_destination at all in
-%% the default case.
-
-str(T)
- when T == undefined;
- T == [] ->
+%% This is not entirely correct. The avp could have an arity 1, in
+%% which case an empty list is a DiameterIdentity of length 0 rather
+%% than the list of no values we treat it as by mapping to undefined.
+%% This behaviour is documented.
+str([]) ->
undefined;
-str([X])
- when is_list(X) ->
- X;
str(T) ->
T.
%% get_avp_value/3
%%
-%% Support outgoing messages in one of three forms:
+%% 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.
@@ -2593,8 +2558,9 @@ get_avp_value(_, Name, [_MsgName | Avps]) ->
undefined
end;
-get_avp_value(Dict, Name, Rec)
- when is_tuple(Rec) ->
+%% Message is typically a record but not necessarily: diameter:call/4
+%% can be passed an arbitrary term.
+get_avp_value(Dict, Name, Rec) ->
try
Dict:'#get-'(Name, Rec)
catch
@@ -2690,7 +2656,8 @@ peers(Alias, RH, Filter, Peers) ->
end.
%% Place a peer whose Destination-Host/Realm matches those of the
-%% request at the front of the result list.
+%% request at the front of the result list. Could add some sort of
+%% 'sort' option to allow more control.
ps([], _, _, {Ys, Ns}) ->
lists:reverse(Ys, Ns);
@@ -2700,11 +2667,11 @@ ps([{_TPid, #diameter_caps{} = Caps} = TC | Rest], RH, Filter, Acc) ->
TC,
Acc)).
-pacc(true, true, TC, {Ts, Fs}) ->
- {[TC|Ts], Fs};
-pacc(true, false, TC, {Ts, Fs}) ->
- {Ts, [TC|Fs]};
-pacc(false, _, _, Acc) ->
+pacc(true, true, Peer, {Ts, Fs}) ->
+ {[Peer|Ts], Fs};
+pacc(true, false, Peer, {Ts, Fs}) ->
+ {Ts, [Peer|Fs]};
+pacc(_, _, _, Acc) ->
Acc.
%% caps_filter/3
@@ -2712,17 +2679,19 @@ pacc(false, _, _, Acc) ->
caps_filter(C, RH, {neg, F}) ->
not caps_filter(C, RH, F);
-caps_filter(C, RH, {all, L}) ->
+caps_filter(C, RH, {all, L})
+ when is_list(L) ->
lists:all(fun(F) -> caps_filter(C, RH, F) end, L);
-caps_filter(C, RH, {any, L}) ->
+caps_filter(C, RH, {any, L})
+ when is_list(L) ->
lists:any(fun(F) -> caps_filter(C, RH, F) end, L);
-caps_filter(#diameter_caps{origin_host = {_,H}}, [_,DH], host) ->
- eq(undefined, DH, H);
+caps_filter(#diameter_caps{origin_host = {_,OH}}, [_,DH], host) ->
+ eq(undefined, DH, OH);
-caps_filter(#diameter_caps{origin_realm = {_,R}}, [DR,_], realm) ->
- eq(undefined, DR, R);
+caps_filter(#diameter_caps{origin_realm = {_,OR}}, [DR,_], realm) ->
+ eq(undefined, DR, OR);
caps_filter(C, _, Filter) ->
caps_filter(C, Filter).
@@ -2738,6 +2707,9 @@ caps_filter(#diameter_caps{origin_host = {_,OH}}, {host, H}) ->
caps_filter(#diameter_caps{origin_realm = {_,OR}}, {realm, R}) ->
eq(any, R, OR);
+%% Anything else is expected to be an eval filter. Filter failure is
+%% documented as being equivalent to a non-matching filter.
+
caps_filter(C, T) ->
try
{eval, F} = T,
@@ -2746,8 +2718,14 @@ caps_filter(C, T) ->
_:_ -> false
end.
-eq(X, A, B) ->
- X == A orelse A == B.
+eq(Any, Id, PeerId) ->
+ Any == Id orelse try
+ iolist_to_binary(Id) == iolist_to_binary(PeerId)
+ catch
+ _:_ -> false
+ end.
+%% OctetString() can be specified as an iolist() so test for string
+%% rather then term equality.
%% transports/1
diff --git a/lib/diameter/src/app/diameter_stats.erl b/lib/diameter/src/app/diameter_stats.erl
index b52d4cdcfb..71479afa95 100644
--- a/lib/diameter/src/app/diameter_stats.erl
+++ b/lib/diameter/src/app/diameter_stats.erl
@@ -207,7 +207,7 @@ handle_call({flush, Contrib}, _From, State) ->
{reply, fetch(Contrib), State};
handle_call(Req, From, State) ->
- warning_msg("received unexpected request from ~p:~n~w", [From, Req]),
+ ?UNEXPECTED([Req, From]),
{reply, nok, State}.
%% ----------------------------------------------------------
@@ -219,7 +219,7 @@ handle_cast({incr, Rec}, State) ->
{noreply, State};
handle_cast(Msg, State) ->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%% ----------------------------------------------------------
@@ -231,7 +231,7 @@ handle_info({'DOWN', _MRef, process, Pid, _}, State) ->
{noreply, State};
handle_info(Info, State) ->
- warning_msg("received unknown info:~n~w", [Info]),
+ ?UNEXPECTED([Info]),
{noreply, State}.
%% ----------------------------------------------------------
@@ -340,8 +340,3 @@ cast(Msg) ->
call(Request) ->
gen_server:call(?SERVER, Request, infinity).
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/app/diameter_sync.erl b/lib/diameter/src/app/diameter_sync.erl
index f7777ae809..ce2db4b3a2 100644
--- a/lib/diameter/src/app/diameter_sync.erl
+++ b/lib/diameter/src/app/diameter_sync.erl
@@ -204,37 +204,37 @@ handle_call(?REQUEST(Type, Name, Req, Max, Timeout),
T = find(Name, QD),
nq(queued(T) =< Max, T, {Type, From}, Name, Req, Timeout, State);
-handle_call(Request, _From, State) ->
- {reply, call(Request, State), State}.
+handle_call(Request, From, State) ->
+ {reply, call(Request, From, State), State}.
-%% call/2
+%% call/3
-call(?CARP(Name), #state{queue = QD}) ->
+call(?CARP(Name), _, #state{queue = QD}) ->
pcar(find(Name, QD));
-call(state, State) ->
+call(state, _, State) ->
State;
-call(uptime, #state{time = T}) ->
+call(uptime, _, #state{time = T}) ->
diameter_lib:now_diff(T);
-call({flush, Name}, #state{queue = QD}) ->
+call({flush, Name}, _, #state{queue = QD}) ->
cancel(find(Name, QD));
-call(pending, #state{pending = N}) ->
+call(pending, _, #state{pending = N}) ->
N;
-call({pending, Name}, #state{queue = QD}) ->
+call({pending, Name}, _, #state{queue = QD}) ->
queued(find(Name, QD));
-call(queues, #state{queue = QD}) ->
+call(queues, _, #state{queue = QD}) ->
fetch_keys(QD);
-call({pids, Name}, #state{queue = QD}) ->
+call({pids, Name}, _, #state{queue = QD}) ->
plist(find(Name, QD));
-call(Req, _State) -> %% ignore
- warning_msg("received unexpected request:~n~w", [Req]),
+call(Req, From, _State) -> %% ignore
+ ?UNEXPECTED(handle_call, [Req, From]),
nok.
%%% ----------------------------------------------------------
@@ -242,7 +242,7 @@ call(Req, _State) -> %% ignore
%%% ----------------------------------------------------------
handle_cast(Msg, State) ->
- warning_msg("received unexpected message:~n~w", [Msg]),
+ ?UNEXPECTED([Msg]),
{noreply, State}.
%%% ----------------------------------------------------------
@@ -267,7 +267,7 @@ info({'DOWN', MRef, process, Pid, Info},
queue = dq(fetch(Name, QD), Pid, Info, Name, QD)};
info(Info, State) ->
- warning_msg("received unknown info:~n~w", [Info]),
+ ?UNEXPECTED(handle_info, [Info]),
State.
reply({call, From}, T) ->
@@ -548,8 +548,3 @@ gen_call(Server, Req, Timeout) ->
exit: _ ->
timeout
end.
-
-%% warning_msg/2
-
-warning_msg(F, A) ->
- ?diameter_warning("~p: " ++ F, [?MODULE | A]).
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 30caebc544..a33b07a3d3 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -37,7 +37,6 @@
file/2,
file/3]).
--include_lib("diameter/src/app/diameter_internal.hrl").
-include("diameter_forms.hrl").
%% Generated functions that could have no generated clauses will have