diameter

v2.6

Release Notes

Releases are listed in reverse chronological order, most recent first.

diameter 2.6

Improvements and New Features

Add new option 'indirect_inherits' to diameter_make:codec/2

Own Id: OTP-19626 Aux Id: GH-8235, PR-10149

diameter 2.5.2

Fixed Bugs and Malfunctions

Added documentation about 'proxy' and 'resend' options in diameter:handle_request/3

Own Id: OTP-19768 Aux Id: GH-10150, PR-10182

diameter 2.5.1

Fixed Bugs and Malfunctions

With this change message_cb callback will be called with updated state for processing 'ack' after 'send'.

Own Id: OTP-19753 Aux Id: PR-9815

diameter 2.5

Fixed Bugs and Malfunctions

With this change diameter will not crash when decoding a DiameterURI without port number.

Own Id: OTP-19620 Aux Id: PR-9321

Improvements and New Features

EEP-69: Nominal Types has been implemented. As a side effect, nominal types can encode opaque types. We changed all opaque-handling logic and improved opaque warnings in Dialyzer.

All existing Erlang type systems are structural: two types are seen as equivalent if their structures are the same. Type comparisons are based on the structures of the types, not on how the user explicitly defines them. For example, in the following example, meter() and foot() are equivalent. The two types can be used interchangeably. Neither of them differ from the basic type integer().

-type meter() :: integer().
-type foot() :: integer().

Nominal typing is an alternative type system, where two types are equivalent if and only if they are declared with the same type name. The EEP proposes one new syntax -nominal for declaring nominal types. Under nominal typing, meter() and foot() are no longer compatible. Whenever a function expects type meter(), passing in type foot() would result in a Dialyzer error.

-nominal meter() :: integer().
-nominal foot() :: integer().

More nominal type-checking rules can be found in the EEP. It is worth noting that most work for adding nominal types and type-checking is in erl_types.erl. The rest are changes that removed the previous opaque type-checking, and added an improved version of it using nominal type-checking with reworked warnings.

Backwards compatibility for opaque type-checking is not preserved by this PR. Previous opaque warnings can appear with slightly different wordings. A new kind of opaque warning opaque_union is added, together with a Dialyzer option no_opaque_union to turn this kind of warnings off.

Own Id: OTP-19364 Aux Id: PR-9079

The license and copyright header has changed format to include an SPDX-License-Identifier. At the same time, most files have been updated to follow a uniform standard for license headers.

Own Id: OTP-19575 Aux Id: PR-9670

With this change diameter will not use slave terminology

Own Id: OTP-19621 Aux Id: PR-9786

diameter 2.4.1.1

Fixed Bugs and Malfunctions

Added documentation about 'proxy' and 'resend' options in diameter:handle_request/3

Own Id: OTP-19768 Aux Id: GH-10150, PR-10182

diameter 2.4.1

Fixed Bugs and Malfunctions

Function specs for the main API module has been updated.

Own Id: OTP-19126 Aux Id: #8399

Man pages are now available for erl, erlc, dialyzer, and all other programs that are included in Erlang/OTP.

Own Id: OTP-19201 Aux Id: PR-8740

diameter:stop_service/1 has been made more synchronous.

Own Id: OTP-19206 Aux Id: ERIERL-1102

diameter 2.4

Improvements and New Features

-callback attributes have been added to diameter_app and diameter_transport.

Own Id: OTP-18783 Aux Id: PR-7699

The documentation has been migrated to use Markdown and ExDoc.

Own Id: OTP-18955 Aux Id: PR-8026

Pick peer can now also handle request of type #diameter_packet{}.

Own Id: OTP-19090 Aux Id: PR-8399

diameter 2.3.2.2

Fixed Bugs and Malfunctions

Stop service has been made more synchronous.

Own Id: OTP-19206 Aux Id: ERIERL-1102

diameter 2.3.2.1

Improvements and New Features

Pick peer can now also handle request of type #diameter_packet{}.

Own Id: OTP-19090 Aux Id: PR-8399

diameter 2.3.2

Fixed Bugs and Malfunctions

Reduce the impact of calling service_info by not counting the binaries (on the heap) info, This is done by introducing an option, bins_info, which controls this.

Own Id: OTP-19040 Aux Id: ERIERL-1060

diameter 2.3.1

Fixed Bugs and Malfunctions

Replaced unintentional Erlang Public License 1.1 headers in some files with the intended Apache License 2.0 header.

Own Id: OTP-18815 Aux Id: PR-7780

diameter 2.3

Improvements and New Features

Replace size/1 with either tuple_size/1 or byte_size/1

The size/1 BIF is not optimized by the JIT, and its use can result in worse types for Dialyzer.

When one knows that the value being tested must be a tuple, tuple_size/1 should always be preferred.

When one knows that the value being tested must be a binary, byte_size/1 should be preferred. However, byte_size/1 also accepts a bitstring (rounding up size to a whole number of bytes), so one must make sure that the call to byte_size/ is preceded by a call to is_binary/1 to ensure that bitstrings are rejected. Note that the compiler removes redundant calls to is_binary/1, so if one is not sure whether previous code had made sure that the argument is a binary, it does not harm to add an is_binary/1 test immediately before the call to byte_size/1.

Own Id: OTP-18405 Aux Id: GH-6672,PR-6702,PR-6768,PR-6700,PR-6769,PR-6812,PR-6814

Deprecates dbg:stop_clear/0 because it is simply a function alias to dbg:stop/0

Own Id: OTP-18478 Aux Id: GH-6903

The implementation has been fixed to use proc_lib:init_fail/2,3 where appropriate, instead of proc_lib:init_ack/1,2.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-18490 Aux Id: OTP-18471, GH-6339, PR-6843

diameter 2.2.7.2

Fixed Bugs and Malfunctions

`diameter:stop_service/1` has been made more synchronous.

Own Id: OTP-19206 Aux Id: ERIERL-1102

diameter 2.2.7.1

Fixed Bugs and Malfunctions

Reduce the impact of calling service_info by not counting the binaries (on the heap) info, This is done by introducing an option, bins_info, which controls this.

Own Id: OTP-19040 Aux Id: ERIERL-1060

diameter 2.2.7

Improvements and New Features

There is a new configure option, --enable-deterministic-build, which will apply the deterministic compiler option when building Erlang/OTP. The deterministic option has been improved to eliminate more sources of non-determinism in several applications.

Own Id: OTP-18165 Aux Id: PR-5965

diameter 2.2.6

Fixed Bugs and Malfunctions

Fix decode of non-IP address types; that is, of values of the derived AVP data format Address whose first two octets specify an address family other than 1 (IP) or 2 (IP6). Such values have never been decoded, and were treated as decode errors. They're now decoded to a 2-tuple of the integer() address family and binary() remaining octets, with no family-specific decode. The 2-tuple distinguishes the decode from the 4-tuple and 8-tuple IP address decodes. 2-tuples are also now encoded.

Note that even currently unassigned address families are decoded: only the reserved values, 0 and 65535, are treated as errors.

Own Id: OTP-17976 Aux Id: GH-5463

diameter 2.2.5

Fixed Bugs and Malfunctions

The compilation time is no longer recorded in BEAM files. There remained several undocumented functions that attempted to retrieve compilation times. Those have now been removed.

Own Id: OTP-17962

diameter 2.2.4

Fixed Bugs and Malfunctions

The unordered option was ignored on a client diameter_sctp transport, causing all delivery to be ordered.

The association id was not specified to gen_sctp when requesting unordered delivery, causing the setting to be applied to the whole endpoint.

Thanks to Bengt Kleberg and Andreas Schultz.

Own Id: OTP-17366 Aux Id: GH-4775

diameter 2.2.3

Fixed Bugs and Malfunctions

Add the 'first' tuple to type diameter:peer_filter/0. The filter was added in OTP-17.5.6.8 and OTP-18.3, but neither release updated the type specification.

Own Id: OTP-16548 Aux Id: ERL-1191

diameter 2.2.2

Fixed Bugs and Malfunctions

The possibility of choosing a handler process for an incoming Diameter request with a configured MFA was documented in OTP 20.0, but counters (with {traffic_counters, true}) were not incremented when this process was on a remote node. Counters are now incremented on the node that configures the transport in question.

Introduced in OTP 21.3.

Own Id: OTP-16457

Transport options differing from those passed to diameter:add_transport/2 were used in several situations: when starting a transport process after connect_timer expiry after an initial connection attempt has failed, when starting a transport process after a connection has been accepted, when sending events, when returning options in diameter:service_info/2, and possibly more. In particular, the following configuration options to diameter:add_transport/2 were dropped: avp_dictionaries, incoming_maxlen, spawn_opt, strict_mbit.

Moreover, any service options mistakenly passed to diameter:add_transport/2 were interpreted as such, instead of being ignored as the documentation states, with the consequence that outgoing and incoming requests saw different values of some options, some were always taken from transport options, and others from service options.

diameter:add_transport/2 must be called in new code for the fix to have effect.

Introduced in OTP 20.1.

Own Id: OTP-16459

diameter 2.2.1

Fixed Bugs and Malfunctions

Fix inadvertently broad monitor that resulted in gen_server cast messages to hidden nodes from module diameter_dist.

Own Id: OTP-15768

diameter 2.2

Fixed Bugs and Malfunctions

Fix failure of incoming answer message with faulty Experimental-Result-Code. Failure to decode the AVP resulted in an uncaught exception, with no no handle_answer/error callback as a consequence.

Own Id: OTP-15569 Aux Id: ERIERL-302

Improvements and New Features

Add spawn_opt MFA configuration to allow a callback to spawn a handler process for an incoming Diameter request on an an arbitrary node. Module diameter_dist provides a route_session/2 that can be used to distribute requests based on Session-Id, although this module is currently only documented in the module itself and may change.

Own Id: OTP-15398

diameter 2.1.6

Fixed Bugs and Malfunctions

Fix function_clause when sending an outgoing request after DPA has been sent in response to an incoming DPR. The caused the diameter_peer_fsm gen_server associated with the peer connection to fail, which could then result in the transport connection being reset before the peer closed it upon reception of DPA.

Own Id: OTP-15198 Aux Id: ERIERL-213

diameter 2.1.5

Fixed Bugs and Malfunctions

Fix documentation typos.

Own Id: OTP-15045

diameter 2.1.4.1

Fixed Bugs and Malfunctions

Fix failure of incoming answer message with faulty Experimental-Result-Code. Failure to decode the AVP resulted in an uncaught exception, with no no handle_answer/error callback as a consequence.

Own Id: OTP-15569 Aux Id: ERIERL-302

diameter 2.1.4

Fixed Bugs and Malfunctions

Fix close of diameter_tcp/sctp listening socket at diameter:remove_transport/2, that was broken in diameter 2.1. A reconfigured transport could not listen on the same endpoint as a result.

Own Id: OTP-14839

Fix handling of SUSPECT connections at service termination. A connection with this watchdog state caused diameter_service:terminate/2 to fail.

Own Id: OTP-14947 Aux Id: ERIERL-124

diameter 2.1.3

Fixed Bugs and Malfunctions

Fix documentation typo: peer_up/3 was written where peer_down/3 was intended.

Own Id: OTP-14805

diameter 2.1.2

Fixed Bugs and Malfunctions

A fault introduced in diameter 2.1 could cause decode errors to be ignored in AVPs following the header of a Grouped AVP.

Own Id: OTP-14684 Aux Id: ERIERL-85

diameter 2.1.1

Fixed Bugs and Malfunctions

An inadvertently removed monitor in diameter 2.1 caused the ets table diameter_reg to leak entries, and caused service restart and more to fail.

Own Id: OTP-14668 Aux Id: ERIERL-83

diameter 2.1

Fixed Bugs and Malfunctions

Fix handling of Proxy-Info in answer messages setting the E-bit.

RFC 6733 requires that Proxy-Info AVPs in an incoming request be echoed in an outgoing answer. This was not done in answers formulated by diameter; for example, as a result of a handle_request callback having returned an 'answer-message' or protocol_error tuple.

Own Id: OTP-9869

React to nodeup/nodedown when sharing peer connections.

Service configuration share_peers and use_shared_peers did not respond to the coming and going of remote nodes.

Own Id: OTP-14011

Fix inappropriate message callbacks.

An incoming CER or DPR was regarded as discarded, resulting in a corresponding message callback (if configured) in diameter_tcp/sctp.

Own Id: OTP-14486

Fix handling of 5009 errors (DIAMETER_AVP_OCCURS_TOO_MANY TIMES).

RFC 6733 says that the first AVP that exceeds the bound should be reported, but the suggestions in the errors field of a diameter_packet record counted AVPs from the rear of the message, not the front. Additionally, diameter 2.0 in OTP 20.0 broke the counting by accepting one more AVP than the message grammar in question allowed.

Own Id: OTP-14512

Match case insensitively in diameter_tcp/sctp accept tuple.

Matching of remote addresses when accepting connections in a listening transport was case-sensitive, causing the semantics to change as a consequence of (kernel) OTP-13006.

Own Id: OTP-14535 Aux Id: OTP-13006

Fix backwards incompatibility of remote send when sharing transports.

The sending of requests over a transport connection on a remote node running an older version of diameter was broken by diameter 2.0 in OTP 20.0.

Own Id: OTP-14552

Fix diameter_packet.avps decode of Grouped AVP errors in Failed-AVP.

Decode didn't produce a list of diameter_avp records, so information about faulty component AVPs was lost.

Own Id: OTP-14607

Improvements and New Features

Let unordered delivery be configured in diameter_sctp.

With option {unordered, boolean() | pos_integer()}, with false the default, and N equivalent to OS =< N, where OS is the number of outbound streams negotiated on the association in question. If configured, unordered sending commences upon reception of a second message, outgoing messages being sent on stream 0 before this.

The default false is for backwards compatibility, but false or 1 should be set to follow RFC 6733's recommendation on the use of unordered sending to avoid head-of-line blocking. There is typically no meaningful order to preserve, since the order in which outgoing messages are received by a transport process isn't known to the sender.

Own Id: OTP-10889

Complete/simplify Standards Compliance in User's Guide.

Own Id: OTP-10927

Add service option decode_format.

To allow incoming messages to be decoded into maps or lists instead of records. Messages can be presented in any of the formats for encode.

Decode performance has also been improved.

Own Id: OTP-14511 Aux Id: OTP-14343

Add service option traffic_counters.

To let message-related counters be disabled, which can be a performance improvement in some usecases.

Own Id: OTP-14521

Allow loopback/any as local addresses in diameter_tcp/sctp.

The atoms were implied by documentation, but not handled in code.

Own Id: OTP-14544

Add transport option strict_capx.

To allow the RFC 6733 requirement that a transport connection be closed if a message is received before capabilities exchange to be relaxed.

Own Id: OTP-14546

Be consistent with service/transport configuration.

For options for which it's meaningful, defaults values for transport options can now be configured on a service. This was previously the case only for an arbitrary subset of options.

Own Id: OTP-14555

Add service/transport option avp_dictionaries.

To provide better support for AVPs that are not defined in the application dictionary: configuring additional dictionaries in an avp_dictionaries tuple allows their AVPs to be encoded/decoded in much the same fashion as application AVPs.

The motivation is RFC 7683 Diameter Overload, Indicator Conveyance (DOIC), that defines AVPs intended to be piggybacked onto arbitrary messages. A DOIC dictionary has been included in the installation, in module diameter_gen_doic_rfc7683.

Own Id: OTP-14588

Decode application AVPs in answers setting the E-bit.

AVPs defined in the application of the message being sent were previously not decoded, only those in the common application that defines the answer-message grammar.

Own Id: OTP-14596

diameter 2.0

Improvements and New Features

Let candidate peers be passed to diameter:call/4

With call option peer, to allow a request to be sent to a peer that hasn't advertised support for the application in question.

RFC 6733 2.4 requires a node to send the application identifiers of all locally supported applications at capabilities exchange, but not all nodes respect this for the common application, and diameter itself will send D[WP][RA] without the common application having been explicitly advertised. Regarding the common application as implicit renders Result-Code 5010 (DIAMETER_NO_COMMON_APPLICATION) meaningless however, so allow any request to be sent as long as there is a configured dictionary to support it.

Own Id: OTP-14338

Improve performance of message encode/decode and related handling.

Dictionaries using @custom_types or @codecs will need to adapt the corresponding functions to accept an additional argument that is now passed through encode/decode, which was required to remove various process dictionary-based workarounds that have been used to solve problems in the past.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-14343

Add transport options to avoid deadlock and allow for load regulation.

Both diameter_tcp and diameter_sctp now accept two new configuration options: sender and message_cb. The former causes outgoing sends to take place in a dedicated process, to avoid the possibility of deadlock when both the transport process and its peer block in send. The latter allows a callback to control the reading of messages on the socket, to allow for backpressure towards peers when the rate of incoming traffic is greater than can otherwise be handled.

Neither of these options are yet documented, but are unlikely to change unless problems are discovered. The sender option is not the default since it should probably always be used in combination with message_cb, to prevent incoming requests from being read at a higher rate than a peer allows outgoing answers to be sent.

Own Id: OTP-14455 Aux Id: ERL-332

diameter 1.12.2

Fixed Bugs and Malfunctions

An improvement in the handling of peer failover in diameter 1.12.1 adversely affected performance when sending requests. Further, the inefficient use of a public table to route incoming answers has been removed.

Own Id: OTP-14206

Fixed xml issues in old release notes

Own Id: OTP-14269

diameter 1.12.1

Fixed Bugs and Malfunctions

Close diameter_tcp/sctp listening sockets at diameter:stop_service/1.

Broken by OTP-13611.

Own Id: OTP-13787 Aux Id: OTP-13611

Update build scripts to not make assumptions about where env, cp and perl are located.

Own Id: OTP-13800

diameter 1.12

Fixed Bugs and Malfunctions

Ensure listening socket is closed at transport removal.

Transport removal did not immediately close a diameter_tcp/sctp listening socket, and a subsequent peer connection caused it to remain open.

Own Id: OTP-13611

Improvements and New Features

Add diameter:peer_info/1.

That retrieves information in the style of diameter:service_info/2, but for a single peer connection.

