diff options
| -rw-r--r-- | lib/diameter/src/base/diameter_config.erl | 7 | ||||
| -rw-r--r-- | lib/diameter/src/base/diameter_service.erl | 2 | ||||
| -rw-r--r-- | lib/diameter/src/base/diameter_traffic.erl | 42 | ||||
| -rw-r--r-- | lib/diameter/test/diameter_traffic_SUITE.erl | 7 | 
4 files changed, 47 insertions, 11 deletions
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 1db9b52dfa..99d8c8c6ec 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); diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index be50e87179..8e383818ea 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 54f39afbf0..af7ac10f13 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -212,8 +212,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{}}, @@ -230,9 +231,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, _) -> @@ -254,18 +256,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}} diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index f2e796005d..7c36b3f82b 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -203,8 +203,7 @@           {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]},           {restrict_connections, false},           {string_decode, Decode}, -         {incoming_maxlen, 1 bsl 21}, -         {spawn_opt, [{min_heap_size, 5000}]} +         {incoming_maxlen, 1 bsl 21}           | [{application, [{dictionary, D},                             {module, ?MODULE},                             {answer_errors, callback}]} @@ -466,8 +465,8 @@ add_transports(Config) ->                              || T == sctp andalso CS]],                          [{capabilities_cb, fun capx/2},                           {pool_size, 8}, -                         {spawn_opt, [{min_heap_size, 8096}]}, -                         {applications, apps(rfc3588)}]), +                         {applications, apps(rfc3588)}] +                        ++ [{spawn_opt, {erlang, spawn, []}} || CS]),      Cs = [?util:connect(CN,                          [T, {sender, CS}],                          LRef,  | 
