aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/diameter/doc/src/diameter.xml155
-rw-r--r--lib/diameter/doc/src/diameter_app.xml39
-rw-r--r--lib/diameter/doc/src/diameter_codec.xml56
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml69
-rw-r--r--lib/diameter/doc/src/diameter_examples.xml1
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml2
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml9
-rw-r--r--lib/diameter/doc/src/diameterc.xml6
-rw-r--r--lib/diameter/examples/code/relay.erl2
-rw-r--r--lib/diameter/src/base/diameter_lib.erl24
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl88
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl15
-rw-r--r--lib/diameter/src/diameter.appup.src12
-rw-r--r--lib/diameter/src/transport/diameter_sctp.erl76
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl104
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl7
-rw-r--r--lib/diameter/vsn.mk2
17 files changed, 335 insertions, 332 deletions
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index d68a78ed6d..72181a42b0 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -94,12 +94,12 @@ in this module.</p>
<taglist>
-<tag><c>Address()</c></tag>
-<tag><c>DiameterIdentity()</c></tag>
-<tag><c>Grouped()</c></tag>
-<tag><c>OctetString()</c></tag>
-<tag><c>Time()</c></tag>
-<tag><c>Unsigned32()</c></tag>
+<tag><c>Address()</c></tag><item/>
+<tag><c>DiameterIdentity()</c></tag><item/>
+<tag><c>Grouped()</c></tag><item/>
+<tag><c>OctetString()</c></tag><item/>
+<tag><c>Time()</c></tag><item/>
+<tag><c>Unsigned32()</c></tag><item/>
<tag><c>UTF8String()</c></tag>
<item>
<p>
@@ -159,8 +159,7 @@ Has one the following types.</p>
<p>
Unique identifier for the application in the scope of the
service.
-Defaults to the value of the <c>dictionary</c> option if
-unspecified.</p>
+Defaults to the value of the <c>dictionary</c> option.</p>
</item>
<tag><c>{dictionary, atom()}</c></tag>
@@ -187,7 +186,7 @@ Initial callback state.
The prevailing state is passed to some
&man_app;
callbacks, which can then return a new state.
-Defaults to the value of the <c>alias</c> option if unspecified.</p>
+Defaults to the value of the <c>alias</c> option.</p>
</item>
<tag><c>{call_mutates_state, true|false}</c></tag>
@@ -195,7 +194,7 @@ Defaults to the value of the <c>alias</c> option if unspecified.</p>
<p>
Whether or not the &app_pick_peer;
application callback can modify the application state.
-Defaults to <c>false</c> if unspecified.</p>
+Defaults to <c>false</c>.</p>
<warning>
<p>
@@ -228,7 +227,7 @@ question is as if a callback had taken place and returned
<c>{error, failure}</c>.</p>
<p>
-Defaults to <c>discard</c> if unspecified.</p>
+Defaults to <c>discard</c>.</p>
</item>
<tag><c>{request_errors, answer_3xxx|answer|callback}</c></tag>
@@ -249,7 +248,7 @@ place and its return value determines the answer sent to the peer, if
any.</p>
<p>
-Defaults to <c>answer_3xxx</c> if unspecified.</p>
+Defaults to <c>answer_3xxx</c>.</p>
<note>
<p>
@@ -339,8 +338,8 @@ Has one of the following types.</p>
<taglist>
-<tag><c>{'Origin-Host', &dict_DiameterIdentity;}</c></tag>
-<tag><c>{'Origin-Realm', &dict_DiameterIdentity;}</c></tag>
+<tag><c>{'Origin-Host', &dict_DiameterIdentity;}</c></tag><item/>
+<tag><c>{'Origin-Realm', &dict_DiameterIdentity;}</c></tag><item/>
<tag><c>{'Host-IP-Address', [&dict_Address;]}</c></tag>
<item>
<p>
@@ -352,8 +351,8 @@ question communicates an address list as described in
&man_transport;</p>
</item>
-<tag><c>{'Vendor-Id', &dict_Unsigned32;}</c></tag>
-<tag><c>{'Product-Name', &dict_UTF8String;}</c></tag>
+<tag><c>{'Vendor-Id', &dict_Unsigned32;}</c></tag><item/>
+<tag><c>{'Product-Name', &dict_UTF8String;}</c></tag><item/>
<tag><c>{'Origin-State-Id', &dict_Unsigned32;}</c></tag>
<item>
<p>
@@ -366,8 +365,8 @@ can be used as to retrieve a value that is computed when the diameter
application is started.</p>
</item>
-<tag><c>{'Supported-Vendor-Id', [&dict_Unsigned32;]}</c></tag>
-<tag><c>{'Auth-Application-Id', [&dict_Unsigned32;]}</c></tag>
+<tag><c>{'Supported-Vendor-Id', [&dict_Unsigned32;]}</c></tag><item/>
+<tag><c>{'Auth-Application-Id', [&dict_Unsigned32;]}</c></tag><item/>
<tag><c>{'Inband-Security-Id', [&dict_Unsigned32;]}</c></tag>
<item>
<p>
@@ -377,9 +376,9 @@ If 1 (TLS) is specified then TLS is selected if the CER/CEA received
from the peer offers it.</p>
</item>
-<tag><c>{'Acct-Application-Id', [&dict_Unsigned32;]}</c></tag>
-<tag><c>{'Vendor-Specific-Application-Id', [&dict_Grouped;]}</c></tag>
-<tag><c>{'Firmware-Revision', &dict_Unsigned32;}</c></tag>
+<tag><c>{'Acct-Application-Id', [&dict_Unsigned32;]}</c></tag><item/>
+<tag><c>{'Vendor-Specific-Application-Id', [&dict_Grouped;]}</c></tag><item/>
+<tag><c>{'Firmware-Revision', &dict_Unsigned32;}</c></tag><item/>
</taglist>
@@ -567,9 +566,8 @@ Can have one of the following types.</p>
<taglist>
-<tag><c>start</c></tag>
+<tag><c>start</c></tag><item/>
<tag><c>stop</c></tag>
-
<item>
<p>
The service is being started or stopped.
@@ -578,8 +576,8 @@ No event follows a <c>stop</c> event, and this event
implies the termination of all transport processes.</p>
</item>
-<tag><c>{up, Ref, Peer, Config, Pkt}</c></tag>
-<tag><c>{up, Ref, Peer, Config}</c></tag>
+<tag><c>{up, Ref, Peer, Config, Pkt}</c></tag><item/>
+<tag><c>{up, Ref, Peer, Config}</c></tag><item/>
<tag><c>{down, Ref, Peer, Config}</c></tag>
<item>
<pre>
@@ -788,8 +786,8 @@ be matched by corresponding &capability; configuration, of
</item>
-<marker id="incoming_maxlen"/>
-<tag><c>{incoming_maxlen, 0..16777215}</c></tag>
+<tag>
+<marker id="incoming_maxlen"/><c>{incoming_maxlen, 0..16777215}</c></tag>
<item>
<p>
Bound on the expected size of incoming Diameter messages.
@@ -917,8 +915,8 @@ Options <c>monitor</c> and <c>link</c> are ignored.</p>
Defaults to the empty list.</p>
</item>
-<marker id="strict_mbit"/>
-<tag><c>{strict_mbit, boolean()}</c></tag>
+<tag>
+<marker id="strict_mbit"/><c>{strict_mbit, boolean()}</c></tag>
<item>
<p>
Whether or not to regard an AVP setting the M-bit as erroneous when
@@ -935,7 +933,7 @@ Defaults to <c>true</c>.</p>
<p>
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 <b>any</b> arbitrary AVP; on the
+in a command grammar as meaning <em>any</em> 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.</p>
@@ -945,7 +943,7 @@ 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 <c>AVP</c> in a command grammar as <b>any</b>
+However, interpreting <c>AVP</c> 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.</p>
@@ -960,8 +958,8 @@ occur in the message in question.</p>
</item>
-<marker id="string_decode"/>
-<tag><c>{string_decode, boolean()}</c></tag>
+<tag>
+<marker id="string_decode"/><c>{string_decode, boolean()}</c></tag>
<item>
<p>
Whether or not to decode AVPs of type &dict_OctetString; and its
@@ -1031,8 +1029,9 @@ Option passed to &add_transport;.
Has one of the following types.</p>
<taglist>
-<marker id="applications"/>
-<tag><c>{applications, [&application_alias;]}</c></tag>
+
+<tag>
+<marker id="applications"/><c>{applications, [&application_alias;]}</c></tag>
<item>
<p>
Diameter applications to which the transport should be restricted.
@@ -1050,8 +1049,8 @@ implies having to set matching *-Application-Id AVPs in a
</item>
-<marker id="capabilities"/>
-<tag><c>{capabilities, [&capability;]}</c></tag>
+<tag>
+<marker id="capabilities"/><c>{capabilities, [&capability;]}</c></tag>
<item>
<p>
AVPs used to construct outgoing CER/CEA messages.
@@ -1064,8 +1063,8 @@ may be particularly appropriate for Inband-Security-Id, in case
TLS is desired over TCP as implemented by &man_tcp;.</p>
</item>
-<marker id="capabilities_cb"/>
-<tag><c>{capabilities_cb, &evaluable;}</c></tag>
+<tag>
+<marker id="capabilities_cb"/><c>{capabilities_cb, &evaluable;}</c></tag>
<item>
<p>
Callback invoked upon reception of CER/CEA during capabilities
@@ -1112,8 +1111,8 @@ case the corresponding callbacks are applied until either all return
<c>ok</c> or one does not.</p>
</item>
-<marker id="capx_timeout"/>
-<tag><c>{capx_timeout, &dict_Unsigned32;}</c></tag>
+<tag>
+<marker id="capx_timeout"/><c>{capx_timeout, &dict_Unsigned32;}</c></tag>
<item>
<p>
Number of milliseconds after which a transport process having an
@@ -1127,8 +1126,8 @@ For a listening transport, the peer determines the timing.</p>
Defaults to 10000.</p>
</item>
-<marker id="connect_timer"/>
-<tag><c>{connect_timer, Tc}</c></tag>
+<tag>
+<marker id="connect_timer"/><c>{connect_timer, Tc}</c></tag>
<item>
<pre>
Tc = &dict_Unsigned32;
@@ -1158,9 +1157,8 @@ Defaults to 30000 for a connecting transport and 60000 for a listening
transport.</p>
</item>
-<marker id="disconnect_cb"/>
-<tag><c>{disconnect_cb, &evaluable;}</c></tag>
-
+<tag>
+<marker id="disconnect_cb"/><c>{disconnect_cb, &evaluable;}</c></tag>
<item>
<p>
Callback invoked prior to terminating the transport process of a
@@ -1236,8 +1234,8 @@ configured them.</p>
Defaults to a single callback returning <c>dpr</c>.</p>
</item>
-<marker id="dpa_timeout"/>
-<tag><c>{dpa_timeout, &dict_Unsigned32;}</c></tag>
+<tag>
+<marker id="dpa_timeout"/><c>{dpa_timeout, &dict_Unsigned32;}</c></tag>
<item>
<p>
Number of milliseconds after which a transport connection is
@@ -1247,8 +1245,8 @@ terminated following an outgoing DPR if DPA is not received.</p>
Defaults to 1000.</p>
</item>
-<marker id="dpr_timeout"/>
-<tag><c>{dpr_timeout, &dict_Unsigned32;}</c></tag>
+<tag>
+<marker id="dpr_timeout"/><c>{dpr_timeout, &dict_Unsigned32;}</c></tag>
<item>
<p>
Number of milliseconds after which a transport connection is
@@ -1259,8 +1257,8 @@ connection.</p>
Defaults to 5000.</p>
</item>
-<marker id="length_errors"/>
-<tag><c>{length_errors, exit|handle|discard}</c></tag>
+<tag>
+<marker id="length_errors"/><c>{length_errors, exit|handle|discard}</c></tag>
<item>
<p>
How to deal with errors in the Message Length field of the
@@ -1308,8 +1306,8 @@ the same peer.</p>
</item>
-<marker id="spawn_opt"/>
-<tag><c>{spawn_opt, [term()]}</c></tag>
+<tag>
+<marker id="spawn_opt"/><c>{spawn_opt, [term()]}</c></tag>
<item>
<p>
Options passed to &spawn_opt; when spawning a process for an
@@ -1320,15 +1318,15 @@ Options <c>monitor</c> and <c>link</c> are ignored.</p>
Defaults to the list configured on the service if not specified.</p>
</item>
-<marker id="transport_config"/>
-<tag><c>{transport_config, term()}</c></tag>
+<tag>
+<marker id="transport_config"/><c>{transport_config, term()}</c></tag><item/>
<tag><c>{transport_config, term(), &dict_Unsigned32; | infinity}</c></tag>
<item>
<p>
Term passed as the third argument to the &transport_start; function of
the relevant &transport_module; in order to
start a transport process.
-Defaults to the empty list if unspecified.</p>
+Defaults to the empty list.</p>
<p>
The 3-tuple form additionally specifies an interval, in milliseconds,
@@ -1349,12 +1347,12 @@ request a connection with one peer over SCTP or another
To listen on both SCTP and TCP, define one transport for each.</p>
</item>
-<marker id="transport_module"/>
-<tag><c>{transport_module, atom()}</c></tag>
+<tag>
+<marker id="transport_module"/><c>{transport_module, atom()}</c></tag>
<item>
<p>
Module implementing a transport process as defined in &man_transport;.
-Defaults to <c>diameter_tcp</c> if unspecified.</p>
+Defaults to <c>diameter_tcp</c>.</p>
<p>
Multiple <c>transport_module</c> and &transport_config;
@@ -1369,8 +1367,9 @@ modules in order until one establishes a connection within the
corresponding timeout (see below) or all fail.</p>
</item>
-<marker id="watchdog_config"/>
-<tag><c>{watchdog_config, [{okay|suspect, non_neg_integer()}]}</c></tag>
+<tag>
+<marker id="watchdog_config"/><c>{watchdog_config,
+ [{okay|suspect, non_neg_integer()}]}</c></tag>
<item>
<p>
Configuration that alters the behaviour of the watchdog
@@ -1393,8 +1392,8 @@ misbehaving nodes during test.</p>
</warning>
</item>
-<marker id="watchdog_timer"/>
-<tag><c>{watchdog_timer, TwInit}</c></tag>
+<tag>
+<marker id="watchdog_timer"/><c>{watchdog_timer, TwInit}</c></tag>
<item>
<pre>
TwInit = &dict_Unsigned32;
@@ -1412,7 +1411,7 @@ the callback.</p>
<p>
An integer value must be at least 6000 as required by RFC 3539.
-Defaults to 30000 if unspecified.</p>
+Defaults to 30000.</p>
</item>
</taglist>
@@ -1422,10 +1421,10 @@ Unrecognized options are silently ignored but are returned unmodified
by &service_info; and can be referred to
in predicate functions passed to &remove_transport;.</p>
-<marker id="transport_ref"/>
</item>
-<tag><c>transport_ref() = reference()</c></tag>
+<tag>
+<marker id="transport_ref"/><c>transport_ref() = reference()</c></tag>
<item>
<p>
Reference returned by &add_transport; that
@@ -1682,17 +1681,17 @@ returned.</p>
<taglist>
-<tag><c>'Origin-Host'</c></tag>
-<tag><c>'Origin-Realm'</c></tag>
-<tag><c>'Vendor-Id'</c></tag>
-<tag><c>'Product-Name'</c></tag>
-<tag><c>'Origin-State-Id'</c></tag>
-<tag><c>'Host-IP-Address'</c></tag>
-<tag><c>'Supported-Vendor'</c></tag>
-<tag><c>'Auth-Application-Id'</c></tag>
-<tag><c>'Inband-Security-Id'</c></tag>
-<tag><c>'Acct-Application-Id'</c></tag>
-<tag><c>'Vendor-Specific-Application-Id'</c></tag>
+<tag><c>'Origin-Host'</c></tag><item/>
+<tag><c>'Origin-Realm'</c></tag><item/>
+<tag><c>'Vendor-Id'</c></tag><item/>
+<tag><c>'Product-Name'</c></tag><item/>
+<tag><c>'Origin-State-Id'</c></tag><item/>
+<tag><c>'Host-IP-Address'</c></tag><item/>
+<tag><c>'Supported-Vendor'</c></tag><item/>
+<tag><c>'Auth-Application-Id'</c></tag><item/>
+<tag><c>'Inband-Security-Id'</c></tag><item/>
+<tag><c>'Acct-Application-Id'</c></tag><item/>
+<tag><c>'Vendor-Specific-Application-Id'</c></tag><item/>
<tag><c>'Firmware-Revision'</c></tag>
<item>
<p>
diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml
index 973b6eb732..dfcd00975b 100644
--- a/lib/diameter/doc/src/diameter_app.xml
+++ b/lib/diameter/doc/src/diameter_app.xml
@@ -90,17 +90,14 @@ is called in response to an incoming Diameter request message.</p>
</list>
-</description>
-
-<note>
<p>
-The arities given for the the callback functions here assume no extra
-arguments.
+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 &mod_start_service;
and, for the call-specific callbacks, any extra arguments passed to
&mod_call;.</p>
-</note>
+
+</description>
<!-- ===================================================================== -->
<!-- ===================================================================== -->
@@ -110,9 +107,8 @@ and, for the call-specific callbacks, any extra arguments passed to
<taglist>
-<marker id="capabilities"/>
-
-<tag><c>capabilities() = #diameter_caps{}</c></tag>
+<tag>
+<marker id="capabilities"/><c>capabilities() = #diameter_caps{}</c></tag>
<item>
<p>
A record containing the identities of
@@ -126,9 +122,8 @@ Optional or possibly multiple values are encoded as lists of values,
mandatory values as the bare value.</p>
</item>
-<marker id="message"/>
-
-<tag><c>message() = &codec_message;</c></tag>
+<tag>
+<marker id="message"/><c>message() = &codec_message;</c></tag>
<item>
<p>
The representation of a Diameter message as passed to
@@ -136,9 +131,8 @@ The representation of a Diameter message as passed to
</item>
-<marker id="packet"/>
-
-<tag><c>packet() = &codec_packet;</c></tag>
+<tag>
+<marker id="packet"/><c>packet() = &codec_packet;</c></tag>
<item>
<p>
A container for incoming and outgoing Diameter messages that's passed
@@ -146,25 +140,22 @@ through encode/decode and transport.
Fields should not be set in return values except as documented.</p>
</item>
-<marker id="peer_ref"/>
-
-<tag><c>peer_ref() = term()</c></tag>
+<tag>
+<marker id="peer_ref"/><c>peer_ref() = term()</c></tag>
<item>
<p>
A term identifying a transport connection with a Diameter peer.</p>
</item>
-<marker id="peer"/>
-
-<tag><c>peer() = {&peer_ref;, &capabilities;}</c></tag>
+<tag>
+<marker id="peer"/><c>peer() = {&peer_ref;, &capabilities;}</c></tag>
<item>
<p>
A tuple representing a Diameter peer connection.</p>
</item>
-<marker id="state"/>
-
-<tag><c>state() = term()</c></tag>
+<tag>
+<marker id="state"/><c>state() = term()</c></tag>
<item>
<p>
The state maintained by the application callback functions
diff --git a/lib/diameter/doc/src/diameter_codec.xml b/lib/diameter/doc/src/diameter_codec.xml
index a0313e2877..91e96058dd 100644
--- a/lib/diameter/doc/src/diameter_codec.xml
+++ b/lib/diameter/doc/src/diameter_codec.xml
@@ -88,10 +88,9 @@ files resulting from dictionary file compilation.</p>
<taglist>
-<marker id="integers"/>
-
-<tag><c>uint8()&nbsp; = 0..255</c></tag>
-<tag><c>uint24() = 0..16777215</c></tag>
+<tag>
+<marker id="integers"/><c>uint8()&nbsp; = 0..255</c></tag><item/>
+<tag><c>uint24() = 0..16777215</c></tag><item/>
<tag><c>uint32() = 0..4294967295</c></tag>
<item>
<p>
@@ -99,9 +98,8 @@ files resulting from dictionary file compilation.</p>
headers.</p>
</item>
-<marker id="avp"/>
-
-<tag><c>avp() = #diameter_avp{}</c></tag>
+<tag>
+<marker id="avp"/><c>avp() = #diameter_avp{}</c></tag>
<item>
<p>
The application-neutral representation of an AVP.
@@ -116,9 +114,9 @@ Fields have the following types.</p>
<taglist>
-<tag><c>code = uint32()</c></tag>
-<tag><c>is_mandatory = boolean()</c></tag>
-<tag><c>need_encryption = boolean()</c></tag>
+<tag><c>code = uint32()</c></tag><item/>
+<tag><c>is_mandatory = boolean()</c></tag><item/>
+<tag><c>need_encryption = boolean()</c></tag><item/>
<tag><c>vendor_id = uint32() | undefined</c></tag>
<item>
<p>
@@ -167,9 +165,8 @@ Possible types are <c>undefined</c> and the Diameter types:
</item>
-<marker id="dictionary"/>
-
-<tag><c>dictionary() = module()</c></tag>
+<tag>
+<marker id="dictionary"/><c>dictionary() = module()</c></tag>
<item>
<p>
@@ -179,9 +176,8 @@ The interface provided by a dictionary module is an
implementation detail that may change.</p>
</item>
-<marker id="header"/>
-
-<tag><c>header() = #diameter_header{}</c></tag>
+<tag>
+<marker id="header"/><c>header() = #diameter_header{}</c></tag>
<item>
<p>
The record representation of the Diameter header.
@@ -204,11 +200,11 @@ Fields have the following types.</p>
<taglist>
-<tag><c>version = uint8()</c></tag>
-<tag><c>length = uint24()</c></tag>
-<tag><c>cmd_code = uint24()</c></tag>
-<tag><c>application_id = uint32()</c></tag>
-<tag><c>hop_by_hop_id = uint32()</c></tag>
+<tag><c>version = uint8()</c></tag><item/>
+<tag><c>length = uint24()</c></tag><item/>
+<tag><c>cmd_code = uint24()</c></tag><item/>
+<tag><c>application_id = uint32()</c></tag><item/>
+<tag><c>hop_by_hop_id = uint32()</c></tag><item/>
<tag><c>end_to_end_id = uint32()</c></tag>
<item>
<p>
@@ -217,9 +213,9 @@ Hop-by-Hop Identifier and End-to-End Identifier fields of the Diameter
header.</p>
</item>
-<tag><c>is_request = boolean()</c></tag>
-<tag><c>is_proxiable = boolean()</c></tag>
-<tag><c>is_error = boolean()</c></tag>
+<tag><c>is_request = boolean()</c></tag><item/>
+<tag><c>is_proxiable = boolean()</c></tag><item/>
+<tag><c>is_error = boolean()</c></tag><item/>
<tag><c>is_retransmitted = boolean()</c></tag>
<item>
<p>
@@ -232,9 +228,8 @@ header.</p>
</item>
-<marker id="message"/>
-
-<tag><c>message() = record() | list()</c></tag>
+<tag>
+<marker id="message"/><c>message() = record() | list()</c></tag>
<item>
<p>
The representation of a Diameter message as passed to
@@ -257,9 +252,8 @@ question: messages are sent exactly as specified.</p>
</item>
-<marker id="packet"/>
-
-<tag><c>packet() = #diameter_packet{}</c></tag>
+<tag>
+<marker id="packet"/><c>packet() = #diameter_packet{}</c></tag>
<item>
<p>
A container for incoming and outgoing Diameter messages.
@@ -296,7 +290,7 @@ corresponding values.</p>
<warning>
<p>
-A record-valued <c>msg</c> field does <b>not</b> imply an absence of
+A record-valued <c>msg</c> field does <em>not</em> imply an absence of
decode errors.
The <c>errors</c> field should also be examined.</p>
</warning>
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index ae40f99aee..9584d682c2 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "fileref.dtd" [
+<!DOCTYPE fileref SYSTEM "fileref.dtd" [
<!ENTITY format
'<seealso marker="#FILE_FORMAT">FILE FORMAT</seealso>'>
<!ENTITY records
@@ -121,9 +121,8 @@ The order in which sections are specified is unimportant.</p>
<taglist>
-<marker id="id"/>
-
-<tag><c>@id Number</c></tag>
+<tag>
+<marker id="id"/><c>@id Number</c></tag>
<item>
<p>
Defines the integer Number as the Diameter Application Id of the
@@ -146,14 +145,13 @@ Example:</p>
</item>
-<marker id="name"/>
-
-<tag><c>@name Mod</c></tag>
+<tag>
+<marker id="name"/><c>@name Mod</c></tag>
<item>
<p>
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 if unspecified.
+minus any extension.
The section has empty content.</p>
<p>
@@ -169,9 +167,8 @@ Example:</p>
</item>
-<marker id="prefix"/>
-
-<tag><c>@prefix Name</c></tag>
+<tag>
+<marker id="prefix"/><c>@prefix Name</c></tag>
<item>
<p>
Defines Name as the prefix to be added to record and constant names
@@ -194,9 +191,8 @@ Example:</p>
</item>
-<marker id="vendor"/>
-
-<tag><c>@vendor Number Name</c></tag>
+<tag>
+<marker id="vendor"/><c>@vendor Number Name</c></tag>
<item>
<p>
Defines the integer Number as the the default Vendor-Id of AVPs for
@@ -216,9 +212,8 @@ Example:</p>
</item>
-<marker id="avp_vendor_id"/>
-
-<tag><c>@avp_vendor_id Number</c></tag>
+<tag>
+<marker id="avp_vendor_id"/><c>@avp_vendor_id Number</c></tag>
<item>
<p>
Defines the integer Number as the Vendor-Id of the AVPs listed in the
@@ -238,9 +233,8 @@ Region-Set
</item>
-<marker id="inherits"/>
-
-<tag><c>@inherits Mod</c></tag>
+<tag>
+<marker id="inherits"/><c>@inherits Mod</c></tag>
<item>
<p>
Defines the name of a dictionary module containing AVP
@@ -274,9 +268,8 @@ Example:</p>
</pre>
</item>
-<marker id="avp_types"/>
-
-<tag><c>@avp_types</c></tag>
+<tag>
+<marker id="avp_types"/><c>@avp_types</c></tag>
<item>
<p>
Defines the name, code, type and flags of individual AVPs.
@@ -308,9 +301,8 @@ The P flag has been deprecated by &the_rfc;.</p>
</item>
-<marker id="custom_types"/>
-
-<tag><c>@custom_types Mod</c></tag>
+<tag>
+<marker id="custom_types"/><c>@custom_types Mod</c></tag>
<item>
<p>
Specifies AVPs for which module Mod provides encode/decode functions.
@@ -331,9 +323,8 @@ Framed-IP-Address
</pre>
</item>
-<marker id="codecs"/>
-
-<tag><c>@codecs Mod</c></tag>
+<tag>
+<marker id="codecs"/><c>@codecs Mod</c></tag>
<item>
<p>
Like <c>@custom_types</c> but requires the specified module to export
@@ -350,9 +341,8 @@ Framed-IP-Address
</pre>
</item>
-<marker id="messages"/>
-
-<tag><c>@messages</c></tag>
+<tag>
+<marker id="messages"/><c>@messages</c></tag>
<item>
<p>
Defines the messages of the application.
@@ -397,9 +387,8 @@ RTA ::= &lt; Diameter Header: 287, PXY >
</item>
-<marker id="grouped"/>
-
-<tag><c>@grouped</c></tag>
+<tag>
+<marker id="grouped"/><c>@grouped</c></tag>
<item>
<p>
Defines the contents of the AVPs of the application having type
@@ -424,9 +413,8 @@ Specifying a Vendor-Id in the definition of a grouped AVP is
equivalent to specifying it with <c>@avp_vendor_id</c>.</p>
</item>
-<marker id="enum"/>
-
-<tag><c>@enum Name</c></tag>
+<tag>
+<marker id="enum"/><c>@enum Name</c></tag>
<item>
<p>
Defines values of AVP Name having type Enumerated.
@@ -452,9 +440,8 @@ REMOVE_SIP_SERVER 3
</pre>
</item>
-<marker id="end"/>
-
-<tag><c>@end</c></tag>
+<tag>
+<marker id="end"/><c>@end</c></tag>
<item>
<p>
Causes parsing of the dictionary to terminate:
diff --git a/lib/diameter/doc/src/diameter_examples.xml b/lib/diameter/doc/src/diameter_examples.xml
index 853ef96bb3..2e1f2b3c03 100644
--- a/lib/diameter/doc/src/diameter_examples.xml
+++ b/lib/diameter/doc/src/diameter_examples.xml
@@ -42,4 +42,3 @@ Example code can be found in the diameter application's
<c>examples</c> subdirectory.</p>
</chapter>
-
diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml
index 00ccc39c15..6ca280c52b 100644
--- a/lib/diameter/doc/src/diameter_tcp.xml
+++ b/lib/diameter/doc/src/diameter_tcp.xml
@@ -150,7 +150,7 @@ Options <c>binary</c>,
<c>packet</c> and <c>active</c> cannot be specified.
Also, option <c>port</c> can be specified for a listening transport
to specify the local listening port, the default being the standardized
-3868 if unspecified.
+3868.
Note that the option <c>ip</c> specifies the local address.</p>
<p>
diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml
index 736d4cbfbd..294e8a8864 100644
--- a/lib/diameter/doc/src/diameter_transport.xml
+++ b/lib/diameter/doc/src/diameter_transport.xml
@@ -65,9 +65,8 @@ parent).</p>
<taglist>
-<marker id="message"/>
-
-<tag><c>message() = binary() | &codec_packet;</c></tag>
+<tag>
+<marker id="message"/><c>message() = binary() | &codec_packet;</c></tag>
<item>
<p>
A Diameter message as passed over the transport interface.</p>
@@ -160,9 +159,9 @@ It should exit if its transport connection with its peer is lost.</p>
</funcs>
<!-- ===================================================================== -->
-<marker id="MESSAGES"/>
<section>
+<marker id="MESSAGES"/>
<title>MESSAGES</title>
<p>
@@ -234,7 +233,7 @@ established a connection with the peer.
Not sent if the transport process has <c>Type=connect</c>.</p>
</item>
-<tag><c>{diameter, {self(), connected, Remote}}</c></tag>
+<tag><c>{diameter, {self(), connected, Remote}}</c></tag><item/>
<tag><c>{diameter, {self(), connected, Remote, [LocalAddr]}}</c></tag>
<item>
<p>
diff --git a/lib/diameter/doc/src/diameterc.xml b/lib/diameter/doc/src/diameterc.xml
index 5bffe9a771..8f1c660989 100644
--- a/lib/diameter/doc/src/diameterc.xml
+++ b/lib/diameter/doc/src/diameterc.xml
@@ -11,7 +11,7 @@
<comref>
<header>
<copyright>
-<year>2011</year><year>2013</year>
+<year>2011</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -79,14 +79,14 @@ Write generated source to the specified directory.
Defaults to the current working directory.</p>
</item>
-<tag><![CDATA[-E]]></tag>
+<tag><![CDATA[-E]]></tag><item/>
<tag><![CDATA[-H]]></tag>
<item>
<p>
Suppress erl and hrl generation, respectively.</p>
</item>
-<tag><![CDATA[--name <name>]]></tag>
+<tag><![CDATA[--name <name>]]></tag><item/>
<tag><![CDATA[--prefix <prefix>]]></tag>
<item>
<p>
diff --git a/lib/diameter/examples/code/relay.erl b/lib/diameter/examples/code/relay.erl
index 3846b1d161..cf4ce8848b 100644
--- a/lib/diameter/examples/code/relay.erl
+++ b/lib/diameter/examples/code/relay.erl
@@ -53,7 +53,7 @@
{'Auth-Application-Id', [16#FFFFFFFF]},
{string_decode, false},
{application, [{alias, relay},
- {dictionary, diameter_relay},
+ {dictionary, diameter_gen_relay},
{module, relay_cb}]}]).
%% start/1
diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl
index b835e87967..3928769b5e 100644
--- a/lib/diameter/src/base/diameter_lib.erl
+++ b/lib/diameter/src/base/diameter_lib.erl
@@ -299,8 +299,28 @@ spawn_opts(server, Opts) ->
spawn_opts(worker, Opts) ->
opts(5000, Opts).
-opts(HeapSize, Opts) ->
- [{min_heap_size, HeapSize} | lists:keydelete(min_heap_size, 1, Opts)].
+%% These setting are historical rather than useful. In particular, the
+%% server setting can bloat many processes unnecessarily. Let them be
+%% disabled with -diameter min_heap_size false.
+
+opts(Def, Opts) ->
+ Key = min_heap_size,
+ case getenv(Key, Def) of
+ N when is_integer(N), 0 =< N ->
+ [{Key, N} | lists:keydelete(Key, 1, Opts)];
+ _ ->
+ Opts
+ end.
+
+%% getenv/1
+
+getenv(Key, Def) ->
+ case application:get_env(Key) of
+ {ok, T} ->
+ T;
+ undefined ->
+ Def
+ end.
%% ---------------------------------------------------------------------------
%% # wait/1
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index 2112941d5e..d93a3e71e3 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -123,8 +123,16 @@ peer_up(TPid) ->
%% ---------------------------------------------------------------------------
peer_down(TPid) ->
- ets:delete(?REQUEST_TABLE, TPid),
- failover(TPid).
+ ets:delete_object(?REQUEST_TABLE, {TPid}),
+ lists:foreach(fun failover/1, ets:lookup(?REQUEST_TABLE, TPid)).
+%% Note that a request process can store its request after failover
+%% notifications are sent here: insert_request/2 sends the notification
+%% in that case.
+
+%% failover/1
+
+failover({_TPid, {Pid, TRef}}) ->
+ Pid ! {failover, TRef}.
%% ---------------------------------------------------------------------------
%% incr/4
@@ -911,7 +919,7 @@ failed(Rec, FailedAvp, Dict) ->
{'Failed-AVP', [FailedAvp]}
catch
error: _ ->
- Avps = Dict:'get-'('AVP', Rec),
+ Avps = Dict:'#get-'('AVP', Rec),
A = #diameter_avp{name = 'Failed-AVP',
value = FailedAvp},
{'AVP', [A|Avps]}
@@ -1452,7 +1460,7 @@ make_request_packet(#diameter_packet{header = Hdr} = Pkt,
make_request_packet(Msg, Pkt) ->
Pkt#diameter_packet{msg = Msg}.
-%% make_retransmit_packet/2
+%% make_retransmit_packet/1
make_retransmit_packet(#diameter_packet{msg = [#diameter_header{} = Hdr
| Avps]}
@@ -1703,16 +1711,13 @@ send_request(TPid, #diameter_packet{bin = Bin} = Pkt, Req, _SvcName, Timeout)
when node() == node(TPid) ->
Seqs = diameter_codec:sequence_numbers(Bin),
TRef = erlang:start_timer(Timeout, self(), TPid),
- Entry = {Seqs, Req, TRef},
+ Entry = {Seqs, #request{handler = Pid} = Req, TRef},
- %% Ensure that request table is cleaned even if we receive an exit
- %% signal. An alternative would be to simply trap exits, but
- %% callbacks are applied in this process, and these could possibly
- %% be expecting the prevailing behaviour.
- Self = self(),
- spawn(fun() -> diameter_lib:wait([Self]), erase_request(Entry) end),
+ %% Ensure that request table is cleaned even if the process is
+ %% killed.
+ spawn(fun() -> diameter_lib:wait([Pid]), delete_request(Entry) end),
- store_request(Entry, TPid),
+ insert_request(Entry),
send(TPid, Pkt),
TRef;
@@ -1774,6 +1779,8 @@ retransmit({TPid, Caps, App}
SvcName,
Timeout,
[]).
+%% When sending a binary, it's up to prepare_retransmit to modify it
+%% accordingly.
retransmit({send, Msg},
Transport,
@@ -1818,15 +1825,21 @@ resend_request(Pkt0,
TRef = send_request(TPid, Pkt, Req, SvcName, Tmo),
{TRef, Req}.
-%% store_request/2
+%% insert_request/1
-store_request(T, TPid) ->
- ets:insert(?REQUEST_TABLE, T),
- ets:member(?REQUEST_TABLE, TPid)
- orelse begin
- {_Seqs, _Req, TRef} = T,
- self() ! {failover, TRef} %% failover/1 may have missed
- end.
+insert_request({_Seqs, #request{transport = TPid}, TRef} = T) ->
+ ets:insert(?REQUEST_TABLE, [T, {TPid, {self(), TRef}}]),
+ is_peer_up(TPid)
+ orelse (self() ! {failover, TRef}). %% failover/1 may have missed
+
+%% is_peer_up/1
+%%
+%% Is the entry written by peer_up/1 and deleted by peer_down/1 still
+%% in the request table?
+
+is_peer_up(TPid) ->
+ Spec = [{{TPid}, [], ['$_']}],
+ '$end_of_table' /= ets:select(?REQUEST_TABLE, Spec, 1).
%% lookup_request/2
%%
@@ -1846,16 +1859,11 @@ lookup_request(Msg, TPid) ->
false
end.
-%% erase_request/1
-
-erase_request(T) ->
- ets:delete_object(?REQUEST_TABLE, T).
-
-%% match_requests/1
+%% delete_request/1
-match_requests(TPid) ->
- Pat = {'_', #request{transport = TPid, _ = '_'}, '_'},
- ets:select(?REQUEST_TABLE, [{Pat, [], ['$_']}]).
+delete_request({_Seqs, #request{handler = Pid, transport = TPid}, TRef} = T) ->
+ Spec = [{R, [], [true]} || R <- [T, {TPid, {Pid, TRef}}]],
+ ets:select_delete(?REQUEST_TABLE, Spec).
%% have_request/2
@@ -1864,28 +1872,6 @@ have_request(Pkt, TPid) ->
Pat = {Seqs, #request{transport = TPid, _ = '_'}, '_'},
'$end_of_table' /= ets:select(?REQUEST_TABLE, [{Pat, [], ['$_']}], 1).
-%% ---------------------------------------------------------------------------
-%% # failover/1-2
-%% ---------------------------------------------------------------------------
-
-failover(TPid)
- when is_pid(TPid) ->
- lists:foreach(fun failover/1, match_requests(TPid));
-%% Note that a request process can store its request after failover
-%% notifications are sent here: store_request/2 sends the notification
-%% in that case.
-
-%% Failover as a consequence of peer_down/1: inform the
-%% request process.
-failover({_, Req, TRef}) ->
- #request{handler = Pid,
- packet = #diameter_packet{msg = M}}
- = Req,
- M /= undefined andalso (Pid ! {failover, TRef}).
-%% Failover is not performed when msg = binary() since sending
-%% pre-encoded binaries is only partially supported. (Mostly for
-%% test.)
-
%% get_destination/2
get_destination(Dict, Msg) ->
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index cdaa9aa7f9..4007d6b7b1 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -790,20 +790,7 @@ header() ->
("%% -------------------------------------------------------------------\n"
"%% This is a generated file.\n"
"%% -------------------------------------------------------------------\n"
- "\n"
- "%%\n"
- "%% Copyright (c) Ericsson AB. All rights reserved.\n"
- "%%\n"
- "%% The information in this document is the property of Ericsson.\n"
- "%%\n"
- "%% Except as specifically authorized in writing by Ericsson, the\n"
- "%% receiver of this document shall keep the information contained\n"
- "%% herein confidential and shall protect the same in whole or in\n"
- "%% part from disclosure and dissemination to third parties.\n"
- "%%\n"
- "%% Disclosure and disseminations to the receivers employees shall\n"
- "%% only be made on a strict need to know basis.\n"
- "%%\n\n").
+ "\n").
hrl_header(Name) ->
header() ++ "-hrl_name('" ++ ?S(Name) ++ ".hrl').\n".
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index 618d5a7f10..b1b8e38d39 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -49,7 +49,11 @@
{"1.10", [{restart_application, diameter}]}, %% 18.0
{"1.11", [{restart_application, diameter}]}, %% 18.1
{"1.11.1", [{restart_application, diameter}]}, %% 18.2
- {"1.11.2", [{restart_application, diameter}]} %% 18.3
+ {"1.11.2", [{restart_application, diameter}]}, %% 18.3
+ {"1.12", [{load_module, diameter_lib}, %% 19.0
+ {load_module, diameter_traffic},
+ {load_module, diameter_tcp},
+ {load_module, diameter_sctp}]}
],
[
{"0.9", [{restart_application, diameter}]},
@@ -80,6 +84,10 @@
{"1.10", [{restart_application, diameter}]},
{"1.11", [{restart_application, diameter}]},
{"1.11.1", [{restart_application, diameter}]},
- {"1.11.2", [{restart_application, diameter}]}
+ {"1.11.2", [{restart_application, diameter}]},
+ {"1.12", [{load_module, diameter_sctp},
+ {load_module, diameter_tcp},
+ {load_module, diameter_traffic},
+ {load_module, diameter_lib}]}
]
}.
diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl
index 4a005b853d..f48e4347ee 100644
--- a/lib/diameter/src/transport/diameter_sctp.erl
+++ b/lib/diameter/src/transport/diameter_sctp.erl
@@ -98,7 +98,7 @@
-record(listener,
{ref :: reference(),
socket :: gen_sctp:sctp_socket(),
- count = 0 :: uint(), %% attached transport processes
+ service = false :: false | pid(), %% service process
pending = {0, queue:new()},
accept :: [match()]}).
%% Field pending implements two queues: the first of transport-to-be
@@ -129,11 +129,14 @@
-> {ok, pid(), [inet:ip_address()]}
when Ref :: diameter:transport_ref().
-start(T, #diameter_service{capabilities = Caps}, Opts)
+start(T, Svc, Opts)
when is_list(Opts) ->
+ #diameter_service{capabilities = Caps,
+ pid = SPid}
+ = Svc,
diameter_sctp_sup:start(), %% start supervisors on demand
Addrs = Caps#diameter_caps.host_ip_address,
- s(T, Addrs, lists:map(fun ip/1, Opts)).
+ s(T, Addrs, SPid, lists:map(fun ip/1, Opts)).
ip({ifaddr, A}) ->
{ip, A};
@@ -144,18 +147,22 @@ ip(T) ->
%% when there is not yet an association to assign it, or at comm_up on
%% a new association in which case the call retrieves a transport from
%% the pending queue.
-s({accept, Ref} = A, Addrs, Opts) ->
- {LPid, LAs} = listener(Ref, {Opts, Addrs}),
- try gen_server:call(LPid, {A, self()}, infinity) of
- {ok, TPid} -> {ok, TPid, LAs}
+s({accept, Ref} = A, Addrs, SPid, Opts) ->
+ {ok, LPid, LAs} = listener(Ref, {Opts, Addrs}),
+ try gen_server:call(LPid, {A, self(), SPid}, infinity) of
+ {ok, TPid} ->
+ {ok, TPid, LAs};
+ No ->
+ {error, No}
catch
- exit: Reason -> {error, Reason}
+ exit: Reason ->
+ {error, Reason}
end;
%% This implementation is due to there being no accept call in
%% gen_sctp in order to be able to accept a new association only
%% *after* an accepting transport has been spawned.
-s({connect = C, Ref}, Addrs, Opts) ->
+s({connect = C, Ref}, Addrs, _SPid, Opts) ->
diameter_sctp_sup:start_child({C, self(), Opts, Addrs, Ref}).
%% start_link/1
@@ -281,24 +288,23 @@ i({K, Ref}, #transport{mode = {accept, _}} = S) ->
%% Accepting processes can be started concurrently: ensure only one
%% listener is started.
-listener(LRef, T) ->
- diameter_sync:call({?MODULE, listener, LRef},
- {?MODULE, listener, [{LRef, T}]},
+listener(Ref, T) ->
+ diameter_sync:call({?MODULE, listener, Ref},
+ {?MODULE, listener, [{Ref, T}]},
infinity,
infinity).
-listener({LRef, T}) ->
- l(diameter_reg:match({?MODULE, listener, {LRef, '_'}}), LRef, T).
+listener({Ref, T}) ->
+ l(diameter_reg:match({?MODULE, listener, {Ref, '_'}}), Ref, T).
%% Existing listening process ...
l([{{?MODULE, listener, {_, AS}}, LPid}], _, _) ->
- {LAs, _Sock} = AS,
- {LPid, LAs};
+ {LAs, _Sock} = AS,
+ {ok, LPid, LAs};
%% ... or not.
-l([], LRef, T) ->
- {ok, LPid, LAs} = diameter_sctp_sup:start_child({listen, LRef, T}),
- {LPid, LAs}.
+l([], Ref, T) ->
+ diameter_sctp_sup:start_child({listen, Ref, T}).
%% open/3
@@ -364,11 +370,17 @@ type(T) ->
%% # handle_call/3
%% ---------------------------------------------------------------------------
-handle_call({{accept, Ref}, Pid}, _, #listener{ref = Ref,
- count = K}
- = S) ->
+handle_call({{accept, Ref}, Pid}, _, #listener{ref = Ref} = S) ->
{TPid, NewS} = accept(Ref, Pid, S),
- {reply, {ok, TPid}, NewS#listener{count = K+1}};
+ {reply, {ok, TPid}, NewS};
+
+handle_call({{accept, _} = T, Pid, SPid}, From, #listener{service = P} = S) ->
+ handle_call({T, Pid}, From, if not is_pid(P), is_pid(SPid) ->
+ monitor(process, SPid),
+ S#listener{service = SPid};
+ true ->
+ S
+ end);
handle_call(_, _, State) ->
{reply, nok, State}.
@@ -441,6 +453,13 @@ l({sctp, Sock, _RA, _RP, Data} = T, #listener{socket = Sock,
setopts(Sock),
NewS;
+%% Service process has died.
+l({'DOWN', _, process, Pid, _} = T, #listener{service = Pid,
+ socket = Sock}) ->
+ gen_sctp:close(Sock),
+ x(T);
+
+%% Accepting process has died.
l({'DOWN', _MRef, process, TPid, _}, #listener{pending = {_,Q}} = S) ->
down(queue:member(TPid, Q), TPid, S);
@@ -454,20 +473,17 @@ l({transport, remove, _} = T, #listener{socket = Sock}) ->
%% Accepting transport has died.
%% One that's waiting for transport start in the pending queue ...
-down(true, TPid, #listener{pending = {N,Q},
- count = K}
- = S) ->
+down(true, TPid, #listener{pending = {N,Q}} = S) ->
NQ = queue:filter(fun(P) -> P /= TPid end, Q),
if N < 0 -> %% awaiting an association ...
- S#listener{count = K-1,
- pending = {N+1, NQ}};
+ S#listener{pending = {N+1, NQ}};
true -> %% ... or one has been assigned
S#listener{pending = {N-1, NQ}}
end;
%% ... or one that's already attached.
-down(false, _TPid, #listener{count = K} = S) ->
- S#listener{count = K-1}.
+down(false, _TPid, S) ->
+ S.
%% t/2
%%
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index 546c2cfa5e..44abc5c3b4 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -71,11 +71,8 @@
%% a process owning the listening port.
%% Listener process state.
--record(listener, {socket :: inet:socket(),
- count = 1 :: non_neg_integer()}). %% accepting processes
-%% The count of accepting processes was previously used to terminate
-%% the listening process, but diameter_reg:subscribe/2 is now used for
-%% this. Leave the the count for trace purposes.
+-record(listener, {socket :: inet:socket(),
+ service = false :: false | pid()}). %% service process
%% Monitor process state.
-record(monitor,
@@ -138,11 +135,15 @@
| {ok, pid()}
when Ref :: diameter:transport_ref().
-start({T, Ref}, #diameter_service{capabilities = Caps}, Opts) ->
+start({T, Ref}, Svc, Opts) ->
+ #diameter_service{capabilities = Caps,
+ pid = SPid}
+ = Svc,
+
diameter_tcp_sup:start(), %% start tcp supervisors on demand
{Mod, Rest} = split(Opts),
Addrs = Caps#diameter_caps.host_ip_address,
- Arg = {T, Ref, Mod, self(), Rest, Addrs},
+ Arg = {T, Ref, Mod, self(), Rest, Addrs, SPid},
diameter_tcp_sup:start_child(Arg).
split([{module, M} | Opts]) ->
@@ -196,7 +197,7 @@ init(T) ->
%% i/1
%% A transport process.
-i({T, Ref, Mod, Pid, Opts, Addrs})
+i({T, Ref, Mod, Pid, Opts, Addrs, SPid})
when T == accept;
T == connect ->
monitor(process, Pid),
@@ -214,7 +215,7 @@ i({T, Ref, Mod, Pid, Opts, Addrs})
?DEFAULT_FRAGMENT_TIMEOUT),
?IS_TIMEOUT(Tmo) orelse ?ERROR({fragment_timer, Tmo}),
Throttle = proplists:get_value(throttle_cb, OwnOpts, false),
- Sock = init(T, Ref, Mod, Pid, SslOpts, Rest, Addrs),
+ Sock = init(T, Ref, Mod, Pid, SslOpts, Rest, Addrs, SPid),
MPid ! {stop, self()}, %% tell the monitor to die
M = if SslOpts -> ssl; true -> Mod end,
putr(?REF_KEY, Ref),
@@ -228,6 +229,11 @@ i({T, Ref, Mod, Pid, Opts, Addrs})
%% Put the reference in the process dictionary since we now use it
%% advertise the ssl socket after TLS upgrade.
+i({T, _Ref, _Mod, _Pid, _Opts, _Addrs} = Arg) %% from old code
+ when T == accept;
+ T == connect ->
+ i(erlang:append_element(Arg, _SPid = false));
+
%% A monitor process to kill the transport if the parent dies.
i(#monitor{parent = Pid, transport = TPid} = S) ->
proc_lib:init_ack({ok, self()}),
@@ -240,16 +246,18 @@ i(#monitor{parent = Pid, transport = TPid} = S) ->
%% death. However, a link can be unlinked and this is exactly what
%% gen_tcp seems to so. Links should be left to supervisors.
-i({listen, LRef, APid, {Mod, Opts, Addrs}}) ->
- [_] = diameter_config:subscribe(LRef, transport), %% assert existence
+i({listen = L, Ref, _APid, T}) -> %% from old code
+ i({L, Ref, T});
+
+i({listen, Ref, {Mod, Opts, Addrs}}) ->
+ [_] = diameter_config:subscribe(Ref, transport), %% assert existence
{[LA, LP], Rest} = proplists:split(Opts, [ip, port]),
LAddrOpt = get_addr(LA, Addrs),
LPort = get_port(LP),
{ok, LSock} = Mod:listen(LPort, gen_opts(LAddrOpt, Rest)),
LAddr = laddr(LAddrOpt, Mod, LSock),
- true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}),
+ true = diameter_reg:add_new({?MODULE, listener, {Ref, {LAddr, LSock}}}),
proc_lib:init_ack({ok, self(), {LAddr, LSock}}),
- monitor(process, APid),
#listener{socket = LSock}.
laddr([], Mod, Sock) ->
@@ -268,21 +276,22 @@ ssl_opts([{ssl_options, Opts}])
ssl_opts(T) ->
?ERROR({ssl_options, T}).
-%% init/7
+%% init/8
%% Establish a TLS connection before capabilities exchange ...
-init(Type, Ref, Mod, Pid, true, Opts, Addrs) ->
- init(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs);
+init(Type, Ref, Mod, Pid, true, Opts, Addrs, SPid) ->
+ init(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs, SPid);
%% ... or not.
-init(Type, Ref, Mod, Pid, _, Opts, Addrs) ->
- init(Type, Ref, Mod, Pid, Opts, Addrs).
+init(Type, Ref, Mod, Pid, _, Opts, Addrs, SPid) ->
+ init(Type, Ref, Mod, Pid, Opts, Addrs, SPid).
-%% init/6
+%% init/7
-init(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
+init(accept = T, Ref, Mod, Pid, Opts, Addrs, SPid) ->
{[Matches], Rest} = proplists:split(Opts, [accept]),
- {LAddr, LSock} = listener(Ref, {Mod, Rest, Addrs}),
+ {ok, LPid, {LAddr, LSock}} = listener(Ref, {Mod, Rest, Addrs}),
+ ok = gen_server:call(LPid, {accept, SPid}, infinity),
proc_lib:init_ack({ok, self(), [LAddr]}),
Sock = ok(accept(Mod, LSock)),
ok = accept_peer(Mod, Sock, accept(Matches)),
@@ -290,7 +299,7 @@ init(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
diameter_peer:up(Pid),
Sock;
-init(connect = T, Ref, Mod, Pid, Opts, Addrs) ->
+init(connect = T, Ref, Mod, Pid, Opts, Addrs, _SPid) ->
{[LA, RA, RP], Rest} = proplists:split(Opts, [ip, raddr, rport]),
LAddrOpt = get_addr(LA, Addrs),
RAddr = get_addr(RA),
@@ -344,24 +353,26 @@ accept(Opts) ->
%% Accepting processes can be started concurrently: ensure only one
%% listener is started.
-listener(LRef, T) ->
- diameter_sync:call({?MODULE, listener, LRef},
- {?MODULE, listener, [{LRef, T, self()}]},
+listener(Ref, T) ->
+ diameter_sync:call({?MODULE, listener, Ref},
+ {?MODULE, listener, [{Ref, T, self()}]},
infinity,
infinity).
-listener({LRef, T, TPid}) ->
- l(diameter_reg:match({?MODULE, listener, {LRef, '_'}}), LRef, T, TPid).
+%% listener/1
+
+listener({Ref, T, _TPid}) ->
+ l(diameter_reg:match({?MODULE, listener, {Ref, '_'}}), Ref, T).
+
+%% l/3
%% Existing listening process ...
-l([{{?MODULE, listener, {_, AS}}, LPid}], _, _, TPid) ->
- LPid ! {accept, TPid},
- AS;
+l([{{?MODULE, listener, {_, AS}}, LPid}], _, _) ->
+ {ok, LPid, AS};
%% ... or not.
-l([], LRef, T, TPid) ->
- {ok, _, AS} = diameter_tcp_sup:start_child({listen, LRef, TPid, T}),
- AS.
+l([], Ref, T) ->
+ diameter_tcp_sup:start_child({listen, Ref, T}).
%% get_addr/1
@@ -440,6 +451,14 @@ portnr(Sock) ->
%% # handle_call/3
%% ---------------------------------------------------------------------------
+handle_call({accept, SPid}, _From, #listener{service = P} = S) ->
+ {reply, ok, if not is_pid(P), is_pid(SPid) ->
+ monitor(process, SPid),
+ S#listener{service = SPid};
+ true ->
+ S
+ end};
+
handle_call(_, _, State) ->
{reply, nok, State}.
@@ -507,19 +526,20 @@ m({'DOWN', _, process, Pid, _}, #monitor{parent = Pid,
%%
%% Transition listener state.
-%% An accepting transport is attaching.
-l({accept, TPid}, #listener{count = N} = S) ->
- monitor(process, TPid),
- S#listener{count = N+1};
-
-%% Accepting process has died.
-l({'DOWN', _, process, _, _}, #listener{count = N} = S) ->
- S#listener{count = N-1};
+%% Service process has died.
+l({'DOWN', _, process, Pid, _} = T, #listener{service = Pid,
+ socket = Sock}) ->
+ gen_tcp:close(Sock),
+ x(T);
%% Transport has been removed.
l({transport, remove, _} = T, #listener{socket = Sock}) ->
gen_tcp:close(Sock),
- x(T).
+ x(T);
+
+%% Possibly death of an accepting process monitored in old code.
+l(_, S) ->
+ S.
%% t/2
%%
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 6f3a4801ee..4c82d4dee2 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -248,17 +248,14 @@ all() ->
groups() ->
Ts = tc(),
Sctp = ?util:have_sctp(),
- [{?util:name([R,D,A,C]), [parallel], Ts} || R <- ?ENCODINGS,
- D <- ?RFCS,
- A <- ?ENCODINGS,
- C <- ?CONTAINERS]
+ [{B, [P], Ts} || {B,P} <- [{true, shuffle}, {false, parallel}]]
++
[{?util:name([T,R,D,A,C,SD,CD]),
[],
[start_services,
add_transports,
result_codes,
- {group, ?util:name([R,D,A,C])},
+ {group, SD orelse CD},
remove_transports,
stop_services]}
|| T <- ?TRANSPORTS,
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index cb750c69a3..23219950bb 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -17,5 +17,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 1.12
+DIAMETER_VSN = 1.12.1
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)