From 91a223d37d6b57f53d26135a4cbaf4ac22854ba2 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Thu, 15 Nov 2012 10:52:58 +0100 Subject: Allow a handle_request callback to return a #diameter_packet{} This allows it to set transport_data and header, inappropriately so even. --- lib/diameter/doc/src/diameter_app.xml | 24 ++++++++++----- lib/diameter/src/base/diameter_service.erl | 49 ++++++++++++++++++------------ 2 files changed, 46 insertions(+), 27 deletions(-) (limited to 'lib/diameter') diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml index ac056c2d39..b6870f7c28 100644 --- a/lib/diameter/doc/src/diameter_app.xml +++ b/lib/diameter/doc/src/diameter_app.xml @@ -382,7 +382,7 @@ communicate transport (or any other) data to the callback.

A returned packet() can set the header field to a -#diameter_header{} in order to specify values that should +#diameter_header{} to specify values that should be preserved in the outgoing request, values otherwise being those in the header record contained in Packet. A returned length, cmd_code or application_id is @@ -537,7 +537,8 @@ not selected.

| {relay, [Opt]} | discard | {eval|eval_packet, Action, PostF} -Reply = {reply, message()} +Reply = {reply, packet() + | message()} | {protocol_error, 3000..3999} Opt = diameter:call_opt() PostF = diameter:evaluable() @@ -568,7 +569,7 @@ The argument packet() has the following sign

-The msg field will be undefined only in case the request has +The msg field will be undefined in case the request has been received in the relay application. Otherwise it contains the record representing the request as outlined in The transport_data field contains an arbitrary term passed into diameter from the transport module in question, or the atom undefined if the transport specified no data. -The term is preserved in the packet() containing any answer message -sent back to the transport process unless another value is explicitly -specified.

+The term is preserved if a message() is returned but must be set +explicitly in a returned packet().

The semantics of each of the possible return values are as follows.

-{reply, message()} +{reply, packet() + | message()}

-Send the specified answer message to the peer.

+Send the specified answer message to the peer. +In the case of a packet(), the +message to be sent must be set in the +msg field and the header field can be set to a +#diameter_header{} to specify values that should be +preserved in the outgoing answer, appropriate values otherwise +being set by diameter.

{protocol_error, 3000..3999} diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 0a0fd6ded1..467bb585cd 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -2175,15 +2175,13 @@ reply([Msg], Dict, TPid, Fs, Pkt) reply(Msg, Dict, TPid, Fs, Pkt#diameter_packet{errors = []}); %% No errors or a diameter_header/avp list. -reply(Msg, Dict, TPid, Fs, #diameter_packet{errors = Es, - transport_data = TD} - = ReqPkt) +reply(Msg, Dict, TPid, Fs, #diameter_packet{errors = Es} = ReqPkt) when [] == Es; is_record(hd(Msg), diameter_header) -> Pkt = diameter_codec:encode(Dict, make_answer_packet(Msg, ReqPkt)), eval_packet(Pkt, Fs), incr(send, Pkt, Dict, TPid), %% count result codes in sent answers - send(TPid, Pkt#diameter_packet{transport_data = TD}); + send(TPid, Pkt); %% Or not: set Result-Code and Failed-AVP AVP's. reply(Msg, Dict, TPid, Fs, #diameter_packet{errors = [H|_] = Es} = Pkt) -> @@ -2198,23 +2196,36 @@ eval_packet(Pkt, Fs) -> %% make_answer_packet/2 +%% A reply message clears the R and T flags and retains the P flag. +%% The E flag will be set at encode. 6.2 of 3588 requires the same P +%% flag on an answer as on the request. A #diameter_packet{} returned +%% from a handle_request callback can circumvent this by setting its +%% own header values. +make_answer_packet(#diameter_packet{header = Hdr, + msg = Msg, + transport_data = TD}, + #diameter_packet{header = ReqHdr}) -> + Hdr0 = ReqHdr#diameter_header{version = ?DIAMETER_VERSION, + is_request = false, + is_error = undefined, + is_retransmitted = false}, + #diameter_packet{header = fold_record(Hdr0, Hdr), + msg = Msg, + transport_data = TD}; + %% Binaries and header/avp lists are sent as-is. -make_answer_packet(Bin, _) +make_answer_packet(Bin, #diameter_packet{transport_data = TD}) when is_binary(Bin) -> - #diameter_packet{bin = Bin}; -make_answer_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. 6.2 of 3588 requires the -%% same P flag on an answer as on the request. -make_answer_packet(Msg, #diameter_packet{header = ReqHdr}) -> - Hdr = ReqHdr#diameter_header{version = ?DIAMETER_VERSION, - is_request = false, - is_error = undefined, - is_retransmitted = false}, - #diameter_packet{header = Hdr, - msg = Msg}. + #diameter_packet{bin = Bin, + transport_data = TD}; +make_answer_packet([#diameter_header{} | _] = Msg, + #diameter_packet{transport_data = TD}) -> + #diameter_packet{msg = Msg, + transport_data = TD}; + +%% Otherwise, preserve transport_data. +make_answer_packet(Msg, #diameter_packet{transport_data = TD} = Pkt) -> + make_answer_packet(#diameter_packet{msg = Msg, transport_data = TD}, Pkt). %% rc/1 -- cgit v1.2.3