Own Id: OTP-13508

diameter 1.11.2

Fixed Bugs and Malfunctions

Make peer handling more efficient.

Inefficient lookup and manipulation of peer lists could result in poor performance when many outgoing requests were sent simultaneously, or when many peers connected simultaneously. Filtering peer lists on realm/host is now also more efficient in many cases.

Own Id: OTP-13164

Fix handling of shared peer connections in watchdog state SUSPECT.

A peer connection shared from a remote node was regarded as being up for the lifetime of the connection, ignoring watchdog transitions into state SUSPECT.

Own Id: OTP-13342

diameter 1.11.1

Fixed Bugs and Malfunctions

Fix request table leaks

The End-to-End and Hop-by-Hop identifiers of outgoing Diameter requests are stored in a table in order for the caller to be located when the corresponding answer message is received. Entries were orphaned if the handler was terminated by an exit signal as a consequence of actions taken by callback functions, or if callbacks modified identifiers in retransmission cases.

Own Id: OTP-13137

diameter 1.11

Fixed Bugs and Malfunctions

Fix relay encode of nested, Grouped AVPs.

A fault in OTP-12475 caused encode to fail if the first AVP in a Grouped AVP was itself Grouped.

Own Id: OTP-12879 Aux Id: OTP-12475

Match acceptable peer addresses case insensitively.

Regular expressions passed in an 'accept' tuple to diameter_tcp or diameter_sctp inappropriately matched case.

Own Id: OTP-12902

Fix diameter_watchdog function clause.

OTP-12912 introduced an error with accepting transports setting {restrict_connections, false}, causing processes to fail when peer connections were terminated.

Own Id: OTP-12969

Improvements and New Features

Don't report 5005 (DIAMETER_AVP_MISSING) errors unnecessarily.

An AVP whose decode failed was reported as missing, despite having been reported with another error as a consequence of the failure.

Own Id: OTP-12871

Improve decode performance.

The time required to decode a message increased quadratically with the number of AVPs in the worst case, leading to extremely long execution times.

Own Id: OTP-12891

Improve watchdog and statistics performance.

Inefficient use of timers contributed to poor performance at high load, as did ordering of the table statistics are written to.

Own Id: OTP-12912

Add service_opt() strict_mbit.

There are differing opinions on whether or not reception of an arbitrary AVP setting the M-bit is an error. The default interpretation is strict: if a command grammar doesn't explicitly allow an AVP setting the M-bit then reception of such an AVP is regarded as an error. Setting {strict_mbit, false} disables this check.

Own Id: OTP-12947

diameter 1.10

Fixed Bugs and Malfunctions

Fix decode of Grouped AVPs containing errors.

RFC 6733 says this of Failed-AVP in 7.5:

____ - In the case where the offending AVP is embedded within a Grouped AVP, the Failed-AVP MAY contain the grouped AVP, which in turn contains the single offending AVP. The same method MAY be employed if the grouped AVP itself is embedded in yet another grouped AVP and so on. In this case, the Failed-AVP MAY contain the grouped AVP hierarchy up to the single offending AVP. This enables the recipient to detect the location of the offending AVP when embedded in a group.

It says this of DIAMETER_INVALID_AVP_LENGTH in 7.1.5:

____ - The request contained an AVP with an invalid length. A Diameter message indicating this error MUST include the offending AVPs within a Failed-AVP AVP. In cases where the erroneous AVP length value exceeds the message length or is less than the minimum AVP header length, it is sufficient to include the offending AVP header and a zero filled payload of the minimum required length for the payloads data type. If the AVP is a Grouped AVP, the Grouped AVP header with an empty payload would be sufficient to indicate the offending AVP. In the case where the offending AVP header cannot be fully decoded when the AVP length is less than the minimum AVP header length, it is sufficient to include an offending AVP header that is formulated by padding the incomplete AVP header with zero up to the minimum AVP header length.

The AVPs placed in the errors field of a diameter_packet record are intended to be appropriate for inclusion in a Failed-AVP, but neither of the above paragraphs has been followed in the Grouped case: the entire faulty AVP (non-faulty components and all) has been included. This made it difficult to identify the actual faulty AVP in all but simple cases.

The decode is now adapted to the RFC, and implements the suggested single faulty AVP, nested in as many Grouped containers as required.

Own Id: OTP-12721

Fix SCTP problems on Solaris.

The allocation of association ids in Solaris was in conflict with an assumption made in diameter_sctp, resulting in failures when accepting multiple peer connections.

Own Id: OTP-12768

Fix start order of alternate transports.

A transport configured with diameter:add_transport/2 can be passed multiple transport_module/transport_config tuples in order to specify alternate configuration, modules being attempted in order until one succeeds. This is primarily for the connecting case; for example, to allow a transport to be configured to first attempt connection over SCTP, and then TCP in case SCTP fails. Multiple module tuples can be paired with a single config tuple, but in this case the start order was reversed relative to the order in which the modules were specified.

Own Id: OTP-12851

Improvements and New Features

Change license text from Erlang Public License to Apache Public License v2.

Own Id: OTP-12845

diameter 1.9.2

Fixed Bugs and Malfunctions

Fix broken relay counters.

OTP-12654 in OTP 17.5.3 broke counters in the case of answer messages received in the relay application. Counters were accumulated as unknown messages or no_result_code instead of as relayed messages on the intended Result-Code and 'Experimental-Result' tuples.

Own Id: OTP-12741

Fix diameter_sctp listener race.

An oversight in OTP-12428 made it possible to start a transport process that could not establish associations.

Own Id: OTP-12744

diameter 1.9.1

Known Bugs and Problems

Don't leave extra bit in decoded AVP data.

OTP-12074 in OTP 17.3 missed one case: a length error on a trailing AVP unknown to the dictionary in question.

Own Id: OTP-12642

Don't confuse Result-Code and Experimental-Result.

The errors field of a decoded diameter_packet record was populated with a Result-Code AVP when an Experimental-Result containing a 3xxx Result-Code was received in an answer not setting the E-bit. The correct AVP is now extracted from the incoming message.

Own Id: OTP-12654

Don't count on unknown Application Id.

OTP-11721 in OTP 17.1 missed the case of an Application Id not agreeing with that of the dictionary in question, causing counters to be accumulated on keys containing the unknown id.

Own Id: OTP-12701

diameter 1.9

Fixed Bugs and Malfunctions

Don't discard outgoing answers unnecessarily.

Answers missing a Result-Code AVP or setting an E-bit inappropriately were discarded even if encode was successful.

Own Id: OTP-11492

Increase supervision timeouts.

At diameter application shutdown, DPR could be omitted on open peer connections because of short supervision timeouts.

Own Id: OTP-12412

Fix retransmission of messages sent as header/avps list.

Extracting End-to-End and Hop-by-Hop Identifiers resulted in a function clause error, resulting in a handle_error callback.

Own Id: OTP-12415

Fix diameter_avp decode of Grouped AVPs having decode errors.

Components of such an AVP were not extracted, causing it to be represented by a single diameter_avp record instead of the intended list.

Dictionary files must be recompiled for the fix to have effect.

Own Id: OTP-12475

Fix ordering of AVPs in relayed messages.

The order was reversed relative to the received order, with a Route-Record AVP prepended.

Thanks to Andrzej Trawiński.

Own Id: OTP-12551

Fix issues with DiameterURI encode/decode.

RFC 6773 changed the default port and transport, but the RFC 3588 defaults were used even if the RFC 6733 common dictionary was in use. The RFC 3588 defaults are now only used when the common dictionary is diameter_gen_base_rfc3588.

Both RFC 3588 and 6733 disallow transport=udp;protocol=diameter. Encode of the combination now fails.

Decode of ports numbers outside the range 0-65535 and fully qualified domain names longer than 255 octets now fails.

Note that RFC 3588 is obsolete, and that there is a diameter_gen_base_rfc6733. The change in defaults is a potential interoperability problem when moving to RFC 6733 with peers that do not send all URI components. The fact that 6733 allows 5xxx result codes in answer messages setting the E-bit, which RFC 3588 doesn't, is another.

Own Id: OTP-12589

Improvements and New Features

Add service_opt() string_decode.

To disable the decode of potentially large binaries to string. This prevents large strings from being copied when incoming Diameter messages are passed between processes, a vulnerability that can lead to memory being exhausted given sufficiently malicious peers.

The value is a boolean(), true being the default for backwards compatibility. Setting false causes both diameter_caps records and decoded messages to contain binary() in relevant places that previously had string(): diameter_app(3) callbacks need to be prepared for the change.

The Diameter types affected are OctetString and the derived types UTF8String, DiameterIdentity, DiameterURI, IPFilterRule, and QoSFilterRule. Time and Address are unaffected.

Own Id: OTP-11952

Add transport_opt() pool_size.

To allow for pools of accepting transport processes, which can better service multiple simultaneous peer connections. The option can also be used with connecting transports, to establish multiple connections to the same peer without having to configure multiple transports.

Own Id: OTP-12428

Allow DPR to be sent with diameter:call/4.

It has been possible to send, but the answer was regarded as unsolicited and discarded. DPA now causes the transport process in question to be terminated, as for DPR that diameter itself sends.

Own Id: OTP-12542

Discard requests after DPR.

RFC 6733 is imprecise, but the tone is that messages received after DPR are an exception to be dealt with only because of the possibility of unordered delivery over SCTP. As a consequence, and because a request following DPR is unlikely to be answered due to the impending loss of the peer connection, discard outgoing requests following an outgoing or incoming DPR. Incoming requests are also discarded, with the exception of DPR itself. Answers are sent and received as usual.

Own Id: OTP-12543

Add transport_opt() dpr_timeout.

To cause a peer connection to be closed following an outgoing DPA when the peer fails to do so. It is the recipient of DPA that should close the connection according to RFC 6733.

Own Id: OTP-12609

Add service_opt() incoming_maxlen.

To bound the expected size of incoming Diameter messages. Messages larger than the specified number of bytes are discarded, to prevent a malicious peer from generating excessive load.

Own Id: OTP-12628

diameter 1.8

Fixed Bugs and Malfunctions

Fix remote diameter_request table leak.

An outgoing request whose pick_peer callback selected a transport on another node resulted in an orphaned table entry on that node.

Own Id: OTP-12196

Fix handling of 3xxx Result-Code without E-bit.

OTP-12233 broke the population of the errors field of the diameter_packet record when an incoming request with an E-bit/Result-Code mismatch was detected, causing a 4-tuple to be inserted as Result-Code in a diameter_avp record.

Own Id: OTP-12233

Fix ignored connect timer.

There are two timers governing the establishment of peer connections: connect_timer and watchdog_timer. The former is the RFC 6733 Tc timer, and is used at initial connection establishment. The latter is RFC 3539 TwInit, and is used for connection reestablishment. A connecting transport erroneously used watchdog_timer in both cases.

Own Id: OTP-12281 Aux Id: seq12728

Improvements and New Features

Order candidate peers in pick_peer callbacks.

The order of candidate peers presented to a diameter_app(3) pick_peer callback has previously not been documented, but there are use cases that are simplified by an ordering. The order is now determined by the filter.

Own Id: OTP-12308

diameter 1.7.1

Fixed Bugs and Malfunctions

Don't leave extra bit in decoded AVP data.

An extra bit could be communicated in the data field of a diameter_avp record in the case of length errors. Of no consequence for code using the record encoding of Diameter messages, but code examining diameter_avp records would see this bit.

Dictionary files must be recompiled for the fix to have effect.

Own Id: OTP-12074

Fix counting of outgoing requests and answers setting the E-bit.

OTP-11721 broke these counters for all outgoing requests except DWR, and caused answers setting the E-bit to be counted as unknown messages.

Own Id: OTP-12080

Fix Failed-AVP decode.

The best-effort decode only worked for AVPs in the common dictionary, not for those in the dictionary of the application identified in the Diameter Header of the answer message in question.

Failed-AVP in an answer decoded with the RFC 3588 common dictionary (diameter_gen_base_rfc3588) was regarded as an error. The RFC 6733 dictionary was unaffected.

Dictionary files must be recompiled for the fix to have effect.

Own Id: OTP-12094

diameter 1.7

Fixed Bugs and Malfunctions

Improve robustness.

Counters returned by diameter:service_info/2 now only count messages known to the dictionary in question, so that an attacker cannot cause arbitrarily many counters to be created.

Messages to the Erlang log have been minimized, and those related to traffic have been removed entirely since an attacker could cause a node to be logged to death. Consequently, the default answer_errors configuration has been changed from report to discard. A service needs to be restarted for the change in default to take effect.

Own Id: OTP-11721

Fix request table leak.

Outgoing Diameter requests are stored in a table until an answer is received or times out. Calling diameter:stop_service/1 before this took place would orphan the entries, resulting in a memory leak.

Own Id: OTP-11893

Fix broken SCTP transport.

OTP-11593 caused the sending of answer messages over SCTP to fail.

Own Id: OTP-11901 Aux Id: OTP-11593

Fix watchdog process leak.

A failed capabilities exchange on a listening transport would orphan a process, causing a memory leak.

Own Id: OTP-11934

Fix incorrect handling of incoming DPR.

In the case of a listening transport, a reconnection by a peer following DPR could transition the watchdog state to REOPEN instead of OKAY.

Own Id: OTP-11938

Fix handling of AVP length errors on unknown AVPs.

An AVP (Header) length that pointed past the end of the message was not flagged as a 5014 error in this case. Moreover, encoding such an AVP in the Failed-AVP of an answer message as a consequence of other errors (eg. M-bit, resulting in 5001) failed if the AVP contained a complete header.

Dictionary files must be recompiled for the fix to have effect.

Own Id: OTP-11946

Fix broken check in dictionary compilation.

That an AVP specified in the content of a @codecs or @custom_types section was undefined went undetected, causing compilation to fail when attempting to lookup the AVP's type.

Own Id: OTP-11958

Improvements and New Features

Add result code counters for CEA, DWA, and DPA.

In addition to the existing result code counters on other answer messages.

Own Id: OTP-11891

Add best-effort decode of AVPs within Failed-AVP.

OTP-11007 disabled the decode of AVPs in Failed-AVP since errors could cause the decode of Failed-AVP itself to fail. Component AVPs are now decoded if possible, otherwise not. AVPs of type Grouped are decoded as much as possible, as deeply as possible.

Dictionary files must be recompiled for the fix to have effect.

Own Id: OTP-11936 Aux Id: OTP-11007

Add counters for encode errors in outgoing Diameter messages.

In addition to the existing counters on decode errors. The latter now count independently of result codes in answer messages since decode errors do not preclude the presence of a result code.

Own Id: OTP-11937

diameter 1.6

Fixed Bugs and Malfunctions

Add missing check at dictionary compilation.

In particular, that an AVP defined as having type Grouped in an @avp_types section has a corresponding definition in a @grouped section.

Own Id: OTP-11561

Correct documentation on the setting of Origin-State-Id

It was incorrectly stated that the AVP would be set in an outgoing DPR/DPA.

Own Id: OTP-11583

Change interface for communicating outbound stream id to diameter_sctp

The module uses the transport_data field of record diameter_packet to communicate the stream on which the an incoming message is received and on which an outgoing message should be sent, the previous interface being that both are communicated as a tuple of the form {stream, Id}. However, since diameter retains the value of an incoming request's transport_data unless the corresponding answer message specifies otherwise, the behaviour in this case is to send an answer on the outbound stream with the same identifier as the that of the inbound stream on which the request was received. If the inbound stream id is greater than or equal to the number of outbound streams then this is guaranteed to fail, causing the transport process in question to terminate. There is no relationship between inbound and outbound stream identifiers so diameter_sctp's imposition of one is simply wrong.

Outbound stream ids are now communicated with a different tuple: {outstream, Id}, interpreted modulo the number of outbound streams. Thus, retention of an inbound request's transport_data has no effect on the selection of an outbound stream.

The change in interface is not strictly backwards compatible because of the new atom for the outbound stream. However, as there is currently no documented way of obtaining the available number of outbound streams for a peer connection, there is no way for a client to have known the range of ids from which it could reliably have chosen with the previous interface, so any setting of the outbound stream has probably been unintentional. Not explicitly specifying an outbound stream now results in a round-robin selection.

Thanks to Sharmila Pillai for reporting the problem.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-11593

Fix unicode path failure in diameter_make:codec/2.

A dictionary path containing a unicode codepoint > 255 caused the function to fail.

Own Id: OTP-11655

Fix 'accept' config to diameter_sctp.

OTP-10893 added support for {accept, Match} tuples to specify addresses or regexps that should be matched against peer addresses to decide whether or not a newly established association should be retained, but this hasn't been functional in the SCTP case because of missing support in inet(3).

The display of both local and peer addresses in diameter:service_info/2 output has also been corrected.

Own Id: OTP-11661 Aux Id: OTP-10229

Be lenient with the M-bit in Grouped AVPs.

RFC 6733 says this, in 4.4:

____ - Receivers of a Grouped AVP that does not have the 'M' (mandatory) bit set and one or more of the encapsulated AVPs within the group has the 'M' (mandatory) bit set MAY simply be ignored if the Grouped AVP itself is unrecognized. The rule applies even if the encapsulated AVP with its 'M' (mandatory) bit set is further encapsulated within other sub-groups, i.e., other Grouped AVPs embedded within the Grouped AVP.

The first sentence is mangled but take it to mean this:

____ - An unrecognized AVP of type Grouped that does not set the 'M' bit MAY be ignored even if one of its encapsulated AVPs sets the 'M' bit.

This is a bit of a non-statement since if the AVP is unrecognized then its type is unknown. We therefore don't know that its data bytes contain encapsulated AVPs, so can't but ignore any of those that set the M-bit. Doing anything else when the type is known would be inconsistent.

