diff options
author | Anders Svensson <[email protected]> | 2016-09-12 22:32:00 +0200 |
---|---|---|
committer | Anders Svensson <[email protected]> | 2016-09-12 22:32:00 +0200 |
commit | 564aaba04228da215e560027eaa7963d86454ad0 (patch) | |
tree | 8bdd7c847a810492876e1fbc48d51a429e458965 /lib | |
parent | 437bf798d86b85a0c81bb92b730440890b9ea92a (diff) | |
parent | 58cc6bb63216d66975b8b9a895c0596925a8571d (diff) | |
download | otp-564aaba04228da215e560027eaa7963d86454ad0.tar.gz otp-564aaba04228da215e560027eaa7963d86454ad0.tar.bz2 otp-564aaba04228da215e560027eaa7963d86454ad0.zip |
Merge branch 'maint'
Diffstat (limited to 'lib')
-rw-r--r-- | lib/diameter/doc/src/diameter.xml | 155 | ||||
-rw-r--r-- | lib/diameter/doc/src/diameter_app.xml | 39 | ||||
-rw-r--r-- | lib/diameter/doc/src/diameter_codec.xml | 56 | ||||
-rw-r--r-- | lib/diameter/doc/src/diameter_dict.xml | 69 | ||||
-rw-r--r-- | lib/diameter/doc/src/diameter_examples.xml | 1 | ||||
-rw-r--r-- | lib/diameter/doc/src/diameter_tcp.xml | 2 | ||||
-rw-r--r-- | lib/diameter/doc/src/diameter_transport.xml | 9 | ||||
-rw-r--r-- | lib/diameter/doc/src/diameterc.xml | 6 | ||||
-rw-r--r-- | lib/diameter/examples/code/relay.erl | 2 | ||||
-rw-r--r-- | lib/diameter/src/base/diameter_lib.erl | 24 | ||||
-rw-r--r-- | lib/diameter/src/base/diameter_traffic.erl | 88 | ||||
-rw-r--r-- | lib/diameter/src/compiler/diameter_codegen.erl | 15 | ||||
-rw-r--r-- | lib/diameter/src/diameter.appup.src | 12 | ||||
-rw-r--r-- | lib/diameter/src/transport/diameter_sctp.erl | 76 | ||||
-rw-r--r-- | lib/diameter/src/transport/diameter_tcp.erl | 104 | ||||
-rw-r--r-- | lib/diameter/test/diameter_traffic_SUITE.erl | 7 | ||||
-rw-r--r-- | lib/diameter/vsn.mk | 2 |
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() = 0..255</c></tag> -<tag><c>uint24() = 0..16777215</c></tag> +<tag> +<marker id="integers"/><c>uint8() = 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 ::= < 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) |