diameter(3erl) Erlang Module Definition diameter(3erl)
NAME
diameter - Main API of the diameter application.
DESCRIPTION
This module provides the interface with which a user can implement a
Diameter node that sends and receives messages using the Diameter pro-
tocol as defined in RFC 6733.
Basic usage consists of creating a representation of a locally imple-
mented Diameter node and its capabilities with start_service/2, adding
transport capability using add_transport/2 and sending Diameter re-
quests and receiving Diameter answers with call/4. Incoming Diameter
requests are communicated as callbacks to a diameter_app(3erl) callback
modules as specified in the service configuration.
Beware the difference between diameter (not capitalized) and Diameter
(capitalized). The former refers to the Erlang application named diame-
ter whose main api is defined here, the latter to Diameter protocol in
the sense of RFC 6733.
The diameter application must be started before calling most functions
in this module.
DATA TYPES
Address():
DiameterIdentity():
Grouped():
OctetString():
Time():
Unsigned32():
UTF8String():
Types corresponding to RFC 6733 AVP Data Formats. Defined in diame-
ter_dict(5).
application_alias() = term():
Name identifying a Diameter application in service configuration.
Passed to call/4 when sending requests defined by the application.
application_module() = Mod | [Mod | ExtraArgs] | #diameter_call-
back{}:
Mod = atom()
ExtraArgs = list()
Module implementing the callback interface defined in diame-
ter_app(3erl), along with any extra arguments to be appended to
those documented. Note that extra arguments specific to an outgoing
request can be specified to call/4, in which case those are ap-
pended to any module-specific extra arguments.
Specifying a #diameter_callback{} record allows individual func-
tions to be configured in place of the usual diameter_app(3erl)
callbacks. See diameter_callback.erl for details.
application_opt():
Options defining a Diameter application. Has one of the following
types.
{alias, application_alias()}:
Unique identifier for the application in the scope of the ser-
vice. Defaults to the value of the dictionary option.
{dictionary, atom()}:
Name of an encode/decode module for the Diameter messages defined
by the application. These modules are generated from files whose
format is documented in diameter_dict(5).
{module, application_module()}:
Callback module in which messages of the Diameter application are
handled. See diameter_app(3erl) for the required interface and
semantics.
{state, term()}:
Initial callback state. The prevailing state is passed to some
diameter_app(3erl) callbacks, which can then return a new state.
Defaults to the value of the alias option.
{call_mutates_state, true|false}:
Whether or not the pick_peer/4 application callback can modify
the application state. Defaults to false.
Warning:
pick_peer/4 callbacks are serialized when this option is true,
which is a potential performance bottleneck. A simple Diameter
client may suffer no ill effects from using mutable state but a
server or agent that responds to incoming request should probably
avoid it.
{answer_errors, callback|report|discard}:
Manner in which incoming answer messages containing decode errors
are handled.
If callback then errors result in a handle_answer/4 callback in
the same fashion as for handle_request/3, with errors communi-
cated in the errors field of the #diameter_packet{} passed to the
callback. If report then an answer containing errors is discarded
without a callback and a warning report is written to the log. If
discard then an answer containing errors is silently discarded
without a callback. In both the report and discard cases the re-
turn value for the call/4 invocation in question is as if a call-
back had taken place and returned {error, failure}.
Defaults to discard.
{request_errors, answer_3xxx|answer|callback}:
Manner in which incoming requests are handled when an error other
than 3007 (DIAMETER_APPLICATION_UNSUPPORTED, which cannot be as-
sociated with an application callback module), is detected.
If answer_3xxx then requests are answered without a handle_re-
quest/3 callback taking place. If answer then even 5xxx errors
are answered without a callback unless the connection in question
has configured the RFC 3588 common dictionary as noted below. If
callback then a handle_request/3 callback always takes place and
its return value determines the answer sent to the peer, if any.
Defaults to answer_3xxx.
Note:
Answers sent by diameter set the E-bit in the Diameter Header.
Since RFC 3588 allows only 3xxx result codes in an answer-message,
answer has the same semantics as answer_3xxx when the transport in
question has been configured with diameter_gen_base_rfc3588 as its
common dictionary. Since RFC 6733 allows both 3xxx and 5xxx result
codes in an answer-message, a transport with diame-
ter_gen_base_rfc6733 as its common dictionary does distinguish be-
tween answer_3xxx and answer.
call_opt():
Options available to call/4 when sending an outgoing Diameter re-
quest. Has one of the following types.
{extra, list()}:
Extra arguments to append to callbacks to the callback module in
question. These are appended to any extra arguments configured on
the callback itself. Multiple options append to the argument
list.
{filter, peer_filter()}:
Filter to apply to the list of available peers before passing it
to the pick_peer/4 callback for the application in question. Mul-
tiple options are equivalent a single all filter on the corre-
sponding list of filters. Defaults to none.
{peer, diameter_app:peer_ref()}:
Peer to which the request in question can be sent, preempting the
selection of peers having advertised support for the Diameter ap-
plication in question. Multiple options can be specified, and
their order is respected in the candidate lists passed to a sub-
sequent pick_peer/4 callback.
{timeout, Unsigned32()}:
Number of milliseconds after which the request should timeout.
Defaults to 5000.
detach:
Cause call/4 to return ok as soon as the request in question has
been encoded, instead of waiting for and returning the result
from a subsequent handle_answer/4 or handle_error/4 callback.
An invalid option will cause call/4 to fail.
capability():
AVP values sent in outgoing CER or CEA messages during capabilities
exchange. Can be configured both on a service and a transport, val-
ues on the latter taking precedence. Has one of the following
types.
{'Origin-Host', DiameterIdentity()}:
{'Origin-Realm', DiameterIdentity()}:
{'Host-IP-Address', [Address()]}:
An address list is available to the start function of a transport
module, which can return a new list for use in the subsequent CER
or CEA. Host-IP-Address need not be specified if the transport
module in question communicates an address list as described in
diameter_transport(3erl)
{'Vendor-Id', Unsigned32()}:
{'Product-Name', UTF8String()}:
{'Origin-State-Id', Unsigned32()}:
Origin-State-Id is optional but, if configured, will be included
in outgoing CER/CEA and DWR/DWA messages. Setting a value of 0
(zero) is equivalent to not setting a value, as documented in RFC
6733. The function origin_state_id/0 can be used as to retrieve a
value that is computed when the diameter application is started.
{'Supported-Vendor-Id', [Unsigned32()]}:
{'Auth-Application-Id', [Unsigned32()]}:
{'Inband-Security-Id', [Unsigned32()]}:
Inband-Security-Id defaults to the empty list, which is equiva-
lent to a list containing only 0 (NO_INBAND_SECURITY). If 1 (TLS)
is specified then TLS is selected if the CER/CEA received from
the peer offers it.
{'Acct-Application-Id', [Unsigned32()]}:
{'Vendor-Specific-Application-Id', [Grouped()]}:
{'Firmware-Revision', Unsigned32()}:
Note that each tuple communicates one or more AVP values. It is an
error to specify duplicate tuples.
eval() = {M,F,A} | fun() | [eval() | A]:
An expression that can be evaluated as a function in the following
sense.
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) ->
eval([F]).
Applying an eval() E to an argument list A is meant in the sense of
eval([E|A]).
Warning:
Beware of using fun expressions of the form fun Name/Arity in situa-
tions in which the fun is not short-lived and code is to be upgraded
at runtime since any processes retaining such a fun will have a ref-
erence to old code. In particular, such a value is typically inappro-
priate in configuration passed to start_service/2 or add_transport/2.
peer_filter() = term():
Filter passed to call/4 in order to select candidate peers for a
pick_peer/4 callback. Has one of the following types.
none:
Matches any peer. This is a convenience that provides a filter
equivalent to no filter.
host:
Matches only those peers whose Origin-Host has the same value as
Destination-Host in the outgoing request in question, or any peer
if the request does not contain a Destination-Host AVP.
realm:
Matches only those peers whose Origin-Realm has the same value as
Destination-Realm in the outgoing request in question, or any
peer if the request does not contain a Destination-Realm AVP.
{host, any|DiameterIdentity()}:
Matches only those peers whose Origin-Host has the specified
value, or all peers if the atom any.
{realm, any|DiameterIdentity()}:
Matches only those peers whose Origin-Realm has the specified
value, or all peers if the atom any.
{eval, eval()}:
Matches only those peers for which the specified eval() returns
true when applied to the connection's diameter_caps record. Any
other return value or exception is equivalent to false.
{neg, peer_filter()}:
Matches only those peers not matched by the specified filter.
{all, [peer_filter()]}:
Matches only those peers matched by each filter in the specified
list.
{any, [peer_filter()]}:
Matches only those peers matched by at least one filter in the
specified list. The resulting list will be in match order, peers
matching the first filter of the list sorting before those
matched by the second, and so on.
{first, [peer_filter()]}:
Like any, but stops at the first filter for which there are
matches, which can be much more efficient when there are many
peers. For example, the following filter causes only peers best
matching both the host and realm filters to be presented.
{first, [{all, [host, realm]}, realm]}
An invalid filter is equivalent to {any,[]}, a filter that matches
no peer.
Note:
The host and realm filters cause the Destination-Host and Destina-
tion-Realm AVPs to be extracted from the outgoing request, assuming
it to be a record- or list-valued diameter_codec:message(), and as-
suming at most one of each AVP. If this is not the case then the
{host|realm, DiameterIdentity()} filters must be used to achieve the
desired result. An empty DiameterIdentity() (which should not be typ-
ical) matches all hosts/realms for the purposes of filtering.
Warning:
A host filter is not typically desirable when setting Destination-
Host since it will remove peer agents from the candidates list.
service_event() = #diameter_event{service = service_name(), info =
service_event_info()}:
An event message sent to processes that have subscribed to these
using subscribe/1.
service_event_info() = term():
The info field of a service_event() record. Can have one of the
following types.
start:
stop:
The service is being started or stopped. No event precedes a
start event. No event follows a stop event, and this event im-
plies the termination of all transport processes.
{up, Ref, Peer, Config, Pkt}:
{up, Ref, Peer, Config}:
{down, Ref, Peer, Config}:
Ref = transport_ref()
Peer = diameter_app:peer()
Config = {connect|listen, [transport_opt()]}
Pkt = #diameter_packet{}
The RFC 3539 watchdog state machine has transitioned into (up) or
out of (down) the OKAY state. If a #diameter_packet{} is present
in an up event then there has been a capabilities exchange on a
newly established transport connection and the record contains
the received CER or CEA.
Note that a single up or down event for a given peer corresponds
to multiple peer_up/3 or peer_down/3 callbacks, one for each of
the Diameter applications negotiated during capabilities ex-
change. That is, the event communicates connectivity with the
peer as a whole while the callbacks communicate connectivity with
respect to individual Diameter applications.
{reconnect, Ref, Opts}:
Ref = transport_ref()
Opts = [transport_opt()]
A connecting transport is attempting to establish/reestablish a
transport connection with a peer following connect_timer or
watchdog_timer expiry.
{closed, Ref, Reason, Config}:
Ref = transport_ref()
Config = {connect|listen, [transport_opt()]}
Capabilities exchange has failed. Reason can have one of the fol-
lowing types.
{'CER', Result, Caps, Pkt}:
Result = ResultCode | {capabilities_cb, CB, ResultCode|discard}
Caps = #diameter_caps{}
Pkt = #diameter_packet{}
ResultCode = integer()
CB = eval()
An incoming CER has been answered with the indicated result
code, or discarded. Caps contains pairs of values, for the lo-
cal node and remote peer respectively. Pkt contains the CER in
question. In the case of rejection by a capabilities callback,
the tuple contains the rejecting callback.
{'CER', Caps, {ResultCode, Pkt}}:
ResultCode = integer()
Caps = #diameter_caps{}
Pkt = #diameter_packet{}
An incoming CER contained errors and has been answered with the
indicated result code. Caps contains values for the local node
only. Pkt contains the CER in question.
{'CER', timeout}:
An expected CER was not received within capx_timeout of connec-
tion establishment.
{'CEA', Result, Caps, Pkt}:
Result = ResultCode | atom() | {capabilities_cb, CB, ResultCode|discard}
Caps = #diameter_caps{}
Pkt = #diameter_packet{}
ResultCode = integer()
An incoming CEA has been rejected for the indicated reason. An
integer-valued Result indicates the result code sent by the
peer. Caps contains pairs of values for the local node and re-
mote peer. Pkt contains the CEA in question. In the case of re-
jection by a capabilities callback, the tuple contains the re-
jecting callback.
{'CEA', Caps, Pkt}:
Caps = #diameter_caps{}
Pkt = #diameter_packet{}
An incoming CEA contained errors and has been rejected. Caps
contains only values for the local node. Pkt contains the CEA
in question.
{'CEA', timeout}:
An expected CEA was not received within capx_timeout of connec-
tion establishment.
{watchdog, Ref, PeerRef, {From, To}, Config}:
Ref = transport_ref()
PeerRef = diameter_app:peer_ref()
From, To = initial | okay | suspect | down | reopen
Config = {connect|listen, [transport_opt()]}
An RFC 3539 watchdog state machine has changed state.
any():
For forward compatibility, a subscriber should be prepared to re-
ceive info fields of forms other than the above.
service_name() = term():
Name of a service as passed to start_service/2 and with which the
service is identified. There can be at most one service with a
given name on a given node. Note that erlang:make_ref/0 can be used
to generate a service name that is somewhat unique.
service_opt():
Option passed to start_service/2. Can be any capability() as well
as the following.
{application, [application_opt()]}:
A Diameter application supported by the service.
A service must configure one tuple for each Diameter application
it intends to support. For an outgoing request, the relevant ap-
plication_alias() is passed to call/4, while for an incoming re-
quest the application identifier in the message header determines
the application, the identifier being specified in the applica-
tion's dictionary file.
Warning:
The capabilities advertised by a node must match its configured ap-
plications. In particular, application configuration must be
matched by corresponding capability() configuration, of *-Applica-
tion-Id AVPs in particular.
{decode_format, record | list | map | none}:
The format of decoded messages and grouped AVPs in the msg field
of diameter_packet records and value field of diameter_avp
records respectively. If record then a record whose definition is
generated from the dictionary file in question. If list or map
then a [Name | Avps] pair where Avps is a list of AVP name/values
pairs or a map keyed on AVP names respectively. If none then the
atom-value message name, or undefined for a Grouped AVP. See also
diameter_codec:message().
Defaults to record.
Note:
AVPs are decoded into a list of diameter_avp records in avps field
of diameter_packet records independently of decode_format.
{restrict_connections, false | node | nodes | [node()] | eval()}:
The degree to which the service allows multiple transport connec-
tions to the same peer, as identified by its Origin-Host at capa-
bilities exchange.
If [node()] then a connection is rejected if another already ex-
ists on any of the specified nodes. Types false, node, nodes and
eval() are equivalent to [], [node()], [node()|nodes()] and the
evaluated value respectively, evaluation of each expression tak-
ing place whenever a new connection is to be established. Note
that false allows an unlimited number of connections to be estab-
lished with the same peer.
Multiple connections are independent and governed by their own
peer and watchdog state machines.
Defaults to nodes.
{sequence, {H,N} | eval()}:
A constant value H for the topmost 32-N bits of of 32-bit End-to-
End and Hop-by-Hop Identifiers generated by the service, either
explicitly or as a return value of a function to be evaluated at
start_service/2. In particular, an identifier Id is mapped to a
new identifier as follows.
(H bsl N) bor (Id band ((1 bsl N) - 1))
Note that RFC 6733 requires that End-to-End Identifiers remain
unique for a period of at least 4 minutes and that this and the
call rate places a lower bound on appropriate values of N: at a
rate of R requests per second, an N-bit counter traverses all of
its values in (1 bsl N) div (R*60) minutes, so the bound is
4*R*60 =< 1 bsl N.
N must lie in the range 0..32 and H must be a non-negative inte-
ger less than 1 bsl (32-N).
Defaults to {0,32}.
Warning:
Multiple Erlang nodes implementing the same Diameter node should be
configured with different sequence masks to ensure that each node
uses a unique range of End-to-End and Hop-by-Hop Identifiers for
outgoing requests.
{share_peers, boolean() | [node()] | eval()}:
Nodes to which peer connections established on the local Erlang
node are communicated. Shared peers become available in the re-
mote candidates list passed to pick_peer/4 callbacks on remote
nodes whose services are configured to use them: see
use_shared_peers below.
If false then peers are not shared. If [node()] then peers are
shared with the specified list of nodes. If eval() then peers are
shared with the nodes returned by the specified function, evalu-
ated whenever a peer connection becomes available or a remote
service requests information about local connections. The value
true is equivalent to fun erlang:nodes/0. The value node() in a
list is ignored, so a collection of services can all be config-
ured to share with the same list of nodes.
Defaults to false.
Note:
Peers are only shared with services of the same name for the pur-
pose of sending outgoing requests. Since the value of the applica-
tion_opt() alias, passed to call/4, is the handle for identifying a
peer as a suitable candidate, services that share peers must use
the same aliases to identify their supported applications. They
should typically also configure identical capabilities(), since by
sharing peer connections they are distributing the implementation
of a single Diameter node across multiple Erlang nodes.
{strict_arities, boolean() | encode | decode}:
Whether or not to require that the number of AVPs in a message or
grouped AVP agree with those specified in the dictionary in ques-
tion when passing messages to diameter_app(3erl) callbacks. If
true then mismatches in an outgoing messages cause message encod-
ing to fail, while mismatches in an incoming message are reported
as 5005/5009 errors in the errors field of the diameter_packet
record passed to handle_request/3 or handle_answer/4 callbacks.
If false then neither error is enforced/detected. If encode or
decode then errors are only enforced/detected on outgoing or in-
coming messages respectively.
Defaults to true.
Note:
Disabling arity checks affects the form of messages at encode/de-
code. In particular, decoded AVPs are represented as lists of val-
ues, regardless of the AVP's arity (ie. expected number in the mes-
sage/AVP grammar in question), and values are expected to be sup-
plied as lists at encode. This differs from the historic decode be-
haviour of representing AVPs of arity 1 as bare values, not wrapped
in a list.
{string_decode, boolean()}:
Whether or not to decode AVPs of type OctetString() and its de-
rived types DiameterIdentity(), DiameterURI(), IPFilterRule(),
QoSFilterRule(), and UTF8String(). If true then AVPs of these
types are decoded to string(). If false then values are retained
as binary().
Defaults to true.
Warning:
This option should be set to false since a sufficiently malicious
peer can otherwise cause large amounts of memory to be consumed
when decoded Diameter messages are passed between processes. The
default value is for backwards compatibility.
{traffic_counters, boolean()}:
Whether or not to count application-specific messages; those for
which diameter_app(3erl) callbacks take place. If false then only
messages handled by diameter itself are counted: CER/CEA,
DWR/DWA, DPR/DPA.
Defaults to true.
Note:
Disabling counters is a performance improvement, but means that the
omitted counters are not returned by service_info/2.
{use_shared_peers, boolean() | [node()] | eval()}:
Nodes from which communicated peers are made available in the re-
mote candidates list of pick_peer/4 callbacks.
If false then remote peers are not used. If [node()] then only
peers from the specified list of nodes are used. If eval() then
only peers returned by the specified function are used, evaluated
whenever a remote service communicates information about an
available peer connection. The value true is equivalent to fun
erlang:nodes/0. The value node() in a list is ignored.
Defaults to false.
Note:
A service that does not use shared peers will always pass the empty
list as the second argument of pick_peer/4 callbacks.
Warning:
Sending a request over a peer connection on a remote node is less
efficient than sending it over a local connection. It may be
preferable to make use of the service_opt() restrict_connections
and maintain a dedicated connection on each node from which re-
quests are sent.
transport_opt():
Any transport option except applications, capabilities, trans-
port_config, and transport_module. Used as defaults for transport
configuration, values passed to add_transport/2 overriding values
configured on the service.
transport_opt():
Option passed to add_transport/2. Has one of the following types.
{applications, [application_alias()]}:
Diameter applications to which the transport should be re-
stricted. Defaults to all applications configured on the service
in question. Applications not configured on the service in ques-
tion are ignored.
Warning:
The capabilities advertised by a node must match its configured ap-
plications. In particular, setting applications on a transport typ-
ically implies having to set matching *-Application-Id AVPs in a
capabilities() tuple.
{avp_dictionaries, [module()]}:
A list of alternate dictionary modules with which to encode/de-
code AVPs that are not defined by the dictionary of the applica-
tion in question. At decode, such AVPs are represented as diame-
ter_avp records in the 'AVP' field of a decoded message or
Grouped AVP, the first alternate that succeeds in decoding the
AVP setting the record's value field. At encode, values in an
'AVP' list can be passed as AVP name/value 2-tuples, and it is an
encode error for no alternate to define the AVP of such a tuple.
Defaults to the empty list.
Note:
The motivation for alternate dictionaries is RFC 7683, Diameter
Overload Indication Conveyance (DOIC), which defines AVPs to be
piggybacked onto existing application messages rather than defining
an application of its own. The DOIC dictionary is provided by the
diameter application, as module diameter_gen_doic_rfc7683, but al-
ternate dictionaries can be used to encode/decode any set of AVPs
not known to an application dictionary.
{capabilities, [capability()]}:
AVPs used to construct outgoing CER/CEA messages. Values take
precedence over any specified on the service in question.
Specifying a capability as a transport option may be particularly
appropriate for Inband-Security-Id, in case TLS is desired over
TCP as implemented by diameter_tcp(3erl).
{capabilities_cb, eval()}:
Callback invoked upon reception of CER/CEA during capabilities
exchange in order to ask whether or not the connection should be
accepted. Applied to the transport_ref() and #diameter_caps{}
record of the connection.
The return value can have one of the following types.
ok:
Accept the connection.
integer():
Causes an incoming CER to be answered with the specified Re-
sult-Code.
discard:
Causes an incoming CER to be discarded without CEA being sent.
unknown:
Equivalent to returning 3010, DIAMETER_UNKNOWN_PEER.
Returning anything but ok or a 2xxx series result code causes the
transport connection to be broken. Multiple capabilities_cb op-
tions can be specified, in which case the corresponding callbacks
are applied until either all return ok or one does not.
{capx_timeout, Unsigned32()}:
Number of milliseconds after which a transport process having an
established transport connection will be terminated if the ex-
pected capabilities exchange message (CER or CEA) is not received
from the peer. For a connecting transport, the timing of connec-
tion attempts is governed by connect_timer or watchdog_timer ex-
piry. For a listening transport, the peer determines the timing.
Defaults to 10000.
{connect_timer, Tc}:
Tc = Unsigned32()
For a connecting transport, the RFC 6733 Tc timer, in millisec-
onds. This timer determines the frequency with which a transport
attempts to establish an initial connection with its peer follow-
ing transport configuration. Once an initial connection has been
established, watchdog_timer determines the frequency of reconnec-
tion attempts, as required by RFC 3539.
For a listening transport, the timer specifies the time after
which a previously connected peer will be forgotten: a connection
after this time is regarded as an initial connection rather than
reestablishment, causing the RFC 3539 state machine to pass to
state OKAY rather than REOPEN. Note that these semantics are not
governed by the RFC and that a listening transport's con-
nect_timer should be greater than its peer's Tw plus jitter.
Defaults to 30000 for a connecting transport and 60000 for a lis-
tening transport.
{disconnect_cb, eval()}:
Callback invoked prior to terminating the transport process of a
transport connection having watchdog state OKAY. Applied to ap-
plication|service|transport and the transport_ref() and diame-
ter_app:peer() in question: application indicates that the diame-
ter application is being stopped, service that the service in
question is being stopped by stop_service/1, and transport that
the transport in question is being removed by remove_transport/2.
The return value can have one of the following types.
{dpr, [option()]}:
Send Disconnect-Peer-Request to the peer, the transport process
being terminated following reception of Disconnect-Peer-Answer
or timeout. An option() can be one of the following.
{cause, 0|rebooting|1|busy|2|goaway}:
Disconnect-Cause to send, REBOOTING, BUSY and
DO_NOT_WANT_TO_TALK_TO_YOU respectively. Defaults to reboot-
ing for Reason=service|application and goaway for Rea-
son=transport.
{timeout, Unsigned32()}:
Number of milliseconds after which the transport process is
terminated if DPA has not been received. Defaults to the
value of dpa_timeout.
dpr:
Equivalent to {dpr, []}.
close:
Terminate the transport process without Disconnect-Peer-Request
being sent to the peer.
ignore:
Equivalent to not having configured the callback.
Multiple disconnect_cb options can be specified, in which case
the corresponding callbacks are applied until one of them returns
a value other than ignore. All callbacks returning ignore is
equivalent to not having configured them.
Defaults to a single callback returning dpr.
{dpa_timeout, Unsigned32()}:
Number of milliseconds after which a transport connection is ter-
minated following an outgoing DPR if DPA is not received.
Defaults to 1000.
{dpr_timeout, Unsigned32()}:
Number of milliseconds after which a transport connection is ter-
minated following an incoming DPR if the peer does not close the
connection.
Defaults to 5000.
{incoming_maxlen, 0..16777215}:
Bound on the expected size of incoming Diameter messages. Mes-
sages larger than the specified number of bytes are discarded.
Defaults to 16777215, the maximum value of the 24-bit Message
Length field in a Diameter Header.
{length_errors, exit|handle|discard}:
How to deal with errors in the Message Length field of the Diame-
ter Header in an incoming message. An error in this context is
that the length is not at least 20 bytes (the length of a
Header), is not a multiple of 4 (a valid length) or is not the
length of the message in question, as received over the transport
interface documented in diameter_transport(3erl).
If exit then the transport process in question exits. If handle
then the message is processed as usual, a resulting handle_re-
quest/3 or handle_answer/4 callback (if one takes place) indicat-
ing the 5015 error (DIAMETER_INVALID_MESSAGE_LENGTH). If discard
then the message in question is silently discarded.
Defaults to exit.
Note:
The default value reflects the fact that a transport module for a
stream-oriented transport like TCP may not be able to recover from
a message length error since such a transport must use the Message
Length header to divide the incoming byte stream into individual
Diameter messages. An invalid length leaves it with no reliable way
to rediscover message boundaries, which may result in the failure
of subsequent messages. See diameter_tcp(3erl) for the behaviour of
that module.
{pool_size, pos_integer()}:
Number of transport processes to start. For a listening trans-
port, determines the size of the pool of accepting transport pro-
cesses, a larger number being desirable for processing multiple
concurrent peer connection attempts. For a connecting transport,
determines the number of connections to the peer in question that
will be attempted to be establshed: the service_opt(): re-
strict_connections should also be configured on the service in
question to allow multiple connections to the same peer.
{spawn_opt, [term()] | {M,F,A}}:
An options list passed to erlang:spawn_opt/2 to spawn a handler
process for an incoming Diameter request on the local node, or an
MFA that returns the pid of a handler process.
Options monitor and link are ignored in the list-valued case. An
MFA is applied with an additional term prepended to its argument
list, and should return either the pid of the handler process
that invokes diameter_traffic:request/1 on the argument in order
to process the request, or the atom discard. The handler process
need not be local, and diameter need not be started on the remote
node, but diameter and relevant application callbacks must be on
the code path.
Defaults to the empty list.
{strict_capx, boolean()]}:
Whether or not to enforce the RFC 6733 requirement that any mes-
sage before capabilities exchange should close the peer connec-
tion. If false then unexpected messages are discarded.
Defaults to true. Changing this results in non-standard behav-
iour, but can be useful in case peers are known to be behave
badly.
{strict_mbit, boolean()}:
Whether or not to regard an AVP setting the M-bit as erroneous
when the command grammar in question does not explicitly allow
the AVP. If true then such AVPs are regarded as 5001 errors, DI-
AMETER_AVP_UNSUPPORTED. If false then the M-bit is ignored and
policing it becomes the receiver's responsibility.
Defaults to true.
Warning:
RFC 6733 is unclear about the semantics of the M-bit. One the one
hand, the CCF specification in section 3.2 documents AVP in a com-
mand grammar as meaning any arbitrary AVP; on the other hand, 1.3.4
states that AVPs setting the M-bit cannot be added to an existing
command: the modified command must instead be placed in a new Diam-
eter application.
The reason for the latter is presumably interoperability: allowing
arbitrary AVPs setting the M-bit in a command makes its interpreta-
tion implementation-dependent, since there's no guarantee that all
implementations will understand the same set of arbitrary AVPs in
the context of a given command. However, interpreting AVP in a com-
mand grammar as any AVP, regardless of M-bit, renders 1.3.4 mean-
ingless, since the receiver can simply ignore any AVP it thinks
isn't relevant, regardless of the sender's intent.
Beware of confusing mandatory in the sense of the M-bit with manda-
tory in the sense of the command grammar. The former is a semantic
requirement: that the receiver understand the semantics of the AVP
in the context in question. The latter is a syntactic requirement:
whether or not the AVP must occur in the message in question.
{transport_config, term()}:
{transport_config, term(), Unsigned32() | infinity}:
Term passed as the third argument to the start/3 function of the
relevant transport module in order to start a transport process.
Defaults to the empty list.
The 3-tuple form additionally specifies an interval, in millisec-
onds, after which a started transport process should be termi-
nated if it has not yet established a connection. For example,
the following options on a connecting transport request a connec-
tion with one peer over SCTP or another (typically the same) over
TCP.
{transport_module, diameter_sctp}
{transport_config, SctpOpts, 5000}
{transport_module, diameter_tcp}
{transport_config, TcpOpts}
To listen on both SCTP and TCP, define one transport for each.
{transport_module, atom()}:
Module implementing a transport process as defined in diame-
ter_transport(3erl). Defaults to diameter_tcp.
Multiple transport_module and transport_config options are al-
lowed. The order of these is significant in this case (and only
in this case), a transport_module being paired with the first
transport_config following it in the options list, or the default
value for trailing modules. Transport starts will be attempted
with each of the modules in order until one establishes a connec-
tion within the corresponding timeout (see below) or all fail.
{watchdog_config, [{okay|suspect, non_neg_integer()}]}:
Configuration that alters the behaviour of the watchdog state ma-
chine. On key okay, the non-negative number of answered DWR mes-
sages before transitioning from REOPEN to OKAY. On key suspect,
the number of watchdog timeouts before transitioning from OKAY to
SUSPECT when DWR is unanswered, or 0 to not make the transition.
Defaults to [{okay, 3}, {suspect, 1}]. Not specifying a key is
equivalent to specifying the default value for that key.
Warning:
The default value is as required by RFC 3539: changing it results
in non-standard behaviour that should only be used to simulate mis-
behaving nodes during test.
{watchdog_timer, TwInit}:
TwInit = Unsigned32()
| {M,F,A}
The RFC 3539 watchdog timer. An integer value is interpreted as
the RFC's TwInit in milliseconds, a jitter of +/- 2 seconds being
added at each rearming of the timer to compute the RFC's Tw. An
MFA is expected to return the RFC's Tw directly, with jitter ap-
plied, allowing the jitter calculation to be performed by the
callback.
An integer value must be at least 6000 as required by RFC 3539.
Defaults to 30000.
Unrecognized options are silently ignored but are returned unmodi-
fied by service_info/2 and can be referred to in predicate func-
tions passed to remove_transport/2.
transport_ref() = reference():
Reference returned by add_transport/2 that identifies the configu-
ration.
EXPORTS
add_transport(SvcName, {connect|listen, [Opt]}) -> {ok, Ref} | {error,
Reason}
Types:
SvcName = service_name()
Opt = transport_opt()
Ref = transport_ref()
Reason = term()
Add transport capability to a service.
The service will start transport processes as required in order
to establish a connection with the peer, either by connecting to
the peer (connect) or by accepting incoming connection requests
(listen). A connecting transport establishes transport connec-
tions with at most one peer, an listening transport potentially
with many.
The diameter application takes responsibility for exchanging
CER/CEA with the peer. Upon successful completion of capabili-
ties exchange the service calls each relevant application mod-
ule's peer_up/3 callback after which the caller can exchange Di-
ameter messages with the peer over the transport. In addition to
CER/CEA, the service takes responsibility for the handling of
DWR/DWA and required by RFC 3539, as well as for DPR/DPA.
The returned reference uniquely identifies the transport within
the scope of the service. Note that the function returns before
a transport connection has been established.
Note:
It is not an error to add a transport to a service that has not
yet been configured: a service can be started after configuring
its transports.
call(SvcName, App, Request, [Opt]) -> Answer | ok | {error, Reason}
Types:
SvcName = service_name()
App = application_alias()
Request = diameter_codec:message()
Answer = term()
Opt = call_opt()
Send a Diameter request message.
App specifies the Diameter application in which the request is
defined and callbacks to the corresponding callback module will
follow as described below and in diameter_app(3erl). Unless the
detach option is specified, the call returns either when an an-
swer message is received from the peer or an error occurs. In
the answer case, the return value is as returned by a handle_an-
swer/4 callback. In the error case, whether or not the error is
returned directly by diameter or from a handle_error/4 callback
depends on whether or not the outgoing request is successfully
encoded for transmission to the peer, the cases being documented
below.
If there are no suitable peers, or if pick_peer/4 rejects them
by returning false, then {error,no_connection} is returned. Oth-
erwise pick_peer/4 is followed by a prepare_request/3 callback,
the message is encoded and then sent.
There are several error cases which may prevent an answer from
being received and passed to a handle_answer/4 callback:
* If the initial encode of the outgoing request fails, then
the request process fails and {error,encode} is returned.
* If the request is successfully encoded and sent but the an-
swer times out then a handle_error/4 callback takes place
with Reason = timeout.
* If the request is successfully encoded and sent but the ser-
vice in question is stopped before an answer is received
then a handle_error/4 callback takes place with Reason =
cancel.
* If the transport connection with the peer goes down after
the request has been sent but before an answer has been re-
ceived then an attempt is made to resend the request to an
alternate peer. If no such peer is available, or if the sub-
sequent pick_peer/4 callback rejects the candidates, then a
handle_error/4 callback takes place with Reason = failover.
If a peer is selected then a prepare_retransmit/3 callback
takes place, after which the semantics are the same as fol-
lowing an initial prepare_request/3 callback.
* If an encode error takes place during retransmission then
the request process fails and {error,failure} is returned.
* If an application callback made in processing the request
fails (pick_peer, prepare_request, prepare_retransmit, han-
dle_answer or handle_error) then either {error,encode} or
{error,failure} is returned depending on whether or not
there has been an attempt to send the request over the
transport.
Note that {error,encode} is the only return value which guaran-
tees that the request has not been sent over the transport con-
nection.
origin_state_id() -> Unsigned32()
Return a reasonable value for use as Origin-State-Id in outgoing
messages.
The value returned is the number of seconds since
19680120T031408Z, the first value that can be encoded as a Diam-
eter Time(), at the time the diameter application was started.
remove_transport(SvcName, Pred) -> ok | {error, Reason}
Types:
SvcName = service_name()
Pred = Fun | MFA | transport_ref() | list() | true | false
Fun = fun((transport_ref(), connect|listen, list()) -> bool-
ean())
| fun((transport_ref(), list()) -> boolean())
| fun((list()) -> boolean())
MFA = {atom(), atom(), list()}
Reason = term()
Remove previously added transports.
Pred determines which transports to remove. An arity-3-valued
Pred removes all transports for which Pred(Ref, Type, Opts) re-
turns true, where Type and Opts are as passed to add_transport/2
and Ref is as returned by it. The remaining forms are equivalent
to an arity-3 fun as follows.
Pred = fun(transport_ref(), list()): fun(Ref, _, Opts) -> Pred(Ref, Opts) end
Pred = fun(list()): fun(_, _, Opts) -> Pred(Opts) end
Pred = transport_ref(): fun(Ref, _, _) -> Pred == Ref end
Pred = list(): fun(_, _, Opts) -> [] == Pred -- Opts end
Pred = true: fun(_, _, _) -> true end
Pred = false: fun(_, _, _) -> false end
Pred = {M,F,A}: fun(Ref, Type, Opts) -> apply(M, F, [Ref, Type, Opts | A]) end
Removing a transport causes the corresponding transport pro-
cesses to be terminated. Whether or not a DPR message is sent to
a peer is controlled by value of disconnect_cb configured on the
transport.
service_info(SvcName, Info) -> term()
Types:
SvcName = service_name()
Info = Item | [Info]
Item = atom()
Return information about a started service. Requesting info for
an unknown service causes undefined to be returned. Requesting a
list of items causes a tagged list to be returned.
Item can be one of the following.
'Origin-Host':
'Origin-Realm':
'Vendor-Id':
'Product-Name':
'Origin-State-Id':
'Host-IP-Address':
'Supported-Vendor':
'Auth-Application-Id':
'Inband-Security-Id':
'Acct-Application-Id':
'Vendor-Specific-Application-Id':
'Firmware-Revision':
Return a capability value as configured with start_ser-
vice/2.
applications:
Return the list of applications as configured with
start_service/2.
capabilities:
Return a tagged list of all capabilities values as config-
ured with start_service/2.
transport:
Return a list containing one entry for each of the service's
transport as configured with add_transport/2. Each entry is
a tagged list containing both configuration and information
about established peer connections. An example return value
with for a client service with Origin-Host "client.exam-
ple.com" configured with a single transport connected to
"server.example.com" might look as follows.
[[{ref,#Ref<0.0.0.93>},
{type,connect},
{options,[{transport_module,diameter_tcp},
{transport_config,[{ip,{127,0,0,1}},
{raddr,{127,0,0,1}},
{rport,3868},
{reuseaddr,true}]}]},
{watchdog,{<0.66.0>,-576460736368485571,okay}},
{peer,{<0.67.0>,-576460736357885808}},
{apps,[{0,common}]},
{caps,[{origin_host,{"client.example.com","server.example.com"}},
{origin_realm,{"example.com","example.com"}},
{host_ip_address,{[{127,0,0,1}],[{127,0,0,1}]}},
{vendor_id,{0,193}},
{product_name,{"Client","Server"}},
{origin_state_id,{[],[]}},
{supported_vendor_id,{[],[]}},
{auth_application_id,{[0],[0]}},
{inband_security_id,{[],[0]}},
{acct_application_id,{[],[]}},
{vendor_specific_application_id,{[],[]}},
{firmware_revision,{[],[]}},
{avp,{[],[]}}]},
{port,[{owner,<0.69.0>},
{module,diameter_tcp},
{socket,{{127,0,0,1},48758}},
{peer,{{127,0,0,1},3868}},
{statistics,[{recv_oct,656},
{recv_cnt,6},
{recv_max,148},
{recv_avg,109},
{recv_dvi,19},
{send_oct,836},
{send_cnt,6},
{send_max,184},
{send_avg,139},
{send_pend,0}]}]},
{statistics,[{{{0,258,0},recv},3},
{{{0,258,1},send},3},
{{{0,258,0},recv,{'Result-Code',2001}},3},
{{{0,257,0},recv},1},
{{{0,257,1},send},1},
{{{0,257,0},recv,{'Result-Code',2001}},1},
{{{0,280,1},recv},2},
{{{0,280,0},send},2},
{{{0,280,0},send,{'Result-Code',2001}},2}]}]]
Here ref is a transport_ref() and options the corresponding
transport_opt() list passed to add_transport/2. The watchdog
entry shows the state of a connection's RFC 3539 watchdog
state machine. The peer entry identifies the diame-
ter_app:peer_ref() for which there will have been peer_up/3
callbacks for the Diameter applications identified by the
apps entry, common being the application_alias(). The caps
entry identifies the capabilities sent by the local node and
received from the peer during capabilities exchange. The
port entry displays socket-level information about the
transport connection. The statistics entry presents Diame-
ter-level counters, an entry like {{{0,280,1},recv},2} say-
ing that the client has received 2 DWR messages: {0,280,1} =
{Application_Id, Command_Code, R_Flag}.
Note that watchdog, peer, apps, caps and port entries depend
on connectivity with the peer and may not be present. Note
also that the statistics entry presents values accumulated
during the lifetime of the transport configuration.
A listening transport presents its information slightly dif-
ferently since there may be multiple accepted connections
for the same transport_ref(). The transport info returned by
a server with a single client connection might look as fol-
lows.
[[{ref,#Ref<0.0.0.61>},
{type,listen},
{options,[{transport_module,diameter_tcp},
{transport_config,[{reuseaddr,true},
{ip,{127,0,0,1}},
{port,3868}]}]},
{accept,[[{watchdog,{<0.56.0>,-576460739249514012,okay}},
{peer,{<0.58.0>,-576460638229179167}},
{apps,[{0,common}]},
{caps,[{origin_host,{"server.example.com","client.example.com"}},
{origin_realm,{"example.com","example.com"}},
{host_ip_address,{[{127,0,0,1}],[{127,0,0,1}]}},
{vendor_id,{193,0}},
{product_name,{"Server","Client"}},
{origin_state_id,{[],[]}},
{supported_vendor_id,{[],[]}},
{auth_application_id,{[0],[0]}},
{inband_security_id,{[],[]}},
{acct_application_id,{[],[]}},
{vendor_specific_application_id,{[],[]}},
{firmware_revision,{[],[]}},
{avp,{[],[]}}]},
{port,[{owner,<0.62.0>},
{module,diameter_tcp},
{socket,{{127,0,0,1},3868}},
{peer,{{127,0,0,1},48758}},
{statistics,[{recv_oct,1576},
{recv_cnt,16},
{recv_max,184},
{recv_avg,98},
{recv_dvi,26},
{send_oct,1396},
{send_cnt,16},
{send_max,148},
{send_avg,87},
{send_pend,0}]}]}],
[{watchdog,{<0.72.0>,-576460638229717546,initial}}]]},
{statistics,[{{{0,280,0},recv},7},
{{{0,280,1},send},7},
{{{0,280,0},recv,{'Result-Code',2001}},7},
{{{0,258,1},recv},3},
{{{0,258,0},send},3},
{{{0,258,0},send,{'Result-Code',2001}},3},
{{{0,280,1},recv},5},
{{{0,280,0},send},5},
{{{0,280,0},send,{'Result-Code',2001}},5},
{{{0,257,1},recv},1},
{{{0,257,0},send},1},
{{{0,257,0},send,{'Result-Code',2001}},1}]}]]
The information presented here is as in the connect case ex-
cept that the client connections are grouped under an accept
tuple.
Whether or not the transport_opt() pool_size has been con-
figured affects the format of the listing in the case of a
connecting transport, since a value greater than 1 implies
multiple transport processes for the same transport_ref(),
as in the listening case. The format in this case is similar
to the listening case, with a pool tuple in place of an ac-
cept tuple.
connections:
Return a list containing one entry for every established
transport connection whose watchdog state machine is not in
the down state. This is a flat view of transport info which
lists only active connections and for which Diameter-level
statistics are accumulated only for the lifetime of the
transport connection. A return value for the server above
might look as follows.
[[{ref,#Ref<0.0.0.61>},
{type,accept},
{options,[{transport_module,diameter_tcp},
{transport_config,[{reuseaddr,true},
{ip,{127,0,0,1}},
{port,3868}]}]},
{watchdog,{<0.56.0>,-576460739249514012,okay}},
{peer,{<0.58.0>,-576460638229179167}},
{apps,[{0,common}]},
{caps,[{origin_host,{"server.example.com","client.example.com"}},
{origin_realm,{"example.com","example.com"}},
{host_ip_address,{[{127,0,0,1}],[{127,0,0,1}]}},
{vendor_id,{193,0}},
{product_name,{"Server","Client"}},
{origin_state_id,{[],[]}},
{supported_vendor_id,{[],[]}},
{auth_application_id,{[0],[0]}},
{inband_security_id,{[],[]}},
{acct_application_id,{[],[]}},
{vendor_specific_application_id,{[],[]}},
{firmware_revision,{[],[]}},
{avp,{[],[]}}]},
{port,[{owner,<0.62.0>},
{module,diameter_tcp},
{socket,{{127,0,0,1},3868}},
{peer,{{127,0,0,1},48758}},
{statistics,[{recv_oct,10124},
{recv_cnt,132},
{recv_max,184},
{recv_avg,76},
{recv_dvi,9},
{send_oct,10016},
{send_cnt,132},
{send_max,148},
{send_avg,75},
{send_pend,0}]}]},
{statistics,[{{{0,280,0},recv},62},
{{{0,280,1},send},62},
{{{0,280,0},recv,{'Result-Code',2001}},62},
{{{0,258,1},recv},3},
{{{0,258,0},send},3},
{{{0,258,0},send,{'Result-Code',2001}},3},
{{{0,280,1},recv},66},
{{{0,280,0},send},66},
{{{0,280,0},send,{'Result-Code',2001}},66},
{{{0,257,1},recv},1},
{{{0,257,0},send},1},
{{{0,257,0},send,{'Result-Code',2001}},1}]}]]
Note that there may be multiple entries with the same ref,
in contrast to transport info.
statistics:
Return a {{Counter, Ref}, non_neg_integer()} list of counter
values. Ref can be either a transport_ref() or a diame-
ter_app:peer_ref(). Entries for the latter are folded into
corresponding entries for the former as peer connections go
down. Entries for both are removed at remove_transport/2.
The Diameter-level statistics returned by transport and con-
nections info are based upon these entries.
diameter_app:peer_ref():
Return transport configuration associated with a single
peer, as passed to add_transport/2. The returned list is
empty if the peer is unknown. Otherwise it contains the ref,
type and options tuples as in transport and connections info
above. For example:
[{ref,#Ref<0.0.0.61>},
{type,accept},
{options,[{transport_module,diameter_tcp},
{transport_config,[{reuseaddr,true},
{ip,{127,0,0,1}},
{port,3868}]}]}]
services() -> [SvcName]
Types:
SvcName = service_name()
Return the list of started services.
session_id(Ident) -> OctetString()
Types:
Ident = DiameterIdentity()
Return a value for a Session-Id AVP.
The value has the form required by section 8.8 of RFC 6733.
Ident should be the Origin-Host of the peer from which the mes-
sage containing the returned value will be sent.
start() -> ok | {error, Reason}
Start the diameter application.
The diameter application must be started before starting a ser-
vice. In a production system this is typically accomplished by a
boot file, not by calling start/0 explicitly.
start_service(SvcName, Options) -> ok | {error, Reason}
Types:
SvcName = service_name()
Options = [service_opt()]
Reason = term()
Start a diameter service.
A service defines a locally-implemented Diameter node, specify-
ing the capabilities to be advertised during capabilities ex-
change. Transports are added to a service using add_transport/2.
Note:
A transport can both override its service's capabilities and re-
strict its supported Diameter applications so "service = Diame-
ter node as identified by Origin-Host" is not necessarily the
case.
stop() -> ok | {error, Reason}
Stop the diameter application.
stop_service(SvcName) -> ok | {error, Reason}
Types:
SvcName = service_name()
Reason = term()
Stop a diameter service.
Stopping a service causes all associated transport connections
to be broken. A DPR message will be sent as in the case of re-
move_transport/2.
Note:
Stopping a service does not remove any associated transports:
remove_transport/2 must be called to remove transport configura-
tion.
subscribe(SvcName) -> true
Types:
SvcName = service_name()
Subscribe to service_event() messages from a service.
It is not an error to subscribe to events from a service that
does not yet exist. Doing so before adding transports is re-
quired to guarantee the reception of all transport-related
events.
unsubscribe(SvcName) -> true
Types:
SvcName = service_name()
Unsubscribe to event messages from a service.
SEE ALSO
diameter_app(3erl), diameter_transport(3erl), diameter_dict(5)
Ericsson AB diameter 2.2.3 diameter(3erl)