OTP-11087 (R16B03) caused the M-bit on any unrecognized AVP to be regarded as an error, unrecognized being taken to mean "not explicitly defined as a member of its container". (That is, an AVP that can't be packed into a dedicated record field, which is slightly stronger than "not defined".) This fixed the original intention for top-level AVPs but broke the required leniency for Grouped AVPs whose type is known. This leniency is now restored.

Note that dictionary files need to be recompiled for the change to have effect.

Thanks to Rory McKeown for reporting the problem.

Own Id: OTP-11675 Aux Id: OTP-11087

Fix pick_peer case clause failure.

In the case of {call_mutates_state, true} configuration on the service in question, any peer selection that failed to select a peer resulted in a case clause failure. This was noticed in the case of a peer failover in which an alternate peer wasn't available.

Own Id: OTP-11789

diameter 1.5

Improvements and New Features

Rename reconnect_timer to connect_timer.

The former is still accepted for backwards compatibility, but the name is misleading given the semantics of the timer.

Own Id: OTP-11168

Extend diameter_make(3).

Dictionaries can now be compiled from strings, not just filesystem paths, and results can be returned instead of written to the filesystem.

Own Id: OTP-11348

Remove hardcoding of diameter_base as @prefix on dictionaries for application id 0.

Own Id: OTP-11361

diameter 1.4.4

Fixed Bugs and Malfunctions

Fix setting of End-to-End and Hop-by-Hop Identifiers in outgoing DWA.

Broken by OTP-11184, which caused the identifiers to be set anew, discarding the values from the incoming DWR.

Own Id: OTP-11367

Fix handling of 5014, DIAMETER_INVALID_AVP_LENGTH.

The error was detected as 5004, DIAMETER_INVALID_AVP_VALUE, for some Diameter types, in which case an AVP length that pointed past the end of a message resulted in encode failure.

Own Id: OTP-11395

diameter 1.4.3

Fixed Bugs and Malfunctions

Fix UTF8String encode.

Encode now accepts any nested list of codepoints and binaries. A list containing a binary was previously misinterpreted and the documentation was incomplete.

Own Id: OTP-11172

Ensure DWR isn't sent immediately after DWA.

This was possible if the timing was unfortunate. An incoming DWR now properly resets the watchdog timer.

Own Id: OTP-11184

Fix faulty encode of Failed-AVP

Reception of a CER, DWR or DPR that has decode failures caused encode of the corresponding answer message to fail.

Own Id: OTP-11293

Fix broken service_opt() spawn_opt.

The option was ignored.

Own Id: OTP-11299

diameter 1.4.2

Fixed Bugs and Malfunctions

Fix handling of 5014 (INVALID_AVP_LENGTH) errors.

This was in some cases reported as 3009 (INVALID_AVP_BITS).

Note that the correction is partially implemented in modules generated by diameterc(1): a dictionary file must be recompiled for the correction to apply to any messages it defines.

Own Id: OTP-11007

Fix faulty capitalization in release notes.

Diameter = the protocol.
diameter = the Erlang application.

Own Id: OTP-11014

Fix watchdog memory leak.

Entries were not removed from a service-specific ets table, causing them to be orphaned at connection reestablishment for listening transports, and diameter:remove_transport/2 for both listening and connecting transports.

The fault was introduced by OTP-10692 in diameter-1.4.1 (R16B).

Own Id: OTP-11019 Aux Id: OTP-10692

Fix decode failure on AVP Length < 8.

The failure caused the message in question to be discarded.

Own Id: OTP-11026

Respect Host-IP-Address configuration.

Addresses returned from a transport module were always used to populate Host-IP-Address AVP's in an outgoing CER/CEA, which precluded the sending of a VIP address. Transport addresses are now only used if Host-IP-Address is unspecified.

Own Id: OTP-11045

Fix mkdir race.

Install could fail if examples/code and examples/dict were created in parallel. Noticed on FreeBSD.

Own Id: OTP-11051

Fix recognition of 5001 on mandatory AVP's.

An AVP setting the M-bit was not regarded as erroneous if it was defined in the dictionary in question and its container (message or Grouped AVP) had an 'AVP' field. It's now regarded as a 5001 error (AVP_UNSUPPORTED), as in the case that the AVP is not defined.

Note that the correction is partially implemented in modules generated by diameterc(1): a dictionary file must be recompiled for the correction to apply to any messages it defines.

Own Id: OTP-11087

Fix setting of Failed-AVP on handle_request {answer_message, 5xxx} return.

Failed-AVP was never in the outgoing answer-message. It is now set with the AVP from the first entry with the specified Result-Code in the errors field of the incoming diameter_packet, if found.

Own Id: OTP-11092

Fix watchdog function_clause

A listening transport on a service that allowed multiple connections to the same peer could result in a function_clause error in module diameter_watchdog. The resulting crash was harmless but unseemly.

Thanks to Aleksander Nycz.

Own Id: OTP-11115

Fix population of Failed-AVP.

In cases in which diameter populated this AVP, many values were sent instead of one as suggested by RFC 6733. This was partially corrected by OTP-11007.

Own Id: OTP-11127 Aux Id: OTP-11007

Fix list-valued Vendor-Specific-Application-Id config

R16B (specifically, OTP-10760) broke the handling of such configuration, resulting in a function clause error if the list was not of length 3, and faulty interpretation of the list's contents otherwise. Only record-valued configuration was properly interpreted.

Own Id: OTP-11165

Improvements and New Features

Allow peer connections to be shared between Erlang nodes for the purpose of sending outgoing requests.

A diameter_app(3) pick_peer/4 callback gets a list of remote candidates as argument, allowing a callback on one node to select a transport connection established on another node. The service_opt() share_peers controls the extent to which local connections are shared with remote nodes. The service_opt() use_shared_peers controls the extent to which connections shared from remote nodes are utilized on the local node.

Own Id: OTP-9610

Allow listening diameter_{tcp,sctp} transports to be configured with remote addresses.

Option 'accept' allows remote addresses to be configured as tuples or regular expressions. Remote addresses are matched against the configured values at connection establishment, any non-matching address causing the connection to be aborted.

Own Id: OTP-10893

Detect more transport_opt() configuration errors at diameter:add_transport/2.

Many errors would previously not be detected until transport start, diameter:add_transport/2 returning 'ok' but transport connections failing to be established. An error tuple is now returned.

Own Id: OTP-10972

Make explicit local address configuration optional in diameter_tcp:start/3.

The default address (as determined by gen_tcp) is now used when a local address is not explicitly configured.

Own Id: OTP-10986

Improve handling of unrecognized service options.

Such options were silently ignored by diameter:start_service/2. An error tuple is now returned.

Own Id: OTP-11017

Don't send default Inband-Security-Id in CER/CEA.

RFC 6733 recommends against the use of Inband-Security-Id. Only send a value that differs from the default, NO_INBAND_SECURITY = 0.

Own Id: OTP-11050

Make spawn options for request processes configurable.

Own Id: OTP-11060

diameter 1.4.1.1

Fixed Bugs and Malfunctions

Fix broken Vendor-Specific-Application-Id configuration.

RFC 6733 changed the definition of this Grouped AVP, changing the arity of Vendor-Id from 1* to 1. A component Vendor-Id can now be either list- or integer-valued in service and transport configuration, allowing it to be used with both RFC 3588 and RFC 6733 dictionaries.

Own Id: OTP-10942

Improvements and New Features

Add transport_opt() watchdog_config to allow non-standard behaviour of the watchdog state machine.

This can be useful during test but should not be used on nodes that must conform to RFC 3539.

Own Id: OTP-10898

diameter 1.4.1

Fixed Bugs and Malfunctions

Fix erroneous watchdog transition from DOWN to INITIAL.

This transition took place when a peer connection was reestablished following a failed capabilities exchange. RFC 3539 requires DOWN to transition into REOPEN.

Own Id: OTP-10692

Improvements and New Features

Add application_opt() request_errors to make the handling of incoming requests containing decode errors configurable.

The value 'callback' ensures that a handle_request callback takes place for all such requests, the default being for diameter to answer 3xxx series errors itself.

Own Id: OTP-10686

Add transport_opt() length_errors.

The value determines how messages received over the transport interface with an incorrect Message Length are dealt with.

Own Id: OTP-10687

Add commentary on RFC 6733 to Standards Compliance chapter of the User's Guide.

Own Id: OTP-10688

Allow a 5xxx result code in an answer-message on peer connections using the RFC 6733 common dictionary.

RFC 6733 allows this while RFC 3588 does not. A handle_request callback can return {answer_message, 3000..3999|5000..5999} in the simplest case.

Own Id: OTP-10759

Add dictionaries for RFC 6733.

Both the common and accounting dictionaries differ from their RFC 3588 counterparts, which is reflected in generated record definitions. Application configuration on a service or transport determines the dictionary that will be used on a given peer connection.

Own Id: OTP-10760

Allow a handle_request callback to control diameter's setting of Result-Code and Failed-AVP.

Setting errors = false in a returned #diameter_packet{} disables the setting.

Own Id: OTP-10761

diameter 1.4

Fixed Bugs and Malfunctions

Add registered server names to the app file.

Own Id: OTP-10442

Fix #diameter_header{} handling broken by OTP-10445.

The fault caused the the header of a [Header | Avps] request to be ignored if both end_to_end_id and hop_by_hop_id were undefined.

Own Id: OTP-10609

Fix error handling for handle_request callback.

A callback that returned a #diameter_packet{} would fail if the incoming request had decode errors.

Own Id: OTP-10614

Fix timing of service start event.

The event did not necessarily precede other events as documented.

Own Id: OTP-10618

Fix setting of header T flag at peer failover.

The flag is now set in the diameter_header record passed to a prepare_retransmit callback.

Own Id: OTP-10619

Fix sending of CER/CEA timeout event at capx_timeout.

The event was not sent as documented.

Own Id: OTP-10628

Fix improper setting of Application-ID in the Diameter header of an answer message whose E flag is set.

The value should be that of the request in question. The fault caused it always to be 0.

Own Id: OTP-10655

Fix faulty handling of AVP length errors.

An incorrect AVP length but no other errors caused an incoming request to fail.

Own Id: OTP-10693

diameter 1.3.1

Known Bugs and Problems

Fix function clause resulting from use of an eval callback.

Own Id: OTP-10685

diameter 1.3

Fixed Bugs and Malfunctions

Fix faulty handling of Origin-State-Id and faulty config values.

The former was expected in a list despite the documentation requiring (correctly) an integer. A bare value for a list-valued capability was not handled.

Own Id: OTP-10440

Fix timing of up/down events.

Previously, a call to diameter:call/4 following a peer_up callback might incorrectly return {error, no_connection}, depending on timing. Both events now follow the corresponding callbacks.

Own Id: OTP-10459

Make diameter:service_info/2 usable in peer_up, peer_down and pick_peer callbacks.

Except for in pick_peer when {call_mutates_state, false}, it would previously hang indefinitely.

Own Id: OTP-10460

Verify that End-to-End and Hop-by-Hop Identifiers in an incoming CEA/DPA match those sent in the corresponding CER/DPR.

The values were previously ignored. Answers whose identifiers do not match are handled as unexpected.

Own Id: OTP-10565

Fix formatting problems in PDF documentation.

In particular, text corresponding to links in HTML was omitted in preformatted blocks. There are still issues with indentation but this is not diameter-specific.

Own Id: OTP-10583

Improvements and New Features

Let prepare_request, prepare_retransmit and handle_request callbacks return a function to be invoked on outgoing messages after encode.

This allows encoded messages to be logged for example.

Own Id: OTP-10441

Add service_opt() 'restrict_connections' to allow multiple transport connections with the same peer.

Own Id: OTP-10443

Add service_opt() 'sequence' to allow the masking of a constant onto the topmost bits of End-to-End and Hop-by-Hop identifiers.

This allows the same service on different nodes to use distinct values in outgoing request messages.

Own Id: OTP-10445

Add diameter:service_info(PeerRef) to return the transport_ref() and transport_opt() list of the corresponding transport.

This allows easy access to these from diameter_app callbacks that only get peer_ref() as an argument.

Own Id: OTP-10470

Add reference pages diameter_codec(3) and diameter_make(3).

Own Id: OTP-10471

Add events for service start and stop.

Own Id: OTP-10492

Add transport_opt() 'disconnect_cb' to make the sending of DPR configurable.

Whether or not DPR should be sent at application stop, service stop or transport removal is determined by the value returned by the callback, as is the Disconnect-Cause and timeout if DPA is not received.

Own Id: OTP-10493

Add transport_opt() 'capx_timeout' for the timeout associated with non-reception of CER/CEA.

Own Id: OTP-10554

Allow a handle_request callback to return a #diameter_packet{}.

This allows an answer to set transport_data and header fields.

Own Id: OTP-10566

Update documentation for RFC 6733.

RFC 3588 is now obsolete.

Own Id: OTP-10568

diameter 1.2

Fixed Bugs and Malfunctions

Fix broken Result-Code setting and Destination-Host/Realm extraction.

Result-Code was assumed to have arity 1 when setting this value in an answer to a request containing AVP decode errors. Destination-Host/Realm were only correctly extracted from messages in the common application.

Own Id: OTP-10202

Handle insufficient capabilities configuration more gracefully.

A transport that does not have sufficient capabilities configuration in order to encode CER/CEA will now emit an error report noting the configuration error and exit instead of failing. The error is not detected at diameter:add_transport/2 since there is no requirement that a service be configured before its transports.

Own Id: OTP-10203

Ensure a failing peer_up/down callback does not affect transport connections to other peers.

Such a failure would previously have taken down all of a service's connections.

Own Id: OTP-10215

Improvements and New Features

Statistics related to Diameter messages can be retrieved using diameter:service_info/2.

Both Diameter and socket-level statistics are available, for both incoming and outgoing messages.

Own Id: OTP-9608

Allow multiple transport_module/config to diameter:add_transport/2.

Multiple values are attempted in sequence until one results in an established connection. This provides a way for a connecting transport to specify configuration in order of preference. (For example, SCTP before TCP.)

Own Id: OTP-9885

Add events for state transitions in the RFC 3539 watchdog state machine.

The watchdog state is also available through diameter:service_info/2.

Own Id: OTP-10212

Add diameter:service_info(SvcName, connections).

This provides an alternative to diameter:service_info(SvcName, transport) that presents information per established connection instead of per transport reference.

Own Id: OTP-10213

Assorted documentation corrections/improvements.

Own Id: OTP-10216

diameter 1.1

Fixed Bugs and Malfunctions

Fix fault in sending of 'closed' events.

The fault made it possible for the 'closed' event not to be sent following a failed capabilities exchange.

Own Id: OTP-9824

Fix faulty diameterc -name/-prefix.

A minor blunder when introducing the new dictionary parser in diameter-1.0 broke these options.

Own Id: OTP-9826

diameter 1.0

Fixed Bugs and Malfunctions

Fix faulty cleanup after diameter:remove_transport/2.

Removing a transport removed the configuration but did not prevent the transport process from being restarted.

Own Id: OTP-9756

Improvements and New Features

Add support for TLS over TCP.

RFC 3588 requires that a Diameter server support TLS. In practice this seems to mean TLS over SCTP since there are limitations with running over SCTP: see RFC 6083 (DTLS over SCTP), which is a response to RFC 3436 (TLS over SCTP). The current RFC 3588 draft acknowledges this by equating TLS with TLS/TCP and DTLS/SCTP.

TLS handshaking can take place either following a CER/CEA that negotiates TLS using the Inband-Security-Id AVP (the method documented in RFC 3588) or immediately following connection establishment (the method added to the current draft).

Own Id: OTP-9605

Improvements to the dictionary parser.

The dictionary parser now emits useful error messages in case of faults in the input file, also identifying the line number at which the fault was detected. There are semantic checks that were missing in the previous parser, a fault in the interpretation of vendor id's in combination with @inherits has been fixed and @end can be used to terminate parsing explicitly instead of always parsing to end of file.

Own Id: OTP-9639

Improve dictionary reusability.

Reusing a dictionary just to get a different generated module name or prefix previously required taking a copy of the source, which may consist of several files if inheritance is used, just to edit a couple of lines which don't affect the semantics of the Diameter application being defined. Options --name, --prefix and --inherits have been added to diameterc to allow corresponding values to be set at compile time.

Own Id: OTP-9641

Add capabilities_cb transport option.

Its value is a function that's applied to the transport reference and capabilities record after capabilities exchange. If a callback returns anything but 'ok' then the connection is closed. In the case of an incoming CER, the callback can return a result code with which to answer. Multiple callbacks can be specified and are applied until either all return 'ok' or one doesn't.

This provides a way to reject a peer connection.

Own Id: OTP-9654

Add @codecs to dictionary format.

The semantics are similar to @custom_types but results in codec functions of the form TypeName(encode|decode, AvpName, Data) rather than AvpName(encode|decode, TypeName, Data). That is, the role of the AVP name and Diameter type name are reversed. This eliminates the need for exporting one function for each AVP sharing a common specialized encode/decode.

Own Id: OTP-9708 Aux Id: OTP-9639

Add #diameter_callback{} for more flexible callback configuration.

The record allows individual functions to be configured for each of the diameter_app(3) callbacks, as well as a default callback.

Own Id: OTP-9777

diameter 0.10

Fixed Bugs and Malfunctions

Handle #sctp_paddr_change and #sctp_pdapi_event from gen_sctp.

The events are enabled by default but diameter_sctp neither disabled nor dealt with them. Reception of such an event caused a transport process to crash.

Own Id: OTP-9538

Fix header folding bug.

A prepare_request callback from diameter can return a diameter_header record in order to set values in the header of an outgoing request. A fault in diameter_lib:fold_tuple/3 caused the subsequent encode of the outgoing request to fail.

Own Id: OTP-9577

Fix bugs in sending of answer-message replies.

3001 (DIAMETER_COMMAND_UNSUPPORTED) was not sent since the decode placed the AVP list in the wrong field of the diameter_packet, causing the subsequent encode to fail. Session-Id was also set improperly, causing encode to fail even in this case.

Own Id: OTP-9578

Fix improper use of error_logger:info_report/2.

Function doesn't take a format string and arguments as it was called. Instead use error_logger:info_report/1 and use the same report format as used for warning and error reports.

Own Id: OTP-9579

Fix and clarify semantics of peer filters.

An eval filter returning a non-true value caused the call process to fail and the doc was vague on how an exception was treated. Clarify that the non-tuple host/realm filters assume messages of a certain form.

Own Id: OTP-9580

Fix and clarify relay behaviour.

Implicit filtering of the sending peer in relaying a request could cause loop detection to be preempted in a manner not specified by RFC3588. Reply with 3002 (DIAMETER_UNABLE_TO_DELIVER) on anything but an answer to a relayed request.

Own Id: OTP-9583

Improvements and New Features

@id required in dictionary files only when @messages is specified.

@id defines an application identifier and this is used only when sending or receiving messages. A dictionary can define only AVP's however, to be included by other dictionaries using @inherits, in which case it makes no sense to require @id.

Note that message definitions are not inherited with @inherits, only AVP's

Own Id: OTP-9467

Allow @enum when AVP is defined in an inherited dictionary.

3GPP standards (for one) extend the values allowed for RFC 3588 AVP's of type Enumerated. Previously, extending an AVP was only possible by completely redefining the AVP.

Own Id: OTP-9469

Migrate testsuites to pure common test and add both suites and testcases.

Own Id: OTP-9553

Requests of arbitrary form.

diameter:call/4 can be passed anything, as long as the subsequent prepare_request callback returns a term that can be encoded.

Own Id: OTP-9581

diameter 0.9

Initial release of the diameter application.

Known issues or limitations:

Some agent-related functionality is not entirely complete. In particular, support for proxy agents, that advertise specific Diameter applications but otherwise relay messages in much the same way as relay agents (for which a handle_request callback can return a relay tuple), will be completed in an upcoming release. There may also be more explicit support for redirect agents, although redirect behaviour can be implemented with the current functionality.

There is some asymmetry in the treatment of messages sent as diameter_header/avp records and those sent in the "normal" fashion, and not all of this is documented. This is related to the previous point since this form of sending a message was introduced specifically to handle relay agent behaviour using the same callback interface as for client/server behaviour.

The User's Guide is currently quite thin. The introductory chapter followed by the examples (in the application examples subdirectory) may be sufficient for those having some familiarity with the Diameter protocol but the intention is to provide more introductory text. The reference documentation is quite complete, although some points could likely be expanded upon.

The function diameter:service_info/2 can be used to retrieve information about a started service (statistics, information about connected peers, etc) but this is not yet documented and both the input and output may change in the next release.

See Standards Compliance for standards-related issues.

Introduction

The diameter application is an implementation of the Diameter protocol as defined by RFC 6733. It supports arbitrary Diameter applications by way of a dictionary interface that allows messages and AVPs to be defined and input into diameter as configuration. It has support for all roles defined in the RFC: client, server and agent. This chapter provides a short overview of the application.

A Diameter node is implemented by configuring a service and one or more transports using the interface module diameter. The service configuration defines the Diameter applications to be supported by the node and, typically, the capabilities that it should send to remote peers at capabilities exchange upon the establishment of transport connections. A transport is configured on a service and provides protocol-specific send/receive functionality by way of a transport interface defined by diameter and implemented by a transport module. The diameter application provides two transport modules: diameter_tcp and diameter_sctp for transport over TCP (using gen_tcp) and SCTP (using gen_sctp) respectively. Other transports can be provided by any module that implements diameter's transport interface.

While a service typically implements a single Diameter node (as identified by an Origin-Host AVP), transports can themselves be associated with capabilities AVPs so that a single service can be used to implement more than one Diameter node.

Each Diameter application defined on a service is configured with a callback module that implements the application interface through which diameter communicates the connectivity of remote peers, requests peer selection for outgoing requests, and communicates the reception of incoming Diameter request and answer messages. An application using diameter implements these application callback modules to provide the functionality of the Diameter node(s) it implements.

Each Diameter application is also configured with a dictionary module that provide encode/decode functionality for outgoing/incoming Diameter messages belonging to the application. A dictionary module is generated from a dictionary file using the diameterc utility. Dictionaries for the RFC 6733 Diameter Common Messages, Base Accounting and Relay applications are provided with the diameter application.

Usage

To be written.

Examples

Example code can be found in the diameter application's examples subdirectory.

Standards Compliance

The table below summarizes the diameter application's compliance with RFC 6733. Since the diameter application isn't a Diameter node on its own, compliance is strictly the responsibility of the user in many cases, diameter providing the means for the user to be compliant rather than being compliant on its own.

The Compliance column notes C (Compliant) if the required functionality is implemented, PC (Partially Compliant) if there are limitations, NC (Not Compliant) if functionality is not implemented, or a dash if text is informational or only places requirements that must be met by the user's implementation.

Capitalized Diameter refers to the protocol, lowercase diameter to the Erlang application.

RFC 6733 - Diameter Base Protocol

Section | Title | Compliance | Notes
1 | Introduction | — |
1.1 | Diameter Protocol | — |
1.1.1 | Description of the Document Set | — |
1.1.2 | Conventions Used in This Document | — |
1.1.3 | Changes from RFC 3588 | — | It is possible to configure a 3588 dictionary in order to get 3588 semantics, where the differ from 6733.
1.2 | Terminology | — |

1.3
Approach to Extensibility
—
The dictionary interface documented in diameter_dict(4) provides extensibility, allowing the user to defined new AVPs, commands, and applications. Ready dictionaries are provided for the RFC 6733 common message, base accounting, and relay applications, as well as for RFC 7683, Diameter Overload Indicator Conveyance.

1.3.1 | Defining New AVP Values | — |
1.3.2 | Creating New AVPs | — | New AVPs can be defined using the dictionary interface. Both RFC data formats and extensions are supported.
1.3.3 | Creating New Commands | — | New commands can be defined using the dictionary interface.
1.3.4 | Creating New Diameter Applications | — | New applications can be defined using the dictionary interface.
2 | Protocol Overview | — | Session state is the responsibility of the user.   The role of a Diameter node is determined by the user's implementation.

2.1
Transport
PC
Ports are configured by the user: diameter places no restrictions.   The transport interface documented in diameter_transport allows the user to implement their own methods. Ready support is provided for TCP, TCP/TLS, and SCTP, but not DTLS/SCTP.   Multiple connections to the same peer is possible. ICMP messages are not interpreted.

2.1.1 | SCTP Guidelines | C | Unordered sending is configurable in diameter_sctp. There is no special handling of DPR/DPA: since a user that cares about pending answers should wait for them before initiating DPR.   A PPID can be configured with a a gen_sctp sctp_default_send_param option.
2.2 | Securing Diameter Messages | PC | DTLS is not supported by diameter_sctp. See also 2.1.
2.3 | Diameter Application Compliance | — |
2.4 | Application Identifiers | C | The user configures diameter with the identifiers to send at capabilities exchange, along with corresponding dictionaries defining the messages of the applications.
2.5 | Connections vs. Sessions | C | Connections are realized by configuring transport. Sessions are the responsibility of the user.
2.6 | Peer Table | PC | Routing is implemented by the user in callbacks documented in diameter_app. A peer table of the documented form is not exposed to the user.
2.7 | Routing Table | PC | See 2.6. A routing table of the documented form is not exposed to the user.
2.8 | Role of Diameter Agents | C | Most role-specific behaviour is implemented by the user. How a node advertises itself at capabilities exchange is determined by user configuration.
2.8.1 | Relay Agents | C |
2.8.2 | Proxy Agents | C |
2.8.3 | Redirect Agents | C |
2.8.4 | Translation Agents | C |
2.9 | Diameter Path Authorization | — | Authorization is the responsibility of the user.
3 | Diameter Header | C | Hop-by-Hop and End-to-End Identifiers are set by diameter when sending outgoing requests.
3.1 | Command Codes | C |
3.2 | Command Code Format Specification | C | Commands are defined as CCF specifications in dictionary files.
3.3 | Diameter Command Naming Conventions | — |
4 | Diameter AVPs | C | Any required padding is added by diameter when encoding outgoing messages.
4.1 | AVP Header | C |
4.1.1 | Optional Header Elements | C |
4.2 | Basic AVP Data Formats | C |
4.3 | Derived AVP Data Formats | C | Arbitrary derived data formats are supported by the dictionary interface.
4.3.1 | Common Derived AVP Data Formats | C | Beware that RFC 6733 changed the DiameterURI transport/port defaults specified in RFC3588. Relying on the defaults can result in interoperability problems.
4.4 | Grouped AVP Values | C | The M-bit on a component AVP of a Grouped AVP that does not set M is ignored: such AVPs are not regarded as erroneous at decode.   Grouped AVPs are defined as CCF specifications in dictionary files.
4.4.1 | Example AVP with a Grouped Data Type | — |
4.5 | Diameter Base Protocol AVPs | C | The base AVPs are defined in the common dictionary provided by diameter. There are common dictionaries for both RFC 3588 and RFC 6733 since the latter made changes to both syntax and semantics.
5 | Diameter Peers | — |

5.1
Peer Connections
PC
A peer's DiameterIdentity is not required when initiating a connection: the identify is received at capabilities exchange, at which time the connection can be rejected if the identity is objectionable.   The number of connections established depends on the user's configuration. Multiple connections per peer is possible.

5.2 | Diameter Peer Discovery | NC | No form of peer discovery is implemented. The user can implement this independently of diameter if required.
5.3 | Capabilities Exchange | C | All supported applications are sent in CEA. The user can reject an incoming CER or CEA in a configured callback.   Both transport security at connection establishment and negotiated via an Inband-Security AVP are supported.
5.3.1 | Capabilities-Exchange-Request | C | CER is sent and received by diameter.
5.3.2 | Capabilities-Exchange-Answer | C | CEA is sent and received by diameter.
5.3.3 | Vendor-Id AVP | C |
5.3.4 | Firmware-Revision AVP | C |
5.3.5 | Host-IP-Address AVP | C |
5.3.6 | Supported-Vendor-Id AVP | C |
5.3.7 | Product-Name AVP | C |
5.4 | Disconnecting Peer Connections | C | DPA will not be answered with error: a peer that wants to a avoid a race can wait for pending answers before sending DPR.
5.4.1 | Disconnect-Peer-Request | C | DPR is sent by diameter in response to configuration changes requiring a connection to be broken. The user can also send DPR.
5.4.2 | Disconnect-Peer-Answer | C | DPR is answered by diameter.
5.4.3 | Disconnect-Cause AVP | C |
5.5 | Transport Failure Detection | — |
5.5.1 | Device-Watchdog-Request | C | DWR is sent and received by diameter. Callbacks notify the user of transitions into and out of the OKAY state.
5.5.2 | Device-Watchdog-Answer | C | DWA is sent and received by diameter.
5.5.3 | Transport Failure Algorithm | C |
5.5.4 | Failover and Failback Procedures | C |
5.6 | Peer State Machine | PC | The election process is modified as described in 5.6.4.
5.6.1 | Incoming Connections | C |
5.6.2 | Events | — |
5.6.3 | Actions | — |

5.6.4
The Election Process
PC
As documented, the election assumes knowledge of a peer's DiameterIdentity when initiating a connection, which diameter doesn't require. Connections will be accepted if configuration allows multiple connections per peer to be established or there is no existing connection. Note that the election process is only applicable when multiple connections per peer is disallowed.

6 | Diameter Message Processing | — |
6.1 | Diameter Request Routing Overview | — | Routing is performed by the user. A callback from diameter provides a list of available suitable peer connections.
6.1.1 | Originating a Request | C | Requests are constructed by the user; diameter sets header fields as defined in the relevant dictionary.
6.1.2 | Sending a Request | C |
6.1.3 | Receiving Requests | C | Loops are detected by diameter when the return value of a request callback asks that a request be forwarded. Loop detection in other cases is the responsibility of the user.
6.1.4 | Processing Local Requests | C | The user decides whether or not to process a request locally in the request callback from diameter.
6.1.5 | Request Forwarding | PC | See 2.6.
6.1.6 | Request Routing | PC | See 2.7.
6.1.7 | Predictive Loop Avoidance | C | See 6.1.3.
6.1.8 | Redirecting Requests | PC | See 2.6.
6.1.9 | Relaying and Proxying Requests | C | A Route-Record AVP is appended by diameter when the return value of a request callback asks that a request be forwarded. Appending the AVP in other cases is the responsibility of the user.
6.2 | Diameter Answer Processing | C | Answer message are constructed by the user, except in the case of some protocol errors, in which case the procedures are followed.
6.2.1 | Processing Received Answers | C | Answers with an unknown Hop-by-Hop Identifier are discarded.
6.2.2 | Relaying and Proxying Answers | — | Modifying answers is the responsibility of the user in callbacks from diameter.
6.3 | Origin-Host AVP | C | The order of AVPs in an encoded message is determined by the CCF of the message in question.   AVPs defined in the RFC are defined in dictionaries provided by diameter. Their proper use in application messages is the responsibility of the user.
6.4 | Origin-Realm AVP | C |
6.5 | Destination-Host AVP | C |
6.6 | Destination-Realm AVP | C |
6.7 | Routing AVPs | — |
6.7.1 | Route-Record AVP | C |
6.7.2 | Proxy-Info AVP | C |
6.7.3 | Proxy-Host AVP | C |
6.7.4 | Proxy-State AVP | C |
6.8 | Auth-Application-Id AVP | C |
6.9 | Acct-Application-Id AVP | C |
6.10 | Inband-Security-Id AVP | C | See 2.1.
6.11 | Vendor-Specific-Application-Id AVP | C | Note that the CCF of this AVP is not the same as in RFC 3588.
6.12 | Redirect-Host AVP | C |
6.13 | Redirect-Host-Usage AVP | C |
6.14 | Redirect-Max-Cache-Time AVP | C |
7 | Error Handling | C | Answers are formulated by the user in most cases. Answers setting the E-bit can be sent by diameter itself in response to a request that cannot be handled by the user.
7.1 | Result-Code AVP | C |
7.1.1 | Informational | C |
7.1.2 | Success | C |
7.1.3 | Protocol Errors | C | Result codes 3001, 3002, 3005, and 3007 can be sent in answers formulated by diameter, if configured to do so.
7.1.4 | Transient Failures | C | Result code 4003 is sent in CEA if there is an existing connection to the peer in question and configuration does not allow more than one.

7.1.5
Permanent Failures
C
Message reception detects 5001, 5004, 5005, 5008, 5009, 5010, 5011, 5014, 5015, and 5017 errors. It ignores 5013 errors at the admonition of sections 3 and 4.1.   Note that RFC 3588 did not allow 5xxx result codes in answers setting the E-bit, while RFC 6733 does. This is a potential interoperability problem since the Diameter protocol version has not changed.

7.2 | Error Bit | C |
7.3 | Error-Message AVP | C | The user can include this AVP as required.
7.4 | Error-Reporting-Host AVP | C | The user can include this AVP as required.
7.5 | Failed-AVP AVP | C | The user constructs application-specific messages, but diameter provides failed AVPs in message callbacks. Failed component AVPs are grouped within the relevant Grouped AVPs.
7.6 | Experimental-Result AVP | C |
7.7 | Experimental-Result-Code AVP | C |
8 | Diameter User Sessions | — | Authorization and accounting AVPs are defined in provided dictionaries. Their proper use is the responsibility of the user.
8.1 | Authorization Session State Machine | — | Authorization is the responsibility of the user: diameter does not implement this state machine.
8.2 | Accounting Session State Machine | — | Accounting is the responsibility of the user: diameter does not implement this state machine.
8.3 | Server-Initiated Re-Auth | — |
8.3.1 | Re-Auth-Request | C |
8.3.2 | Re-Auth-Answer | C |
8.4 | Session Termination | — | Session-related messages and AVPs are defined in provided dictionaries. Their proper use is the user's responsibility.
8.4.1 | Session-Termination-Request | C |
8.4.2 | Session-Termination-Answer | C |
8.5 | Aborting a Session | — | Session-related messages and AVPs are defined in provided dictionaries. Their proper use is the user's responsibility.
8.5.1 | Abort-Session-Request | C |
8.5.2 | Abort-Session-Answer | C |
8.6 | Inferring Session Termination from Origin-State-Id | — | Session-related messages and AVPs are defined in provided dictionaries. Their proper use is the user's responsibility.
8.7 | Auth-Request-Type AVP | C |
8.8 | Session-Id AVP | C |
8.9 | Authorization-Lifetime AVP | C |
8.10 | Auth-Grace-Period AVP | C |
8.11 | Auth-Session-State AVP | C |
8.12 | Re-Auth-Request-Type AVP | C |
8.13 | Session-Timeout AVP | C |
8.14 | User-Name AVP | C |
8.15 | Termination-Cause AVP | C |
8.16 | Origin-State-Id AVP | C |
8.17 | Session-Binding AVP | C |
8.18 | Session-Server-Failover AVP | C |
8.19 | Multi-Round-Time-Out AVP | C |
8.20 | Class AVP | C |
8.21 | Event-Timestamp AVP | C |
9 | Accounting | — | Accounting-related messages and AVPs are defined in provided dictionaries. Their proper use is the user's responsibility.
9.1 | Server Directed Model | — |
9.2 | Protocol Messages | — |
9.3 | Accounting Application Extension and Requirements | — |
9.4 | Fault Resilience | — |
9.5 | Accounting Records | — |
9.6 | Correlation of Accounting Records | — |
9.7 | Accounting Command Codes | — |
9.7.1 | Accounting-Request | C |
9.7.2 | Accounting-Answer | C |
9.8 | Accounting AVPs | — |
9.8.1 | Accounting-Record-Type AVP | C |
9.8.2 | Acct-Interim-Interval AVP | C |
9.8.3 | Accounting-Record-Number AVP | C |
9.8.4 | Acct-Session-Id AVP | C |
9.8.5 | Acct-Multi-Session-Id AVP | C |
9.8.6 | Accounting-Sub-Session-Id AVP | C |
9.8.7 | Accounting-Realtime-Required AVP | C |
10 | AVP Occurrence Tables | — |
10.1 | Base Protocol Command AVP Table | — |
10.2 | Accounting AVP Table | — |
11 | IANA Considerations | — |
11.1 | AVP Header | — |
11.1.1 | AVP Codes | — |
11.1.2 | AVP Flags | — |
11.2 | Diameter Header | — |
11.2.1 | Command Codes | — |
11.2.2 | Command Flags |  |
11.3 | AVP Values | — |
11.3.1 | Experimental-Result-Code AVP | — |
11.3.2 | Result-Code AVP Values | — |
11.3.3 | Accounting-Record-Type AVP Values | — |
11.3.4 | Termination-Cause AVP Values | — |
11.3.5 | Redirect-Host-Usage AVP Values | — |
11.3.6 | Session-Server-Failover AVP Values | — |
11.3.7 | Session-Binding AVP Values | — |
11.3.8 | Disconnect-Cause AVP Values | — |
11.3.9 | Auth-Request-Type AVP Values | — |
11.3.10 | Auth-Session-State AVP Values | — |
11.3.11 | Re-Auth-Request-Type AVP Values | — |
11.3.12 | Accounting-Realtime-Required AVP Values | — |
11.3.13 | Inband-Security-Id AVP (code 299) | — |
11.4 | _diameters Service Name and Port Number Registration | — |
11.5 | SCTP Payload Protocol Identifiers | — |
11.6 | S-NAPTR Parameters | — |
12 | Diameter Protocol-Related Configurable Parameters | — |
13 | Security Considerations | PC | See 2.1.   IPsec is transparent to diameter.
13.1 | TLS/TCP and DTLS/SCTP Usage | PC | See 2.1.
13.2 | Peer-to-Peer Considerations | — |
13.3 | AVP Considerations | — |
14 | References | — |
14.1 | Normative References | — |
14.2 | Informative References | — |

Table: RFC 6733 Compliance

diameterc

Compile a diameter dictionary to Erlang source.

Synopsis

diameterc [<options>] <file>

Description

The diameterc utility is used to compile a diameter dictionary file into Erlang source. The resulting source implements the interface diameter required to encode and decode the dictionary's messages and AVPs.

The module diameter_make provides an alternate compilation interface.

USAGE

Compile a single dictionary file to Erlang source. Valid options are as follows.

-i <dir> - Prepend the specified directory to the code path. Use to point at beam files compiled from inherited dictionaries, @inherits in a dictionary file creating a beam dependency, not an erl/hrl dependency.

Multiple -i options can be specified.

-o <dir> - Write generated source to the specified directory. Defaults to the current working directory.

-E - Suppress .erl file generation.

-H - Suppress .hrl file generation.

--name <name> - Name the output module.

--prefix <prefix> - Transform the input dictionary before compilation, setting @name or @prefix to the specified string.

--inherits <arg> - Transform the input dictionary before compilation, appending @inherits of the specified string.

Two forms of --inherits have special meaning:

--inherits -
--inherits Prev/Mod

The first has the effect of clearing any previous inherits, the second of replacing a previous inherits of Prev to one of Mod. This allows the semantics of the input dictionary to be changed without modifying the file itself.

Multiple --inherits options can be specified.

--indirect-inherits - Enables indirect inherits feature, see more here.

EXIT STATUS

Returns 0 on success, non-zero on failure.

SEE ALSO

diameter_make, diameter_dict(4)

diameter_dict

Dictionary interface of the diameter application.

Description

A diameter service, as configured with diameter:start_service/2, specifies one or more supported Diameter applications. Each Diameter application specifies a dictionary module that knows how to encode and decode its messages and AVPs. The dictionary module is in turn generated from a file that defines these messages and AVPs. The format of such a file is defined in FILE FORMAT below. Users add support for their specific applications by creating dictionary files, compiling them to Erlang modules using either diameterc(1) or diameter_make and configuring the resulting dictionaries modules on a service.

Dictionary module generation also results in a hrl file that defines records for the messages and Grouped AVPs defined by the dictionary, these records being what a user of the diameter application sends and receives, modulo other possible formats as discussed in diameter_app. These records and the underlying Erlang data types corresponding to Diameter data formats are discussed in MESSAGE RECORDS and DATA TYPES respectively. The generated hrl also contains macro definitions for the possible values of AVPs of type Enumerated.

The diameter application includes five dictionary modules corresponding to applications defined in section 2.4 of RFC 6733: diameter_gen_base_rfc3588 and diameter_gen_base_rfc6733 for the Diameter Common Messages application with application identifier 0, diameter_gen_accounting (for RFC 3588) and diameter_gen_acct_rfc6733 for the Diameter Base Accounting application with application identifier 3 and diameter_gen_relay the Relay application with application identifier 0xFFFFFFFF.

The Common Message and Relay applications are the only applications that diameter itself has any specific knowledge of. The Common Message application is used for messages that diameter itself handles: CER/CEA, DWR/DWA and DPR/DPA. The Relay application is given special treatment with regard to encode/decode since the messages and AVPs it handles are not specifically defined.

FILE FORMAT

A dictionary file consists of distinct sections. Each section starts with a tag followed by zero or more arguments and ends at the the start of the next section or end of file. Tags consist of an ampersand character followed by a keyword and are separated from their arguments by whitespace. Whitespace separates individual tokens but is otherwise insignificant.

The tags, their arguments and the contents of each corresponding section are as follows. Each section can occur multiple times unless otherwise specified. The order in which sections are specified is unimportant.

@id Number - Defines the integer Number as the Diameter Application Id of the application in question. Can occur at most once and is required if the dictionary defines @messages. The section has empty content.

The Application Id is set in the Diameter Header of outgoing messages of the application, and the value in the header of an incoming message is used to identify the relevant dictionary module.

Example:

@id 16777231

@name Mod - Defines the name of the generated dictionary module. Can occur at most once and defaults to the name of the dictionary file minus any extension. The section has empty content.

Note that a dictionary module should have a unique name so as not collide with existing modules in the system.

Example:

@name etsi_e2

@prefix Name - Defines Name as the prefix to be added to record and constant names (followed by a '_' character) in the generated dictionary module and hrl. Can occur at most once. The section has empty content.

A prefix is optional but can be be used to disambiguate between record and constant names resulting from similarly named messages and AVPs in different Diameter applications.

Example:

@prefix etsi_e2

@vendor Number Name - Defines the integer Number as the the default Vendor-Id of AVPs for which the V flag is set. Name documents the owner of the application but is otherwise unused. Can occur at most once and is required if an AVP sets the V flag and is not otherwise assigned a Vendor-Id. The section has empty content.

Example:

@vendor 13019 ETSI

@avp_vendor_id Number - Defines the integer Number as the Vendor-Id of the AVPs listed in the section content, overriding the @vendor default. The section content consists of AVP names.

Example:

@avp_vendor_id 2937

WWW-Auth
Domain-Index
Region-Set

@inherits Mod - Defines the name of a dictionary module containing AVP definitions that should be imported into the current dictionary. The section content consists of the names of those AVPs whose definitions should be imported from the dictionary, an empty list causing all to be imported. Any listed AVPs must not be defined in the current dictionary and it is an error to inherit the same AVP from more than one dictionary.

Note that an inherited AVP that sets the V flag takes its Vendor-Id from either @avp_vendor_id in the inheriting dictionary or @vendor in the inherited dictionary. In particular, @avp_vendor_id in the inherited dictionary is ignored. Inheriting from a dictionary that specifies the required @vendor is equivalent to using @avp_vendor_id with a copy of the dictionary's definitions but the former makes for easier reuse.

All dictionaries should typically inherit RFC 6733 AVPs from diameter_gen_base_rfc6733.

Example:

@inherits diameter_gen_base_rfc6733

When using the indirect_inherits option from codec/2, only @vendor from the dictionary that defined the AVPs and @avp_vendor_id in the currently compiled dictionary is used. All other dictionaries along the chain are ignored, so for example:

a.dia:

@vendor 1 A
@avp_types
    AAA 111 Unsigned32 V
    BBB 222 Unsigned32 V

a.dia will see:

AAA vendor_id = 1

BBB vendor_id = 1

b.dia:

@vendor 2 B
@avp_types
    CCC 333 Unsigned32 V
@inherits diameter_a
@avp_vendor_id 4
    AAA

b.dia will see:

AAA vendor_id = 4

BBB vendor_id = 1

CCC vendor_id = 2

c.dia:

@vendor 3 C
@avp_types
    DDD 444 Unsigned32 V
@inherits diameter_b
@avp_vendor_id 5
    BBB
    CCC

c.dia will see:

AAA vendor_id = 1

BBB vendor_id = 5

CCC vendor_id = 5

DDD vendor_id = 3

In particular b.dia's override of AAA to vendor_id = 4 is ignored by c.dia and AAA is back to having vendor_id = 1.

@avp_types - Defines the name, code, type and flags of individual AVPs. The section consists of definitions of the form

Name Code Type Flags

where Code is the integer AVP code, Type identifies an AVP Data Format as defined in section DATA TYPES below, and Flags is a string of V, M and P characters indicating the flags to be set on an outgoing AVP or a single '-' (minus) character if none are to be set.

Example:

@avp_types

Location-Information   350  Grouped     MV
Requested-Information  353  Enumerated   V

Warning

The P flag has been deprecated by RFC 6733.

@custom_types Mod - Specifies AVPs for which module Mod provides encode/decode functions. The section contents consists of AVP names. For each such name, Mod:Name(encode|decode, Type, Data, Opts) is expected to provide encode/decode for values of the AVP, where Name is the name of the AVP, Type is it's type as declared in the @avp_types section of the dictionary, Data is the value to encode/decode, and Opts is a term that is passed through encode/decode.

Example:

@custom_types rfc4005_avps

Framed-IP-Address

@codecs Mod - Like @custom_types but requires the specified module to export Mod:Type(encode|decode, Name, Data, Opts) rather than Mod:Name(encode|decode, Type, Data, Opts).

Example:

@codecs rfc4005_avps

Framed-IP-Address

@messages - Defines the messages of the application. The section content consists of definitions of the form specified in section 3.2 of RFC 6733, "Command Code Format Specification".

@messages

RTR ::= < Diameter Header: 287, REQ, PXY >
        < Session-Id >
        { Auth-Application-Id }
        { Auth-Session-State }
        { Origin-Host }
        { Origin-Realm }
        { Destination-Host }
        { SIP-Deregistration-Reason }
        [ Destination-Realm ]
        [ User-Name ]
      * [ SIP-AOR ]
      * [ Proxy-Info ]
      * [ Route-Record ]
      * [ AVP ]

RTA ::= < Diameter Header: 287, PXY >
        < Session-Id >
        { Auth-Application-Id }
        { Result-Code }
        { Auth-Session-State }
        { Origin-Host }
        { Origin-Realm }
        [ Authorization-Lifetime ]
        [ Auth-Grace-Period ]
        [ Redirect-Host ]
        [ Redirect-Host-Usage ]
        [ Redirect-Max-Cache-Time ]
      * [ Proxy-Info ]
      * [ Route-Record ]
      * [ AVP ]

@grouped - Defines the contents of the AVPs of the application having type Grouped. The section content consists of definitions of the form specified in section 4.4 of RFC 6733, "Grouped AVP Values".

Example:

@grouped

SIP-Deregistration-Reason ::= < AVP Header: 383 >
                              { SIP-Reason-Code }
                              [ SIP-Reason-Info ]
                            * [ AVP ]

Specifying a Vendor-Id in the definition of a grouped AVP is equivalent to specifying it with @avp_vendor_id.

@enum Name - Defines values of AVP Name having type Enumerated. Section content consists of names and corresponding integer values. Integer values can be prefixed with 0x to be interpreted as hexadecimal.

Note that the AVP in question can be defined in an inherited dictionary in order to introduce additional values to an enumeration otherwise defined in another dictionary.

Example:

@enum SIP-Reason-Code

PERMANENT_TERMINATION    0
NEW_SIP_SERVER_ASSIGNED  1
SIP_SERVER_CHANGE        2
REMOVE_SIP_SERVER        3

If indirect_inherits option from codec/2 is used, new enum values can also be added in each .dia file along the inheritance chain, example:

a.dia:

@avp_types
    AAA 111 Enumerated V
@enum AAA
    A 0
    B 1

a.dia will see following enum values:

A 0

B 1

b.dia:

@inherits diameter_a
@enum AAA
    C 2
    D 3

b.dia will see following enum values:

A 0

B 1

C 2

D 3

c.dia:

@inherits diameter_b
@enum AAA
    E 4
    F 5

c.dia will see:

A 0

B 1

C 2

D 3

E 4

F 5

Warning: messages are not shown in this example, but it is required to add enum AVPs to messages in order for the code to encode/decode them to be generated!

@end - Causes parsing of the dictionary to terminate: any remaining content is ignored.

Comments can be included in a dictionary file using semicolon: characters from a semicolon to end of line are ignored.

MESSAGE RECORDS

The hrl generated from a dictionary specification defines records for the messages and grouped AVPs defined in @messages and @grouped sections. For each message or grouped AVP definition, a record is defined whose name is the message or AVP name, prefixed with any dictionary prefix defined with @prefix, and whose fields are the names of the AVPs contained in the message or grouped AVP in the order specified in the definition in question. For example, the grouped AVP

SIP-Deregistration-Reason ::= < AVP Header: 383 >
                              { SIP-Reason-Code }
                              [ SIP-Reason-Info ]
                            * [ AVP ]

will result in the following record definition given an empty prefix.

-record('SIP-Deregistration-Reason', {'SIP-Reason-Code',
                                      'SIP-Reason-Info',
                                      'AVP'}).

The values encoded in the fields of generated records depends on the type and number of times the AVP can occur. In particular, an AVP which is specified as occurring exactly once is encoded as a value of the AVP's type while an AVP with any other specification is encoded as a list of values of the AVP's type. The AVP's type is as specified in the AVP definition, the RFC 6733 types being described below.

DATA TYPES

The data formats defined in sections 4.2 ("Basic AVP Data Formats") and 4.3 ("Derived AVP Data Formats") of RFC 6733 are encoded as values of the types defined here. Values are passed to diameter:call/4 in a request record when sending a request, returned in a resulting answer record and passed to a handle_request/3 callback upon reception of an incoming request.

In cases in which there is a choice between string() and binary() types for OctetString() and derived types, the representation is determined by the value of diameter:service_opt() string_decode.

Basic AVP Data Formats

OctetString() = string() | binary()
Integer32()   = -2147483647..2147483647
Integer64()   = -9223372036854775807..9223372036854775807
Unsigned32()  = 0..4294967295
Unsigned64()  = 0..18446744073709551615
Float32()     = '-infinity' | float() | infinity
Float64()     = '-infinity' | float() | infinity
Grouped()     = record()

On encode, an OctetString() can be specified as an iolist(), excessively large floats (in absolute value) are equivalent to infinity or '-infinity' and excessively large integers result in encode failure. The records for grouped AVPs are as discussed in the previous section.

Derived AVP Data Formats

Address() = OctetString()
          | tuple()

On encode, an OctetString() IPv4 address is parsed in the usual x.x.x.x format while an IPv6 address is parsed in any of the formats specified by section 2.2 of RFC 2373, "Text Representation of Addresses". An IPv4 tuple() has length 4 and contains values of type 0..255. An IPv6 tuple() has length 8 and contains values of type 0..65535. The tuple representation is used on decode.

Time() = {date(), time()}

where

  date() = {Year, Month, Day}
  time() = {Hour, Minute, Second}

  Year   = integer()
  Month  = 1..12
  Day    = 1..31
  Hour   = 0..23
  Minute = 0..59
  Second = 0..59

Additionally, values that can be encoded are limited by way of their encoding as four octets as required by RFC 6733 with the required extension from RFC 2030. In particular, only values between {{1968,1,20},{3,14,8}} and {{2104,2,26},{9,42,23}} (both inclusive) can be encoded.

UTF8String() = [integer()] | binary()

List elements are the UTF-8 encodings of the individual characters in the string. Invalid codepoints will result in encode/decode failure. On encode, a UTF8String() can be specified as a binary, or as a nested list of binaries and codepoints.

DiameterIdentity() = OctetString()

A value must have length at least 1.

DiameterURI() = OctetString()
              | #diameter_URI{type = Type,
                              fqdn = FQDN,
                              port = Port,
                              transport = Transport,
                              protocol  = Protocol}

