diameter_app(3erl) Erlang Module Definition diameter_app(3erl)
NAME
diameter_app - Callback module of a Diameter application.
DESCRIPTION
A diameter service as started by diameter:start_service/2 configures
one of more Diameter applications, each of whose configuration speci-
fies a callback that handles messages specific to the application. The
messages and AVPs of the application are defined in a dictionary file
whose format is documented in diameter_dict(5) while the callback mod-
ule is documented here. The callback module implements the Diameter ap-
plication-specific functionality of a service.
A callback module must export all of the functions documented below.
The functions themselves are of three distinct flavours:
* peer_up/3 and peer_down/3 signal the attainment or loss of connec-
tivity with a Diameter peer.
* pick_peer/4, prepare_request/3, prepare_retransmit/3, handle_an-
swer/4 and handle_error/4 are (or may be) called as a consequence
of a call to diameter:call/4 to send an outgoing Diameter request
message.
* handle_request/3 is called in response to an incoming Diameter re-
quest message.
The arities for the the callback functions here assume no extra argu-
ments. All functions will also be passed any extra arguments configured
with the callback module itself when calling diameter:start_service/2
and, for the call-specific callbacks, any extra arguments passed to di-
ameter:call/4.
DATA TYPES
capabilities() = #diameter_caps{}:
A record containing the identities of the local Diameter node and
the remote Diameter peer having an established transport connec-
tion, as well as the capabilities as determined by capabilities ex-
change. Each field of the record is a 2-tuple consisting of values
for the (local) host and (remote) peer. Optional or possibly multi-
ple values are encoded as lists of values, mandatory values as the
bare value.
message() = diameter_codec:message():
The representation of a Diameter message as passed to diame-
ter:call/4 or returned from a handle_request/3 callback.
packet() = diameter_codec:packet():
A container for incoming and outgoing Diameter messages that's
passed through encode/decode and transport. Fields should not be
set in return values except as documented.
peer_ref() = term():
A term identifying a transport connection with a Diameter peer.
peer() = {peer_ref(), capabilities()}:
A tuple representing a Diameter peer connection.
state() = term():
The state maintained by the application callback functions
peer_up/3, peer_down/3 and (optionally) pick_peer/4. The initial
state is configured in the call to diameter:start_service/2 that
configures the application on a service. Callback functions return-
ing a state are evaluated in a common service-specific process
while those not returning state are evaluated in a request-specific
process.
EXPORTS
Mod:peer_up(SvcName, Peer, State) -> NewState
Types:
SvcName = diameter:service_name()
Peer = peer()
State = NewState = state()
Invoked to signal the availability of a peer connection on the
local Erlang node. In particular, capabilities exchange with the
peer has indicated support for the application in question, the
RFC 3539 watchdog state machine for the connection has reached
state OKAY and Diameter messages can be both sent and received.
Note:
A watchdog state machine can reach state OKAY from state SUSPECT
without a new capabilities exchange taking place. A new trans-
port connection (and capabilities exchange) results in a new
peer_ref().
Note:
There is no requirement that a callback return before incoming
requests are received: handle_request/3 callbacks must be han-
dled independently of peer_up/3 and peer_down/3.
Mod:peer_down(SvcName, Peer, State) -> NewState
Types:
SvcName = diameter:service_name()
Peer = peer()
State = NewState = state()
Invoked to signal that a peer connection on the local Erlang
node is no longer available following a previous call to
peer_up/3. In particular, that the RFC 3539 watchdog state ma-
chine for the connection has left state OKAY and the peer will
no longer be a candidate in pick_peer/4 callbacks.
Mod:pick_peer(LocalCandidates, RemoteCandidates, SvcName, State) -> Se-
lection | false
Types:
LocalCandidates = RemoteCandidates = [peer()]
SvcName = diameter:service_name()
State = NewState = state()
Selection = {ok, Peer} | {Peer, NewState}
Peer = peer() | false
Invoked as a consequence of a call to diameter:call/4 to select
a destination peer for an outgoing request. The return value in-
dicates the selected peer.
The candidate lists contain only those peers that have adver-
tised support for the Diameter application in question during
capabilities exchange, that have not be excluded by a filter op-
tion in the call to diameter:call/4 and whose watchdog state ma-
chine is in the OKAY state. The order of the elements is unspec-
ified except that any peers whose Origin-Host and Origin-Realm
matches that of the outgoing request (in the sense of a {filter,
{all, [host, realm]}} option to diameter:call/4) will be placed
at the head of the list. LocalCandidates contains peers whose
transport process resides on the local Erlang node while Remote-
Candidates contains peers that have been communicated from other
nodes by services of the same name.
A callback that returns a peer() will be followed by a pre-
pare_request/3 callback and, if the latter indicates that the
request should be sent, by either handle_answer/4 or handle_er-
ror/4 depending on whether or not an answer message is received
from the peer. If the transport becomes unavailable after pre-
pare_request/3 then a new pick_peer/4 callback may take place to
failover to an alternate peer, after which prepare_retransmit/3
takes the place of prepare_request/3 in resending the request.
There is no guarantee that a pick_peer/4 callback to select an
alternate peer will be followed by any additional callbacks
since a retransmission to an alternate peer is abandoned if an
answer is received from a previously selected peer.
The return values false and {false, State} (that is, NewState =
State) are equivalent, as are {ok, Peer} and {Peer, State}.
Note:
The diameter:service_opt() use_shared_peers determines whether
or not a service uses peers shared from other nodes. If not then
RemoteCandidates is the empty list.
Warning:
The return value {Peer, NewState} is only allowed if the Diame-
ter application in question was configured with the diameter:ap-
plication_opt() {call_mutates_state, true}. Otherwise, the State
argument is always the initial value as configured on the appli-
cation, not any subsequent value returned by a peer_up/3 or
peer_down/3 callback.
Mod:prepare_request(Packet, SvcName, Peer) -> Action
Types:
Packet = packet()
SvcName = diameter:service_name()
Peer = peer()
Action = Send | Discard | {eval_packet, Action, PostF}
Send = {send, packet() | message()}
Discard = {discard, Reason} | discard
PostF = diameter:eval()}
Invoked to return a request for encoding and transport. Allows
the sender to use the selected peer's capabilities to modify the
outgoing request. Many implementations may simply want to return
{send, Packet}
A returned packet() should set the request to be encoded in its
msg field and can set the transport_data field in order to pass
information to the transport process. Extra arguments passed to
diameter:call/4 can be used to communicate transport (or any
other) data to the callback.
A returned packet() can set the header field to a #diame-
ter_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 ap-
plication_id is ignored.
A returned PostF will be evaluated on any encoded #diame-
ter_packet{} prior to transmission, the bin field containing the
encoded binary. The return value is ignored.
Returning {discard, Reason} causes the request to be aborted and
the diameter:call/4 for which the callback has taken place to
return {error, Reason}. Returning discard is equivalent to re-
turning {discard, discarded}.
Mod:prepare_retransmit(Packet, SvcName, Peer) -> Action
Types:
Packet = packet()
SvcName = diameter:service_name()
Peer = peer()
Action = Send | Discard | {eval_packet, Action, PostF}
Send = {send, packet() | message()}
Discard = {discard, Reason} | discard
PostF = diameter:eval()}
Invoked to return a request for encoding and retransmission. Has
the same role as prepare_request/3 in the case that a peer con-
nection is lost an an alternate peer selected but the argument
packet() is as returned by the initial prepare_request/3.
Returning {discard, Reason} causes the request to be aborted and
a handle_error/4 callback to take place with Reason as initial
argument. Returning discard is equivalent to returning {discard,
discarded}.
Mod:handle_answer(Packet, Request, SvcName, Peer) -> Result
Types:
Packet = packet()
Request = message()
SvcName = diameter:service_name()
Peer = peer()
Result = term()
Invoked when an answer message is received from a peer. The re-
turn value is returned from diameter:call/4 unless the detach
option was specified.
The decoded answer record and undecoded binary are in the msg
and bin fields of the argument packet() respectively. Request is
the outgoing request message as was returned from prepare_re-
quest/3 or prepare_retransmit/3.
For any given call to diameter:call/4 there is at most one han-
dle_answer/4 callback: any duplicate answer (due to retransmis-
sion or otherwise) is discarded. Similarly, only one of han-
dle_answer/4 or handle_error/4 is called.
By default, an incoming answer message that cannot be success-
fully decoded causes the request process to fail, causing diame-
ter:call/4 to return {error, failure} unless the detach option
was specified. In particular, there is no handle_error/4 call-
back in this case. The diameter:application_opt() answer_errors
can be set to change this behaviour.
Mod:handle_error(Reason, Request, SvcName, Peer) -> Result
Types:
Reason = timeout | failover | term()
Request = message()
SvcName = diameter:service_name()
Peer = peer()
Result = term()
Invoked when an error occurs before an answer message is re-
ceived in response to an outgoing request. The return value is
returned from diameter:call/4 unless the detach option was spec-
ified.
Reason timeout indicates that an answer message has not been re-
ceived within the time specified with the corresponding diame-
ter:call_opt(). Reason failover indicates that the transport
connection to the peer to which the request has been sent has
become unavailable and that not alternate peer was not selected.
Mod:handle_request(Packet, SvcName, Peer) -> Action
Types:
Packet = packet()
SvcName = term()
Peer = peer()
Action = Reply | {relay, [Opt]} | discard |
{eval|eval_packet, Action, PostF}
Reply = {reply, packet() | message()} | {answer_message,
3000..3999|5000..5999} | {protocol_error, 3000..3999}
Opt = diameter:call_opt()
PostF = diameter:eval()
Invoked when a request message is received from a peer. The ap-
plication in which the callback takes place (that is, the call-
back module as configured with diameter:start_service/2) is de-
termined by the Application Identifier in the header of the in-
coming request message, the selected module being the one whose
corresponding dictionary declares itself as defining either the
application in question or the Relay application.
The argument packet() has the following signature.
#diameter_packet{header = #diameter_header{},
avps = [#diameter_avp{}],
msg = record() | undefined,
errors = [Unsigned32() | {Unsigned32(), #diameter_avp{}}],
bin = binary(),
transport_data = term()}
The msg field will be undefined in case the request has been re-
ceived in the relay application. Otherwise it contains the
record representing the request as outlined in diameter_dict(5).
The errors field specifies any results codes identifying errors
found while decoding the request. This is used to set Result-
Code and/or Failed-AVP in a returned answer unless the callback
returns a #diameter_packet{} whose errors field is set to either
a non-empty list of its own, in which case this list is used in-
stead, or the atom false to disable any setting of Result-Code
and Failed-AVP. Note that the errors detected by diameter are of
the 3xxx and 5xxx series, Protocol Errors and Permanent Failures
respectively. The errors list is empty if the request has been
received in the relay application.
The transport_data field contains an arbitrary term passed into
diameter from the transport module in question, or the atom un-
defined if the transport specified no data. The term is pre-
served 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 fol-
lows.
{reply, packet() | message()}:
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 #diame-
ter_header{} to specify values that should be preserved in
the outgoing answer, appropriate values otherwise being set
by diameter.
{answer_message, 3000..3999|5000..5999}:
Send an answer message to the peer containing the specified
Result-Code. Equivalent to
{reply, ['answer-message' | Avps]
where Avps sets the Origin-Host, Origin-Realm, the specified
Result-Code and (if the request contained one) Session-Id
AVPs, and possibly Failed-AVP as described below.
Returning a value other than 3xxx or 5xxx will cause the re-
quest process in question to fail, as will returning a 5xxx
value if the peer connection in question has been configured
with the RFC 3588 common dictionary diame-
ter_gen_base_rfc3588. (Since RFC 3588 only allows 3xxx val-
ues in an answer-message.)
When returning 5xxx, Failed-AVP will be populated with the
AVP of the first matching Result-Code/AVP pair in the errors
field of the argument packet(), if found. If this is not ap-
propriate then an answer-message should be constructed ex-
plicitly and returned in a reply tuple instead.
{relay, Opts}:
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 pick_peer/4 and subsequent call-
backs take place just as if diameter:call/4 had been called
explicitly. The End-to-End Identifier of the incoming re-
quest is preserved in the header of the relayed request.
The returned Opts should not specify detach. A subsequent
handle_answer/4 callback for the relayed request must return
its first argument, the packet() containing the answer mes-
sage. Note that the extra option can be specified to supply
arguments that can distinguish the relay case from others if
so desired. Any other return value (for example, from a han-
dle_error/4 callback) causes the request to be answered with
3002 (DIAMETER_UNABLE_TO_DELIVER).
discard:
Discard the request. No answer message is sent to the peer.
{eval, Action, PostF}:
Handle the request as if Action has been returned and then
evaluate PostF in the request process. The return value is
ignored.
{eval_packet, Action, PostF}:
Like eval but evaluate PostF on any encoded #diame-
ter_packet{} prior to transmission, the bin field containing
the encoded binary. The return value is ignored.
{protocol_error, 3000..3999}:
Equivalent to {answer_message, 3000..3999}.
Note:
Requests containing errors may be answered by diameter, without
a callback taking place, depending on the value of the diame-
ter:application_opt() request_errors.
Ericsson AB diameter 2.2.3 diameter_app(3erl)