aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter/src/base
diff options
context:
space:
mode:
Diffstat (limited to 'lib/diameter/src/base')
-rw-r--r--lib/diameter/src/base/diameter_callback.erl4
-rw-r--r--lib/diameter/src/base/diameter_config.erl9
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl2
-rw-r--r--lib/diameter/src/base/diameter_service.erl2
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl42
5 files changed, 48 insertions, 11 deletions
diff --git a/lib/diameter/src/base/diameter_callback.erl b/lib/diameter/src/base/diameter_callback.erl
index f479cb6612..f9cdc66c70 100644
--- a/lib/diameter/src/base/diameter_callback.erl
+++ b/lib/diameter/src/base/diameter_callback.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@
%% in a callback applied to the atom-valued callback name and argument
%% list. For all callbacks not to this module, the 'extra' field is a
%% list of additional arguments, following arguments supplied by
-%% diameter but preceeding those of the diameter:evaluable() being
+%% diameter but preceding those of the diameter:evaluable() being
%% applied.
%%
%% For example, the following config to diameter:start_service/2, in
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 1db9b52dfa..34018ae6d3 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -610,6 +610,9 @@ opt({watchdog_timer, Tmo}) ->
opt({watchdog_config, L}) ->
is_list(L) andalso lists:all(fun wdopt/1, L);
+opt({spawn_opt, {M,F,A}})
+ when is_atom(M), is_atom(F), is_list(A) ->
+ true;
opt({spawn_opt = K, Opts}) ->
if is_list(Opts) ->
{value, {K, spawn_opts(Opts)}};
@@ -739,6 +742,10 @@ opt(incoming_maxlen, N)
when 0 =< N, N < 1 bsl 24 ->
N;
+opt(spawn_opt, {M,F,A} = T)
+ when is_atom(M), is_atom(F), is_list(A) ->
+ T;
+
opt(spawn_opt, L)
when is_list(L) ->
spawn_opts(L);
@@ -881,7 +888,7 @@ init_cb(List) ->
V <- [proplists:get_value(F, List, D)]],
#diameter_callback{} = list_to_tuple([diameter_callback | Values]).
-%% Retreive and validate.
+%% Retrieve and validate.
get_opt(Key, List, Def, Other) ->
init_opt(Key, get_opt(Key, List, Def), [Def|Other]).
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index a5dab45684..1b0dc417e5 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -367,7 +367,7 @@ handle_info(T, #state{} = State) ->
%% Note that there's no guarantee that the service and transport
%% capabilities are good enough to build a CER/CEA that can be
-%% succesfully encoded. It's not checked at diameter:add_transport/2
+%% successfully encoded. It's not checked at diameter:add_transport/2
%% since this can be called before creating the service.
%% terminate/2
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 4fc49309b5..a976a8b998 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -114,7 +114,7 @@
incoming_maxlen := diameter:message_length(),
strict_mbit := boolean(),
string_decode := boolean(),
- spawn_opt := list()}}).
+ spawn_opt := list() | {module(), atom(), list()}}}).
%% Record representing an RFC 3539 watchdog process implemented by
%% diameter_watchdog.
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index 7a5a3d662a..85378babea 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -213,8 +213,9 @@ incr_rc(Dir, Pkt, TPid, Dict0) ->
%% ---------------------------------------------------------------------------
-spec receive_message(pid(), Route, #diameter_packet{}, module(), RecvData)
- -> pid()
- | boolean()
+ -> pid() %% request handler
+ | boolean() %% answer, known request or not
+ | discard %% request discarded by MFA
when Route :: {Handler, RequestRef, Seqs}
| Ack,
RecvData :: {[SpawnOpt], #recvdata{}},
@@ -231,9 +232,10 @@ receive_message(TPid, Route, Pkt, Dict0, RecvData) ->
%% recv/6
%% Incoming request ...
-recv(true, Ack, TPid, Pkt, Dict0, RecvData)
+recv(true, Ack, TPid, Pkt, Dict0, T)
when is_boolean(Ack) ->
- spawn_request(Ack, TPid, Pkt, Dict0, RecvData);
+ {Opts, RecvData} = T,
+ spawn_request(Ack, TPid, Pkt, Dict0, RecvData, Opts);
%% ... answer to known request ...
recv(false, {Pid, Ref, TPid}, _, Pkt, Dict0, _) ->
@@ -255,18 +257,46 @@ recv(false, false, TPid, Pkt, _, _) ->
incr(TPid, {{unknown, 0}, recv, discarded}),
false.
-%% spawn_request/5
+%% spawn_request/6
-spawn_request(Ack, TPid, Pkt, Dict0, {Opts, RecvData}) ->
+%% An MFA should return a pid() or the atom 'discard'. The latter
+%% results in an acknowledgment back to the transport process when
+%% appropriate, to ensure that send/recv callbacks can count
+%% outstanding requests. Acknowledgement is implicit if the
+%% handler process dies (in a handle_request callback for example).
+spawn_request(Ack, TPid, Pkt, Dict0, RecvData, {M,F,A}) ->
+ ReqF = fun() ->
+ ack(Ack, TPid, recv_request(Ack, TPid, Pkt, Dict0, RecvData))
+ end,
+ ack(Ack, TPid, apply(M, F, [ReqF | A]));
+
+%% A spawned process acks implicitly when it dies, so there's no need
+%% to handle 'discard'.
+spawn_request(Ack, TPid, Pkt, Dict0, RecvData, Opts) ->
spawn_opt(fun() ->
recv_request(Ack, TPid, Pkt, Dict0, RecvData)
end,
Opts).
+%% ack/3
+
+ack(Ack, TPid, RC) ->
+ RC == discard andalso Ack andalso (TPid ! {send, false}),
+ RC.
+
%% ---------------------------------------------------------------------------
%% recv_request/5
%% ---------------------------------------------------------------------------
+-spec recv_request(Ack :: boolean(),
+ TPid :: pid(),
+ #diameter_packet{},
+ Dict0 :: module(),
+ #recvdata{})
+ -> ok %% answer was sent
+ | discard %% or not
+ | false. %% no transport
+
recv_request(Ack,
TPid,
#diameter_packet{header = #diameter_header{application_id = Id}}