where

  Type = aaa | aaas
  FQDN = OctetString()
  Port = integer()
  Transport = sctp | tcp
  Protocol  = diameter | radius | 'tacacs+'

On encode, fields port, transport and protocol default to 3868, sctp and diameter respectively. The grammar of an OctetString-valued DiameterURI() is as specified in section 4.3 of RFC 6733. The record representation is used on decode.

Enumerated() = Integer32()

On encode, values can be specified using the macros defined in a dictionary's hrl file.

IPFilterRule()  = OctetString()
QoSFilterRule() = OctetString()

Values of these types are not currently parsed by diameter.

SEE ALSO

diameterc(1), diameter, diameter_app, diameter_codec, diameter_make

diameter

Main API of the diameter application.

This module provides the interface with which a user can implement a Diameter node that sends and receives messages using the Diameter protocol as defined in RFC 6733.

Basic usage consists of creating a representation of a locally implemented Diameter node and its capabilities with start_service/2, adding transport capability using add_transport/2 and sending Diameter requests and receiving Diameter answers with call/4. Incoming Diameter requests are communicated as callbacks to a diameter_app 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 diameter 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 diameter_dict(4).

elapsed_time() - Elapsed time since a given time.

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_callback{}

Mod = atom()
ExtraArgs = list()

Module implementing the callback interface defined in diameter_app, 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 appended to any module-specific extra arguments.

Specifying a #diameter_callback{} record allows individual functions to be configured in place of the usual diameter_app 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 service. 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(4).

{module,application_module()} - Callback module in which messages of the Diameter application are handled. See diameter_app for the required interface and semantics.

{state, term()} - Initial callback state. The prevailing state is passed to some diameter_app 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 communicated 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 return value for the call/4 invocation in question is as if a callback 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 associated with an application callback module), is detected.

If answer_3xxx then requests are answered without a handle_request/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 diameter_gen_base_rfc6733 as its common dictionary does distinguish between answer_3xxx and answer.

call_opt() - Options available to call/4 when sending an outgoing Diameter request. 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. Multiple options are equivalent a single all filter on the corresponding 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 application in question. Multiple options can be specified, and their order is respected in the candidate lists passed to a subsequent 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, values 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

{'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 equivalent 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 situations 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 reference to old code. In particular, such a value is typically inappropriate 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 Destination-Realm AVPs to be extracted from the outgoing request, assuming it to be a record- or list-valued diameter_codec:message(), and assuming 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 typical) 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 implies 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 exchange. 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 following 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 local 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 connection 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 remote peer. Pkt contains the CEA in question. In the case of rejection by a capabilities callback, the tuple contains the rejecting 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 connection 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/0 - For forward compatibility, a subscriber should be prepared to receive 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 application_alias() is passed to call/4, while for an incoming request the application identifier in the message header determines the application, the identifier being specified in the application's dictionary file.

Warning

The capabilities advertised by a node must match its configured applications. In particular, application configuration must be matched by corresponding capability() configuration, of *-Application-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 connections to the same peer, as identified by its Origin-Host at capabilities exchange.

If [node()] then a connection is rejected if another already exists 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 taking place whenever a new connection is to be established. Note that false allows an unlimited number of connections to be established 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 integer 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 remote 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, evaluated 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/0 in a list is ignored, so a collection of services can all be configured to share with the same list of nodes.

Defaults to false.

Note

Peers are only shared with services of the same name for the purpose of sending outgoing requests. Since the value of the application_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 question when passing messages to diameter_app callbacks. If true then mismatches in an outgoing messages cause message encoding 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 incoming messages respectively.

Defaults to true.

Note

Disabling arity checks affects the form of messages at encode/decode. In particular, decoded AVPs are represented as lists of values, regardless of the AVP's arity (ie. expected number in the message/AVP grammar in question), and values are expected to be supplied as lists at encode. This differs from the historic decode behaviour 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 derived 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 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 remote 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/0 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 requests are sent.

transport_opt() - Any transport option except applications, capabilities, transport_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 restricted. Defaults to all applications configured on the service in question. Applications not configured on the service in question are ignored.

Warning

The capabilities advertised by a node must match its configured applications. In particular, setting applications on a transport typically 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/decode AVPs that are not defined by the dictionary of the application in question. At decode, such AVPs are represented as diameter_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 alternate 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.

{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/0 - Causes an incoming CER to be answered with the specified Result-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 options 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 expected capabilities exchange message (CER or CEA) is not received from the peer. For a connecting transport, the timing of connection attempts is governed by connect_timer or watchdog_timer expiry. 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 milliseconds. This timer determines the frequency with which a transport attempts to establish an initial connection with its peer following transport configuration. Once an initial connection has been established, watchdog_timer determines the frequency of reconnection 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 connect_timer should be greater than its peer's Tw plus jitter.

Defaults to 30000 for a connecting transport and 60000 for a listening transport.

{disconnect_cb,eval()} - Callback invoked prior to terminating the transport process of a transport connection having watchdog state OKAY. Applied to application|service|transport and the transport_ref() and diameter_app:peer() in question: application indicates that the diameter 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 rebooting for Reason=service|application and goaway for Reason=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 terminated following an outgoing DPR if DPA is not received.

Defaults to 1000.

{dpr_timeout,Unsigned32()} - Number of milliseconds after which a transport connection is terminated 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. Messages 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 Diameter 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.

If exit then the transport process in question exits. If handle then the message is processed as usual, a resulting handle_request/3 or handle_answer/4 callback (if one takes place) indicating 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 for the behaviour of that module.

{pool_size, pos_integer()} - Number of transport processes to start. For a listening transport, determines the size of the pool of accepting transport processes, 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(): restrict_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 message before capabilities exchange should close the peer connection. If false then unexpected messages are discarded.

Defaults to true. Changing this results in non-standard behaviour, 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, DIAMETER_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 command 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 Diameter application.

The reason for the latter is presumably interoperability: allowing arbitrary AVPs setting the M-bit in a command makes its interpretation 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 command grammar as any AVP, regardless of M-bit, renders 1.3.4 meaningless, 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 mandatory 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 milliseconds, after which a started transport process should be terminated if it has not yet established a connection. For example, the following options on a connecting transport request a connection 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 diameter_transport. Defaults to diameter_tcp.

Multiple transport_module and transport_config options are allowed. 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 connection 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 machine. On key okay, the non-negative number of answered DWR messages 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 misbehaving 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 applied, 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 unmodified by service_info/2 and can be referred to in predicate functions passed to remove_transport/2.

transport_ref() = reference() - Reference returned by add_transport/2 that identifies the configuration.

SEE ALSO

diameter_app, diameter_transport, diameter_dict(4)

Summary

Types

'Address'()

app_alias()

app_module()

application_opt()

call_opt()

capability()

common_opt()

'DiameterIdentity'()

'DiameterURI'()

decode_format()

'Enumerated'()

elapsed_time()

eval()

evaluable()

'Float32'()

'Float64'()

'Grouped'()

'Integer32'()

'Integer64'()

'IPFilterRule'()

message_length()

'OctetString'()

peer_filter()

peer_ref()

'QoSFilterRule'()

remotes()

restriction()

sequence()

service_name()

service_opt()

strict_arities()

'Time'()

transport_opt()

transport_pred()

transport_ref()

'Unsigned32'()

'Unsigned64'()

'UTF8String'()

Functions

add_transport(SvcName, Transport)

Add transport capability to a service.

call(SvcName, App, Request, CallOpts)

Send a Diameter request message.

origin_state_id()

Return a reasonable value for use as Origin-State-Id in outgoing messages.

remove_transport(SvcName, Pred)

Remove previously added transports.

service_info(SvcName, Option)

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.

services()

Return the list of started services.

session_id(Ident)

Return a value for a Session-Id AVP.

start()

Start the diameter application.

start_service(SvcName, Opts)

Start a diameter service.

stop()

Stop the diameter application.

stop_service(SvcName)

Stop a diameter service.

subscribe(SvcName)

Subscribe to service_event() messages from a service.

unsubscribe(SvcName)

Unsubscribe to event messages from a service.

which_connections()

Return a list of all connections, grouped by the service they are associated with.

which_connections(SvcName)

Return a list of connections associated with the service 'SvcName'.

which_transports()

Return a list of all transports.

which_transports(SvcName)

Return a list of transports associated with the service 'SvcName'.

which_watchdogs()

Return a list of all watchdogs.

which_watchdogs(SvcName)

Return a list of watchdogs associated with the service 'SvcName'.

Types

'Address'()

(since OTP R14B03)

-type 'Address'() :: inet:ip_address() | string().

app_alias()

(since OTP R14B03)

-type app_alias() :: any().

app_module()

(since OTP R14B03)

-type app_module() ::
          module() |
          maybe_improper_list(module(), list()) |
          #diameter_callback{peer_up :: term(),
                             peer_down :: term(),
                             pick_peer :: term(),
                             prepare_request :: term(),
                             prepare_retransmit :: term(),
                             handle_request :: term(),
                             handle_answer :: term(),
                             handle_error :: term(),
                             default :: term(),
                             extra :: term()}.

application_opt()

(since OTP R14B03)

-type application_opt() ::
          {alias, app_alias()} |
          {answer_errors, callback | report | discard} |
          {call_mutates_state, boolean()} |
          {dictionary, module()} |
          {module, app_module()} |
          {request_errors, answer_3xxx | answer | callback} |
          {state, any()}.

call_opt()

(since OTP R14B03)

-type call_opt() ::
          detach |
          {extra, list()} |
          {filter, peer_filter()} |
          {peer, peer_ref()} |
          {timeout, 'Unsigned32'()}.

capability()

(since OTP R14B03)

-type capability() ::
          {'Origin-Host', 'DiameterIdentity'()} |
          {'Origin-Realm', 'DiameterIdentity'()} |
          {'Host-IP-Address', ['Address'()]} |
          {'Vendor-Id', 'Unsigned32'()} |
          {'Product-Name', 'UTF8String'()} |
          {'Supported-Vendor-Id', ['Unsigned32'()]} |
          {'Auth-Application-Id', ['Unsigned32'()]} |
          {'Vendor-Specific-Application-Id', ['Grouped'()]} |
          {'Firmware-Revision', 'Unsigned32'()}.

common_opt()

(not exported) (since OTP R14B03)

-type common_opt() ::
          {avp_dictionaries, [module()]} |
          {capabilities_cb, eval()} |
          {capx_timeout, 'Unsigned32'()} |
          {connect_timer, 'Unsigned32'()} |
          {disconnect_cb, eval()} |
          {dpa_timeout, 'Unsigned32'()} |
          {dpr_timeout, 'Unsigned32'()} |
          {incoming_maxlen, message_length()} |
          {length_errors, exit | handle | discard} |
          {pool_size, pos_integer()} |
          {spawn_opt, list() | mfa()} |
          {strict_capx, boolean()} |
          {strict_mbit, boolean()} |
          {watchdog_config, [{okay | suspect, non_neg_integer()}]} |
          {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}}.

'DiameterIdentity'()

(since OTP R14B03)

-type 'DiameterIdentity'() :: 'OctetString'().

'DiameterURI'()

(since OTP R14B03)

-type 'DiameterURI'() :: 'OctetString'().

decode_format()

(since OTP R14B03)

-type decode_format() :: record | list | map | none | record_from_map.

'Enumerated'()

(since OTP R14B03)

-type 'Enumerated'() :: 'Integer32'().

elapsed_time()

(since OTP R14B03)

-type elapsed_time() ::
          {Hours :: non_neg_integer(), Mins :: 0..59, Secs :: 0..59, MicroSecs :: 0..999999}.

eval()

(since OTP R14B03)

-type eval() :: {module(), atom(), list()} | fun() | maybe_improper_list(eval(), list()).

evaluable()

(since OTP R14B03)

-type evaluable() :: eval().

'Float32'()

(since OTP R14B03)

-type 'Float32'() :: '-infinity' | float() | infinity.

'Float64'()

(since OTP R14B03)

-type 'Float64'() :: '-infinity' | float() | infinity.

'Grouped'()

(since OTP R14B03)

-type 'Grouped'() :: list() | tuple().

'Integer32'()

(since OTP R14B03)

-type 'Integer32'() :: -2147483647..2147483647.

'Integer64'()

(since OTP R14B03)

-type 'Integer64'() :: -9223372036854775807..9223372036854775807.

'IPFilterRule'()

(since OTP R14B03)

-type 'IPFilterRule'() :: 'OctetString'().

message_length()

(since OTP R14B03)

-type message_length() :: 0..16777215.

'OctetString'()

(since OTP R14B03)

-type 'OctetString'() :: iolist().

peer_filter()

(since OTP R14B03)

-type peer_filter() ::
          none | host | realm |
          {host, any | 'DiameterIdentity'()} |
          {realm, any | 'DiameterIdentity'()} |
          {eval, eval()} |
          {neg, peer_filter()} |
          {first, [peer_filter()]} |
          {all, [peer_filter()]} |
          {any, [peer_filter()]}.

peer_ref()

(since OTP R14B03)

-opaque peer_ref()

'QoSFilterRule'()

(since OTP R14B03)

-type 'QoSFilterRule'() :: 'OctetString'().

remotes()

(since OTP R14B03)

-type remotes() :: boolean() | [node()] | eval().

restriction()

(since OTP R14B03)

-type restriction() :: false | node | nodes | [node()] | eval().

sequence()

(since OTP R14B03)

-type sequence() :: {'Unsigned32'(), 0..32}.

service_name()

(since OTP R14B03)

-type service_name() :: any().

service_opt()

(since OTP R14B03)

-type service_opt() ::
          capability() |
          {application, [application_opt()]} |
          {decode_format, decode_format()} |
          {restrict_connections, restriction()} |
          {sequence, sequence() | eval()} |
          {share_peers, remotes()} |
          {strict_arities, true | strict_arities()} |
          {string_decode, boolean()} |
          {traffic_counters, boolean()} |
          {use_shared_peers, remotes()} |
          {bins_info, boolean() | non_neg_integer()} |
          common_opt().

strict_arities()

(since OTP R14B03)

-type strict_arities() :: false | encode | decode.

'Time'()

(since OTP R14B03)

-type 'Time'() :: {{integer(), 1..12, 1..31}, {0..23, 0..59, 0..59}}.

transport_opt()

(since OTP R14B03)

-type transport_opt() ::
          {applications, [app_alias()]} |
          {capabilities, [capability()]} |
          {transport_config, any()} |
          {transport_config, any(), 'Unsigned32'() | infinity} |
          {transport_module, atom()} |
          common_opt() |
          {private, any()}.

transport_pred()

(since OTP R14B03)

-type transport_pred() ::
          fun((transport_ref(), connect | listen, list()) -> boolean()) |
          fun((transport_ref(), list()) -> boolean()) |
          fun((list()) -> boolean()) |
          transport_ref() |
          boolean() |
          list() |
          {connect | listen, transport_pred()} |
          {atom(), atom(), list()}.

transport_ref()

(since OTP R14B03)

-type transport_ref() :: reference().

'Unsigned32'()

(since OTP R14B03)

-type 'Unsigned32'() :: 0..4294967295.

'Unsigned64'()

(since OTP R14B03)

-type 'Unsigned64'() :: 0..18446744073709551615.

'UTF8String'()

(since OTP R14B03)

-type 'UTF8String'() :: iolist().

Functions

add_transport(SvcName, Transport)

(since OTP R14B03)

-spec add_transport(SvcName, Transport) -> {ok, TRef} | {error, Reason}
                       when
                           SvcName :: service_name(),
                           Transport :: {T, Opts},
                           T :: listen | connect,
                           Opts :: [transport_opt()],
                           TRef :: 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 connections 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 capabilities exchange the service calls each relevant application module's peer_up/3 callback after which the caller can exchange Diameter 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, CallOpts)

(since OTP R14B03)

-spec call(SvcName, App, Request, CallOpts) -> Result
              when
                  SvcName :: service_name(),
                  App :: app_alias(),
                  Request :: diameter_codec:message() | diameter_codec:packet(),
                  CallOpts :: [call_opt()],
                  Result :: ok | {error, Reason} | Answer,
                  Answer :: term(),
                  Reason :: term().

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. Unless the detach option is specified, the call returns either when an answer message is received from the peer or an error occurs. In the answer case, the return value is as returned by a handle_answer/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. Otherwise 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 answer times out then a handle_error/4 callback takes place with Reason = timeout.

If the request is successfully encoded and sent but the service 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 received then an attempt is made to resend the request to an alternate peer. If no such peer is available, or if the subsequent 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 following 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, handle_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 guarantees that the request has not been sent over the transport connection.

origin_state_id()

(since OTP R14B03)

-spec 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 Diameter Time(), at the time the diameter application was started.

remove_transport(SvcName, Pred)

(since OTP R14B03)

-spec remove_transport(SvcName, Pred) -> ok | {error, Reason}
                          when SvcName :: service_name(), Pred :: transport_pred(), 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) returns 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 processes 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, Option)

(since OTP R14B03)

-spec service_info(SvcName, Item | [Item]) -> term()
                      when SvcName :: service_name(), Item :: atom() | peer_ref().

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_service/2.

applications - Return the list of applications as configured with start_service/2.

capabilities - Return a tagged list of all capabilities values as configured 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.example.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 diameter_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 Diameter-level counters, an entry like {{{0,280,1},recv},2} saying 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 differently 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 follows.

[[{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 except that the client connections are grouped under an accept tuple.

Whether or not the transport_opt() pool_size has been configured 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 accept 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 diameter_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 connections 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()

(since OTP R14B03)

-spec services() -> [SvcName] when SvcName :: service_name().

Return the list of started services.

session_id(Ident)

(since OTP R14B03)

-spec session_id(Ident) -> SessionId when Ident :: 'DiameterIdentity'(), SessionId :: 'OctetString'().

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 message containing the returned value will be sent.

start()

(since OTP R14B03)

-spec start() -> ok | {error, Reason} when Reason :: term().

Start the diameter application.

The diameter application must be started before starting a service. In a production system this is typically accomplished by a boot file, not by calling start/0 explicitly.

start_service(SvcName, Opts)

(since OTP R14B03)

-spec start_service(SvcName, Opts) -> ok | {error, Reason}
                       when SvcName :: service_name(), Opts :: [service_opt()], Reason :: term().

Start a diameter service.

A service defines a locally-implemented Diameter node, specifying the capabilities to be advertised during capabilities exchange. Transports are added to a service using add_transport/2.

Note

A transport can both override its service's capabilities and restrict its supported Diameter applications so "service = Diameter node as identified by Origin-Host" is not necessarily the case.

stop()

(since OTP R14B03)

-spec stop() -> ok | {error, Reason} when Reason :: term().

Stop the diameter application.

stop_service(SvcName)

(since OTP R14B03)

-spec stop_service(SvcName) -> ok | {error, Reason} when 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 remove_transport/2.

Note

Stopping a service does not remove any associated transports: remove_transport/2 must be called to remove transport configuration.

subscribe(SvcName)

(since OTP R14B03)

-spec subscribe(SvcName) -> true when 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 required to guarantee the reception of all transport-related events.

unsubscribe(SvcName)

(since OTP R14B03)

-spec unsubscribe(SvcName) -> true when SvcName :: service_name().

Unsubscribe to event messages from a service.

which_connections()

(since OTP 26.2.4)

-spec which_connections() ->
                           [{SvcName,
                             [#{peer := PeerInfo,
                                wd := WDInfo,
                                peername := {inet:ip_address(), inet:port_number()},
                                sockname := {inet:ip_address(), inet:port_number()}}]}]
                           when
                               SvcName :: string(),
                               PeerInfo :: #{pid := pid(), uptime := elapsed_time()},
                               WDInfo ::
                                   #{ref := reference(),
                                     type := atom(),
                                     pid := pid(),
                                     state := diameter_service:wd_state(),
                                     uptime := elapsed_time()}.

Return a list of all connections, grouped by the service they are associated with.

which_connections(SvcName)

(since OTP 26.2.4)

-spec which_connections(SvcName) ->
                           [#{peer := PeerInfo,
                              wd := WDInfo,
                              peername := {inet:ip_address(), inet:port_number()},
                              sockname := {inet:ip_address(), inet:port_number()}}]
                           when
                               SvcName :: string(),
                               PeerInfo :: #{pid := pid(), uptime := elapsed_time()},
                               WDInfo ::
                                   #{ref := reference(),
                                     type := atom(),
                                     pid := pid(),
                                     state := diameter_service:wd_state(),
                                     uptime := elapsed_time()}.

Return a list of connections associated with the service 'SvcName'.

which_transports()

(since OTP 26.2.4)

-spec which_transports() -> [#{ref := reference(), type := atom(), service := string()}].

Return a list of all transports.

which_transports(SvcName)

(since OTP 26.2.4)

-spec which_transports(SvcName) -> [#{ref := reference(), type := atom()}] when SvcName :: string().

Return a list of transports associated with the service 'SvcName'.

which_watchdogs()

(since OTP 26.2.4)

-spec which_watchdogs() ->
                         [#{ref := reference(),
                            type := atom(),
                            pid := pid(),
                            state := diameter_service:wd_state(),
                            peer := boolean() | pid(),
                            uptime := elapsed_time(),
                            service := SvcName}]
                         when SvcName :: string().

Return a list of all watchdogs.

which_watchdogs(SvcName)

(since OTP 26.2.4)

-spec which_watchdogs(SvcName) ->
                         [#{ref := reference(),
                            type := atom(),
                            pid := pid(),
                            state := diameter_service:wd_state(),
                            peer := boolean() | pid(),
                            uptime := elapsed_time()}]
                         when SvcName :: string().

Return a list of watchdogs associated with the service 'SvcName'.

diameter_app behaviour

Callback module of a Diameter application.

A diameter service as started by diameter:start_service/2 configures one of more Diameter applications, each of whose configuration specifies 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(4) while the callback module is documented here. The callback module implements the Diameter application-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 connectivity with a Diameter peer.

pick_peer/4, prepare_request/3, prepare_retransmit/3, handle_answer/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 request message.

The arities for the the callback functions here assume no extra arguments. 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 diameter:call/4.

Summary

Types

capabilities()

A record containing the identities of the local Diameter node and the remote Diameter peer having an established transport connection, as well as the capabilities as determined by capabilities exchange. Each field of the record is a 2-tuple consisting of values for the (local) host and (remote) peer. Optional or possibly multiple values are encoded as lists of values, mandatory values as the bare value.

message()

The representation of a Diameter message as passed to diameter:call/4 or returned from a handle_request/3 callback.

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()

A tuple representing a Diameter peer connection.

peer_ref()

A term identifying a transport connection with a Diameter peer.

state()

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 returning a state are evaluated in a common service-specific process while those not returning state are evaluated in a request-specific process.

Callbacks

handle_answer(Packet, Request, SvcName, Peer)

Invoked when an answer message is received from a peer. The return value is returned from diameter:call/4 unless the detach option was specified.

handle_error(Reason, Request, SvcName, Peer)

Invoked when an error occurs before an answer message is received in response to an outgoing request. The return value is returned from diameter:call/4 unless the detach option was specified.

handle_request(Packet, SvcName, Peer)

Invoked when a request message is received from a peer. The application in which the callback takes place (that is, the callback module as configured with diameter:start_service/2) is determined by the Application Identifier in the header of the incoming request message, the selected module being the one whose corresponding dictionary declares itself as defining either the application in question or the Relay application.

peer_down(SvcName, Peer, 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 machine for the connection has left state OKAY and the peer will no longer be a candidate in pick_peer/4 callbacks.

peer_up(SvcName, Peer, 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.

pick_peer(LocalCandidates, RemoteCandidates, SvcName, State)

Invoked as a consequence of a call to diameter:call/4 to select a destination peer for an outgoing request. The return value indicates the selected peer.

prepare_request(Packet, SvcName, Peer)

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}

prepare_retransmit(Packet, SvcName, Peer)

Invoked to return a request for encoding and retransmission. Has the same role as prepare_request/3 in the case that a peer connection is lost an an alternate peer selected but the argument packet() is as returned by the initial prepare_request/3.

Types

capabilities()

(not exported) (since OTP R14B03)

-type capabilities() ::
          #diameter_caps{origin_host :: term(),
                         origin_realm :: term(),
                         host_ip_address :: term(),
                         vendor_id :: term(),
                         product_name :: term(),
                         origin_state_id :: term(),
                         supported_vendor_id :: term(),
                         auth_application_id :: term(),
                         inband_security_id :: term(),
                         acct_application_id :: term(),
                         vendor_specific_application_id :: term(),
                         firmware_revision :: term(),
                         avp :: term()}.

A record containing the identities of the local Diameter node and the remote Diameter peer having an established transport connection, as well as the capabilities as determined by capabilities exchange. Each field of the record is a 2-tuple consisting of values for the (local) host and (remote) peer. Optional or possibly multiple values are encoded as lists of values, mandatory values as the bare value.

message()

(not exported) (since OTP R14B03)

-type message() :: diameter_codec:message().

The representation of a Diameter message as passed to diameter:call/4 or returned from a handle_request/3 callback.

packet()

(not exported) (since OTP R14B03)

-type 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()

(not exported) (since OTP R14B03)

-type peer() :: {peer_ref(), capabilities()}.

A tuple representing a Diameter peer connection.

peer_ref()

(not exported) (since OTP R14B03)

-type peer_ref() :: term().

A term identifying a transport connection with a Diameter peer.

state()

(not exported) (since OTP R14B03)

-type 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 returning a state are evaluated in a common service-specific process while those not returning state are evaluated in a request-specific process.

Callbacks

handle_answer(Packet, Request, SvcName, Peer)

(since OTP R14B03)

-callback handle_answer(Packet, Request, SvcName, Peer) -> Result
                           when
                               Packet :: packet(),
                               Request :: message(),
                               SvcName :: diameter:service_name(),
                               Peer :: peer(),
                               Result :: term().

Invoked when an answer message is received from a peer. The return 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_request/3 or prepare_retransmit/3.

For any given call to diameter:call/4 there is at most one handle_answer/4 callback: any duplicate answer (due to retransmission or otherwise) is discarded. Similarly, only one of handle_answer/4 or handle_error/4 is called.

By default, an incoming answer message that cannot be successfully decoded causes the request process to fail, causing diameter:call/4 to return {error, failure} unless the detach option was specified. In particular, there is no handle_error/4 callback in this case. The diameter:application_opt() answer_errors can be set to change this behaviour.

handle_error(Reason, Request, SvcName, Peer)

(since OTP R14B03)

-callback handle_error(Reason, Request, SvcName, Peer) -> Result
                          when
                              Reason :: timeout | failover | term(),
                              Request :: message(),
                              SvcName :: diameter:service_name(),
                              Peer :: peer(),
                              Result :: term().

Invoked when an error occurs before an answer message is received in response to an outgoing request. The return value is returned from diameter:call/4 unless the detach option was specified.

Reason timeout indicates that an answer message has not been received within the time specified with the corresponding diameter: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.

handle_request(Packet, SvcName, Peer)

(since OTP R14B03)

-callback handle_request(Packet, SvcName, Peer) -> Action
                            when
                                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 application in which the callback takes place (that is, the callback module as configured with diameter:start_service/2) is determined by the Application Identifier in the header of the incoming 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 received in the relay application. Otherwise it contains the record representing the request as outlined in diameter_dict(4).

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 instead, 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 undefined if the transport specified no data. 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,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 #diameter_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 request 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 diameter_gen_base_rfc3588. (Since RFC 3588 only allows 3xxx values 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 appropriate then an answer-message should be constructed explicitly 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 callbacks take place just as if diameter:call/4 had been called explicitly. The End-to-End Identifier of the incoming request 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 message. 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 handle_error/4 callback) causes the request to be answered with 3002 (DIAMETER_UNABLE_TO_DELIVER).

This return value can be used only in relay applications (Application identifier = 0xFFFFFFFF).

{proxy, Opts} - Like relay but can only be used in applications other then the relay application.

{resend, Opts} - Neutral alternative to relay and proxy that can be used in any application.

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 #diameter_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 diameter:application_opt() request_errors.

peer_down(SvcName, Peer, State)

(since OTP R14B03)

-callback peer_down(SvcName, Peer, State) -> NewState
                       when
                           SvcName :: diameter:service_name(),
                           Peer :: peer(),
                           State :: 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 machine for the connection has left state OKAY and the peer will no longer be a candidate in pick_peer/4 callbacks.

peer_up(SvcName, Peer, State)

(since OTP R14B03)

-callback peer_up(SvcName, Peer, State) -> NewState
                     when
                         SvcName :: diameter:service_name(),
                         Peer :: peer(),
                         State :: 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 transport 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 handled independently of peer_up/3 and peer_down/3.

pick_peer(LocalCandidates, RemoteCandidates, SvcName, State)

(since OTP R14B03)

-callback pick_peer(LocalCandidates, RemoteCandidates, SvcName, State) -> Selection | false
                       when
                           LocalCandidates :: [peer()],
                           RemoteCandidates :: [peer()],
                           SvcName :: diameter:service_name(),
                           State :: 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 indicates the selected peer.

The candidate lists contain only those peers that have advertised support for the Diameter application in question during capabilities exchange, that have not be excluded by a filter option in the call to diameter:call/4 and whose watchdog state machine is in the OKAY state. The order of the elements is unspecified 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 RemoteCandidates 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 prepare_request/3 callback and, if the latter indicates that the request should be sent, by either handle_answer/4 or handle_error/4 depending on whether or not an answer message is received from the peer. If the transport becomes unavailable after prepare_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 Diameter application in question was configured with the diameter:application_opt() {call_mutates_state, true}. Otherwise, the State argument is always the initial value as configured on the application, not any subsequent value returned by a peer_up/3 or peer_down/3 callback.

prepare_request(Packet, SvcName, Peer)

(since OTP R14B03)

-callback prepare_request(Packet, SvcName, Peer) -> Action
                             when
                                 Packet :: packet(),
                                 SvcName :: diameter:service_name(),
                                 Peer :: peer(),
                                 Action :: Send | Discard | {eval_packet, Action, PostF},
                                 Send :: {send, packet() | message()},
                                 Discard :: {discard, Reason :: term()} | 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 #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 ignored.

A returned PostF will be evaluated on any encoded #diameter_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 returning {discard, discarded}.

prepare_retransmit(Packet, SvcName, Peer)

(since OTP R14B03)

-callback prepare_retransmit(Packet, SvcName, Peer) -> Action
                                when
                                    Packet :: packet(),
                                    SvcName :: diameter:service_name(),
                                    Peer :: peer(),
                                    Action :: Send | Discard | {eval_packet, Action, PostF},
                                    Send :: {send, packet() | message()},
                                    Discard :: {discard, Reason :: term()} | 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 connection 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}.

diameter_codec

Decode and encode of Diameter messages.

Incoming Diameter messages are decoded from binary() before being communicated to diameter_app callbacks. Similarly, outgoing Diameter messages are encoded into binary() before being passed to the appropriate diameter_transport module for transmission. The functions documented here implement the default encode/decode.

Warning

The diameter user does not need to call functions here explicitly when sending and receiving messages using diameter:call/4 and the callback interface documented in diameter_app: diameter itself provides encode/decode as a consequence of configuration passed to diameter:start_service/2, and the results may differ from those returned by the functions documented here, depending on configuration.

The header() and packet() records below are defined in diameter.hrl, which can be included as follows.

-include_lib("diameter/include/diameter.hrl").

Application-specific records are defined in the hrl files resulting from dictionary file compilation.

DATA TYPES

uint8()  = 0..255

uint24() = 0..16777215

uint32() = 0..4294967295 - 8-bit, 24-bit and 32-bit integers occurring in Diameter and AVP headers.

avp() = #diameter_avp{} - The application-neutral representation of an AVP. Primarily intended for use by relay applications that need to handle arbitrary Diameter applications. A service implementing a specific Diameter application (for which it configures a dictionary) can manipulate values of type message() instead.

Fields have the following types.

code = uint32()

is_mandatory = boolean()

need_encryption = boolean()

vendor_id = uint32() | undefined - Values in the AVP header, corresponding to AVP Code, the M flag, P flags and Vendor-ID respectively. A Vendor-ID other than undefined implies a set V flag.

data = iolist() - The data bytes of the AVP.

name = atom() - The name of the AVP as defined in the dictionary file in question, or undefined if the AVP is unknown to the dictionary file in question.

value = term() - The decoded value of an AVP. Will be undefined on decode if the data bytes could not be decoded, the AVP is unknown, or if the decode format is none. The type of a decoded value is as document in diameter_dict(4).

type = atom() - The type of the AVP as specified in the dictionary file in question (or one it inherits). Possible types are undefined and the Diameter types: OctetString, Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64, Grouped, Enumerated, Address, Time, UTF8String, DiameterIdentity, DiameterURI, IPFilterRule and QoSFilterRule.

dictionary() = module() - The name of a generated dictionary module as generated by diameterc(1) or diameter_make:codec/2. The interface provided by a dictionary module is an implementation detail that may change.

header() = #diameter_header{} - The record representation of the Diameter header. Values in a packet() returned by decode/2 are as extracted from the incoming message. Values set in an packet() passed to encode/2 are preserved in the encoded binary(), with the exception of length, cmd_code and application_id, all of which are determined by the dictionary() in question.

Note

It is not necessary to set header fields explicitly in outgoing messages as diameter itself will set appropriate values. Setting inappropriate values can be useful for test purposes.

Fields have the following types.

version = uint8()

length = uint24()

cmd_code = uint24()

application_id = uint32()

hop_by_hop_id = uint32()

end_to_end_id = uint32() - Values of the Version, Message Length, Command-Code, Application-ID, Hop-by-Hop Identifier and End-to-End Identifier fields of the Diameter header.

is_request = boolean()

is_proxiable = boolean()

is_error = boolean()

is_retransmitted = boolean() - Values corresponding to the R(equest), P(roxiable), E(rror) and T(Potentially re-transmitted message) flags of the Diameter header.

message() = record() | maybe_improper_list() - The representation of a Diameter message as passed to diameter:call/4 or returned from a handle_request/3 callback. The record representation is as outlined in diameter_dict(4): a message as defined in a dictionary file is encoded as a record with one field for each component AVP. Equivalently, a message can also be encoded as a list whose head is the atom-valued message name (as specified in the relevant dictionary file) and whose tail is either a list of AVP name/values pairs or a map with values keyed on AVP names. The format at decode is determined by diameter:service_opt() decode_format. Any of the formats is accepted at encode.

Another list-valued representation allows a message to be specified as a list whose head is a header() and whose tail is an avp() list. This representation is used by diameter itself when relaying requests as directed by the return value of a handle_request/3 callback. It differs from the other two in that it bypasses the checks for messages that do not agree with their definitions in the dictionary in question: messages are sent exactly as specified.

packet() = #diameter_packet{} - A container for incoming and outgoing Diameter messages. Fields have the following types.

header =header()| undefined - The Diameter header of the message. Can be (and typically should be) undefined for an outgoing message in a non-relay application, in which case diameter provides appropriate values.

avps = [avp()] | undefined - The AVPs of the message. Ignored for an outgoing message if the msg field is set to a value other than undefined.

msg =message()| undefined - The incoming/outgoing message. For an incoming message, a term corresponding to the configured decode format if the message can be decoded in a non-relay application, undefined otherwise. For an outgoing message, setting a [header()|avp()] list is equivalent to setting the header and avps fields to the corresponding values.

Warning

A value in the msg field does not imply an absence of decode errors. The errors field should also be examined.

bin = binary() - The incoming message prior to encode or the outgoing message after encode.

errors = [5000..5999 | {5000..5999, avp()}] - Errors detected at decode of an incoming message, as identified by a corresponding 5xxx series Result-Code (Permanent Failures). For an incoming request, these should be used to formulate an appropriate answer as documented for the handle_request/3 callback in diameter_app. For an incoming answer, the diameter:application_opt() answer_errors determines the behaviour.

transport_data = term() - An arbitrary term of meaning only to the transport process in question, as documented in diameter_transport.

SEE ALSO

diameterc(1), diameter_app, diameter_dict(4), diameter_make

Summary

Types

dictionary()

The name of a generated dictionary module as generated by diameterc(1) or diameter_make:codec/2. The interface provided by a dictionary module is an implementation detail that may change.

message()

The representation of a Diameter message as passed to diameter:call/4 or returned from a handle_request/3 callback.

packet()

A container for incoming and outgoing Diameter messages.

Functions

decode(Mod, Bin)

Decode a Diameter message.

encode(Mod, Msg)

Encode a Diameter message.

Types

dictionary()

(not exported) (since OTP R15B03)

-type dictionary() :: module().

The name of a generated dictionary module as generated by diameterc(1) or diameter_make:codec/2. The interface provided by a dictionary module is an implementation detail that may change.

message()

(since OTP R15B03)

-type message() :: record() | maybe_improper_list().

The representation of a Diameter message as passed to diameter:call/4 or returned from a handle_request/3 callback.

packet()

(since OTP R15B03)

-type packet() ::
          #diameter_packet{header :: term(),
                           avps :: term(),
                           msg :: term(),
                           bin :: term(),
                           errors :: term(),
                           transport_data :: term()}.

A container for incoming and outgoing Diameter messages.

Functions

decode(Mod, Bin)

(since OTP R15B03)

-spec decode(Mod, Bin) -> Pkt when Mod :: dictionary(), Bin :: binary(), Pkt :: packet().

Decode a Diameter message.

encode(Mod, Msg)

(since OTP R15B03)

-spec encode(Mod, Msg) -> Pkt when Mod :: dictionary(), Msg :: message() | packet(), Pkt :: packet().

Encode a Diameter message.

diameter_make

Diameter dictionary compilation.

The function codec/2 is used to compile a diameter dictionary file into Erlang source. The resulting source implements the interface diameter requires to encode and decode the dictionary's messages and AVPs.

The utility diameterc(1) provides an alternate compilation interface.

BUGS

Unrecognized options are silently ignored.

SEE ALSO

diameterc(1), diameter_dict(4)

Summary

Types

dict()

opt()

parsed()

Functions

codec(File, Opts)

Compile a single dictionary file.

flatten(Parsed)

Reconstitute a parsed dictionary, as returned by codec/2, without using @inherits. That is, construct an equivalent dictionary in which all AVP's are definined in the dictionary itself. The return value is also a parsed dictionary.

format(Parsed)

Turns a parsed dictionary, as returned by codec/2, back into the dictionary format.

format_error(Reason)

Turn an error reason returned by codec/2 into a readable string.

Types

dict()

(not exported) (since OTP R14B03)

-type dict() :: iolist() | binary() | parsed().

opt()

(since OTP R14B03)

-type opt() ::
          {include | outdir | name | prefix | inherits, string()} |
          return | verbose | parse | forms | erl | hrl.

parsed()

(not exported) (since OTP R14B03)

-type parsed() :: list().

Functions

codec(File, Opts)

(since OTP R15B)

-spec codec(File, [opt()]) -> ok | {ok, list()} | {error, Reason}
               when File :: dict() | {path, file:name_all()}, Reason :: string().

Compile a single dictionary file.

The input File can be either a path or a literal dictionary, the occurrence of newline (ascii NL) or carriage return (ascii CR) identifying the latter. Opt determines the format of the results and whether they are written to file or returned, and can have the following types.

parse | forms | erl | hrl - Specifies an output format. Whether the output is returned or written to file depends on whether or not option return is specified. When written to file, the resulting file(s) will have extensions .D, .F, .erl, and .hrl respectively, basenames defaulting to dictionary if the input dictionary is literal and does not specify @name. When returned, results are in the order of the corresponding format options. Format options default to erl and hrl (in this order) if unspecified.

The parse format is an internal representation that can be passed to flatten/1 and format/1, while the forms format can be passed to compile:forms/2. The erl and hrl formats are returned as iolists.

{include, string()} - Prepend the specified directory to the code path. Use to point at beam files compiled from inherited dictionaries, @inherits in a dictionary file creating a beam dependency, not an erl/hrl dependency.

Multiple include options can be specified.

{outdir, string()} - Write generated source to the specified directory. Defaults to the current working directory. Has no effect if option return is specified.

return - Return results in a {ok, [Out]} tuple instead of writing to file and returning ok.

{name|prefix, string()} - Transform the input dictionary before compilation, setting @name or @prefix to the specified string.

{inherits, string()} - Transform the input dictionary before compilation, appending @inherits of the specified string.

Two forms have special meaning:

{inherits, "-"}
{inherits, "Prev/Mod"}

The first has the effect of clearing any previous inherits, the second of replacing a previous inherits of Prev to one of Mod. This allows the semantics of the input dictionary to be changed without modifying the file itself.

Multiple inherits options can be specified.

indirect_inherits - This option makes compiler support automatic recursive inheritance. When a dictionary file inherits another .dia, all ancestors of that .dia will also be considered in code generation. This enhancement removes the requirement to explicitly list all parent dictionaries via @inherits, preventing missing AVP/message encodings and runtime errors.

Example C.dia inherits B.dia and B.dia inherits A.dia.

Before (without indirect_inherits):

If C.dia references AVPs from A.dia without directly inheriting it, the generated code will lack necessary definitions, causing encoding failures.

After (with indirect_inherits):

C.dia can reference AVPs from A.dia without directly inheriting it, compiler will resolve the entire inheritance chain automatically, ensuring all relevant descendant definitions from A.dia are available without additional user declarations.

Note that a dictionary's @name, together with the outdir option, determine the output paths when the return option is not specified. The @name of a literal input dictionary defaults to dictionary.

A returned error reason can be converted into a readable string using format_error/1.

flatten(Parsed)

(since OTP R16B03)

-spec flatten(parsed()) -> parsed().

Reconstitute a parsed dictionary, as returned by codec/2, without using @inherits. That is, construct an equivalent dictionary in which all AVP's are definined in the dictionary itself. The return value is also a parsed dictionary.

format(Parsed)

(since OTP R16B03)

-spec format(parsed()) -> iolist().

Turns a parsed dictionary, as returned by codec/2, back into the dictionary format.

format_error(Reason)

(since OTP 17.0)

-spec format_error(Reason) -> FormattedReason when Reason :: term(), FormattedReason :: string().

Turn an error reason returned by codec/2 into a readable string.

diameter_sctp

Diameter transport over SCTP.

This module implements diameter transport over SCTP using gen_sctp. It can be specified as the value of a transport_module option to diameter:add_transport/2 and implements the behaviour documented in diameter_transport.

SEE ALSO

diameter, diameter_transport, gen_sctp, inet

Summary

Types

connect_option()

listen_option()

match()

option()

Functions

start(TypeRef, Svc, Options)

The start function required by diameter_transport.

Types

connect_option()

(since OTP R14B03)

-type connect_option() :: {raddr, inet:ip_address()} | {rport, inet:port_number()} | option() | term().

listen_option()

(since OTP R14B03)

-type listen_option() :: {accept, match()} | option() | term().

match()

(not exported) (since OTP R14B03)

-type match() :: inet:ip_address() | string() | [match()].

option()

(not exported) (since OTP R14B03)

-type option() ::
          {sender, boolean()} |
          sender |
          {packet, boolean() | raw} |
          {message_cb, false | diameter:eval()}.

Functions

start(TypeRef, Svc, Options)

(since OTP R14B03)

-spec start({accept, Ref},
            #diameter_service{pid :: term(), capabilities :: term(), applications :: term()},
            [listen_option()]) ->
               {ok, pid(), [inet:ip_address()]}
               when Ref :: diameter:transport_ref();
           ({connect, Ref},
            #diameter_service{pid :: term(), capabilities :: term(), applications :: term()},
            [connect_option()]) ->
               {ok, pid(), [inet:ip_address()]}
               when Ref :: diameter:transport_ref().

The start function required by diameter_transport.

Options raddr and rport specify the remote address and port for a connecting transport and not valid for a listening transport: the former is required while latter defaults to 3868 if unspecified. Multiple raddr options can be specified, in which case the connecting transport in question attempts each in sequence until an association is established.

Option accept specifies remote addresses for a listening transport and is not valid for a connecting transport. If specified, a remote address that does not match one of the specified addresses causes the association to be aborted. Multiple accept options can be specified. A string-valued Match that does not parse as an address is interpreted as a regular expression.

Option unordered specifies whether or not to use unordered delivery, integer N being equivalent to N =< OS, where OS is the number of outbound streams negotiated on the association in question. Regardless of configuration, sending is ordered on stream 0 until reception of a second incoming message, to ensure that a peer receives capabilities exchange messages before any other. Defaults to false.

Option packet determines how/if an incoming message is packaged into a diameter_packet record. If false then messages are received as binary(). If true then as a record with the binary() message in the bin field and a {stream, Id} tuple in the transport_data field, where Id is the identifier of the inbound stream the message was received on. If raw then as a record with the received ancillary sctp_sndrcvinfo record in the transport_data field. Defaults to true.

Options message_cb and sender have semantics identical to those documented in diameter_tcp(3), but with the message argument to a recv callback being as directed by the packet option.

An {outstream, Id} tuple in the transport_data field of a outgoing diameter_packet record sets the outbound stream on which the message is sent, modulo the negotiated number of outbound streams. Any other value causes successive such sends to cycle though all outbound streams.

Remaining options are any accepted by gen_sctp:open/1, with the exception of options mode, binary, list, active and sctp_events. Note that options ip and port specify the local address and port respectively.

Multiple ip options can be specified for a multihomed peer. If none are specified then the values of Host-IP-Address in the diameter_service record are used. Option port defaults to 3868 for a listening transport and 0 for a connecting transport.

Warning

An small receive buffer may result in a peer having to resend incoming messages: set the inet option recbuf to increase the buffer size.

An small send buffer may result in outgoing messages being discarded: set the inet option sndbuf to increase the buffer size.

diameter_service

Summary

Types

wd_state()

State of the watchdog

Types

wd_state()

(since OTP 27.1)

-type wd_state() :: initial | okay | suspect | down | reopen.

State of the watchdog

diameter_tcp

Diameter transport over TCP.

This module implements diameter transport over TCP using gen_tcp. It can be specified as the value of a transport_module option to diameter:add_transport/2 and implements the behaviour documented in diameter_transport. TLS security is supported, either as an upgrade following capabilities exchange or at connection establishment.

Note that the ssl application is required for TLS and must be started before configuring TLS capability on diameter transports.

SEE ALSO

diameter, diameter_transport, gen_tcp, inet, ssl

Summary

Types

connect_option()

listen_option()

match()

option()

Functions

start/3

start({Type, Ref}, Svc, [Opt]) -> {ok, Pid} | {ok, Pid, [LAddr]} | {error, Reason}

Types

connect_option()

(since OTP R14B03)

-type connect_option() ::
          {raddr, inet:ip_address()} |
          {rport, pos_integer()} |
          {ssl_options, true | [ssl:tls_client_option()]} |
          option() |
          ssl:tls_client_option() |
          gen_tcp:connect_option().

listen_option()

(since OTP R14B03)

-type listen_option() ::
          {accept, match()} |
          {ssl_options, true | [ssl:tls_server_option()]} |
          option() |
          ssl:tls_server_option() |
          gen_tcp:listen_option().

match()

(not exported) (since OTP R14B03)

-type match() :: inet:ip_address() | string() | [match()].

option()

(not exported) (since OTP R14B03)

-type option() ::
          {port, non_neg_integer()} |
          {sender, boolean()} |
          sender |
          {message_cb, false | diameter:eval()} |
          {fragment_timer, 0..4294967295}.

Functions

start/3

(since OTP R14B03)

-spec start({accept, Ref},
            #diameter_service{pid :: term(), capabilities :: term(), applications :: term()},
            [listen_option()]) ->
               {ok, pid(), [inet:ip_address()]}
               when Ref :: diameter:transport_ref();
           ({connect, Ref},
            #diameter_service{pid :: term(), capabilities :: term(), applications :: term()},
            [connect_option()]) ->
               {ok, pid()}
               when Ref :: diameter:transport_ref().

start({Type, Ref}, Svc, [Opt]) -> {ok, Pid} | {ok, Pid, [LAddr]} | {error, Reason}

The start function required by diameter_transport.

Options raddr and rport specify the remote address and port for a connecting transport and are not valid for a listening transport.

Option accept specifies remote addresses for a listening transport and is not valid for a connecting transport. If specified, a remote address that does not match one of the specified addresses causes the connection to be aborted. Multiple accept options can be specified. A string-valued Match that does not parse as an address is interpreted as a regular expression.

Option ssl_options must be specified for a transport that should support TLS: a value of true results in a TLS handshake immediately upon connection establishment while list/0 specifies options to be passed to ssl:connect/2 or ssl:handshake/2 after capabilities exchange if TLS is negotiated.

Option fragment_timer specifies the timeout, in milliseconds, of a timer used to flush messages from the incoming byte stream even if the number of bytes indicated in the Message Length field of its Diameter Header have not yet been accumulated: such a message is received over the transport interface after two successive timeouts without the reception of additional bytes. Defaults to 1000.

Option sender specifies whether or not to use a dedicated process for sending outgoing messages, which avoids the possibility of send blocking reception. Defaults to false. If set to true then a message_cb that avoids the possibility of messages being queued in the sender process without bound should be configured.

Option message_cb specifies a callback that is invoked on incoming and outgoing messages, that can be used to implement flow control. It is applied to two arguments: an atom indicating the reason for the callback (send, recv, or ack after a completed send), and the message in question (binary() on recv, binary() or diameterpacket record on send or ack, or false on ack when an incoming request has been discarded). It should return a list of actions and a new callback as tail; eg. [fun cb/3, State]. Valid actions are the atoms send or recv, to cause a following message-valued action to be sent/received, a message to send/receive (binary() or diameter_packet record), or a boolean() to enable/disable reading on the socket. More than one send/recv/message sequence can be returned from the same callback, and an initial send/recv can be omitted if the same as the value passed as the callback's first argument. Reading is initially enabled, and returning false does not imply there cannot be subsequent recv callbacks since messages may already have been read. An empty tail is equivalent to the prevailing callback. Defaults to a callback equivalent to `fun(ack, ) -> []; (_, Msg) -> [Msg] end`.

Remaining options are any accepted by ssl:connect/3 or gen_tcp:connect/3 for a connecting transport, or ssl:listen/2 or gen_tcp:listen/2 for a listening transport, depending on whether or not {ssl_options, true} has been specified. Options binary, packet and active cannot be specified. Also, option port can be specified for a listening transport to specify the local listening port, the default being the standardized 3868. Note that the option ip specifies the local address.

An ssl_options list must be specified if and only if the transport in question has set Inband-Security-Id to 1 (TLS), as specified to either diameter:start_service/2 or diameter:add_transport/2, so that the transport process will receive notification of whether or not to commence with a TLS handshake following capabilities exchange. Failing to specify an options list on a TLS-capable transport for which TLS is negotiated will cause TLS handshake to fail. Failing to specify TLS capability when ssl_options has been specified will cause the transport process to wait for a notification that will not be forthcoming, which will eventually cause the RFC 3539 watchdog to take down the connection.

The first element of a non-empty Host-IP-Address list in Svc provides the local IP address if an ip option is not specified. The local address is either returned fromstart/3 or passed in a connected message over the transport interface.

diameter_transport behaviour

Diameter transport interface.

A module specified as a transport_module to diameter:add_transport/2 must implement the interface documented here. The interface consists of a function with which diameter starts a transport process and a message interface with which the transport process communicates with the process that starts it (aka its parent).

DATA TYPES

message() = binary() |diameter_codec:packet() - A Diameter message as passed over the transport interface.

For an inbound message from a transport process, a diameter_codec:packet() must contain the received message in its bin field. In the case of an inbound request, any value set in the transport_data field will passed back to the transport module in the corresponding answer message, unless the sender supplies another value.

For an outbound message to a transport process, a diameter_codec:packet() has a value other than undefined in its transport_data field and has the binary() to send in its bin field.

MESSAGES

All messages sent over the transport interface are of the form {diameter, term()}.

A transport process can expect messages of the following types from its parent.

{diameter, {send,message()| false}} - An outbound Diameter message. The atom false can only be received when request acknowledgements have been requests: see the ack message below.

{diameter, {close, Pid}} - A request to terminate the transport process after having received DPA in response to DPR. The transport process should exit. Pid is the pid() of the parent process.

{diameter, {tls, Ref, Type, Bool}} - Indication of whether or not capabilities exchange has selected inband security using TLS. Ref is a reference() that must be included in the {diameter, {tls, Ref}} reply message to the transport's parent process (see below). Type is either connect or accept depending on whether the process has been started for a connecting or listening transport respectively. Bool is a boolean() indicating whether or not the transport connection should be upgraded to TLS.

If TLS is requested (Bool=true) then a connecting process should initiate a TLS handshake with the peer and an accepting process should prepare to accept a handshake. A successful handshake should be followed by a {diameter, {tls, Ref}} message to the parent process. A failed handshake should cause the process to exit.

This message is only sent to a transport process over whose Inband-Security-Id configuration has indicated support for TLS.

A transport process should send messages of the following types to its parent.

{diameter, {self(), connected}} - Inform the parent that the transport process with Type=accept has established a connection with the peer. Not sent if the transport process has Type=connect.

{diameter, {self(), connected, Remote}}

{diameter, {self(), connected, Remote, [LocalAddr]}} - Inform the parent that the transport process with Type=connect has established a connection with a peer. Not sent if the transport process has Type=accept.  Remote is an arbitrary term that uniquely identifies the remote endpoint to which the transport has connected. A LocalAddr list has the same semantics as one returned from start/3.

{diameter, ack} - Request acknowledgements of unanswered requests. A transport process should send this once before passing incoming Diameter messages into diameter. As a result, every Diameter request passed into diameter with a recv message (below) will be answered with a send message (above), either a message() for the transport process to send or the atom false if the request has been discarded or otherwise not answered.

This is to allow a transport process to keep count of the number of incoming request messages that have not yet been answered or discarded, to allow it to regulate the amount of incoming traffic. Both diameter_tcp and diameter_sctp request acknowledgements when a message_cb is configured, turning send/recv message into callbacks that can be used to regulate traffic.

{diameter, {recv,message()}} - An inbound Diameter message.

{diameter, {tls, Ref}} - Acknowledgment of a successful TLS handshake. Ref is the reference() received in the {diameter, {tls, Ref, Type, Bool}} message in response to which the reply is sent. A transport must exit if a handshake is not successful.

SEE ALSO

diameter_tcp, diameter_sctp

Summary

Callbacks

start/3

Start a transport process. Called by diameter as a consequence of a call to diameter:add_transport/2 in order to establish or accept a transport connection respectively. A transport process maintains a connection with a single remote peer.

Callbacks

start/3

(since OTP R14B03)

-callback start({Type, Ref}, Svc, Config) -> {ok, Pid} | {ok, Pid, LAddrs} | {error, Reason}
                   when
                       Type :: connect | accept,
                       Ref :: diameter:transport_ref(),
                       Svc ::
                           #diameter_service{pid :: term(), capabilities :: term(), applications :: term()},
                       Config :: term(),
                       Pid :: pid(),
                       LAddrs :: [inet:ip_address()],
                       Reason :: term().

Start a transport process. Called by diameter as a consequence of a call to diameter:add_transport/2 in order to establish or accept a transport connection respectively. A transport process maintains a connection with a single remote peer.

Type indicates whether the transport process in question is being started for a connecting (Type=connect) or listening (Type=accept) transport. In the latter case, transport processes are started as required to accept connections from multiple peers.

Ref is the value that was returned from the call to diameter:add_transport/2 that has lead to starting of a transport process.

Svc contains capabilities passed to diameter:start_service/2 and diameter:add_transport/2, values passed to the latter overriding those passed to the former.

Config is as passed in transport_config tuple in the diameter:transport_opt() list passed to diameter:add_transport/2.

The start function should use the Host-IP-Address list in Svc and/or Config to select and return an appropriate list of local IP addresses. In the connecting case, the local address list can instead be communicated in a connected message (see MESSAGES below) following connection establishment. In either case, the local address list is used to populate Host-IP-Address AVPs in outgoing capabilities exchange messages if Host-IP-Address is unspecified.

A transport process must implement the message interface documented below. It should retain the pid of its parent, monitor the parent and terminate if it dies. It should not link to the parent. It should exit if its transport connection with its peer is lost.