<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="amqp.xsl"?>

<!--
  Copyright Notice
  ================
  (c) Copyright Bank of America, N.A., Barclays Bank PLC, Cisco Systems, Credit Suisse, Deutsche
  Boerse, Envoy Technologies Inc., Goldman Sachs, HCL Technologies Ltd, IIT Software GmbH, iMatix
  Corporation, INETCO Systems Limited, Informatica Corporation, JPMorgan Chase & Co., Kaazing
  Corporation, N.A, Microsoft Corporation, my-Channels, Novell, Progress Software, Red Hat Inc.,
  Software AG, Solace Systems Inc., StormMQ Ltd., Tervela Inc., TWIST Process Innovations Ltd,
  VMware, Inc., and WS02 Inc.
  2006-2011. All rights reserved.

  License
  =======

  Bank of America, N.A., Barclays Bank PLC, Cisco Systems, Credit Suisse, Deutsche Boerse, Goldman
  Sachs, HCL Technologies Ltd, IIT Software GmbH, INETCO Systems Limited, Informatica Corporation,
  JPMorgan Chase & Co., Kaazing Corporation, N.A, Microsoft Corporation, my-Channels, Novell,
  Progress Software, Red Hat Inc., Software AG, Solace Systems Inc., StormMQ Ltd., Tervela Inc.,
  TWIST Process Innovations Ltd, VMware, Inc., and WS02 Inc. (collectively, the "Authors") each
  hereby grants to you a worldwide, perpetual, royalty-free, nontransferable, nonexclusive license
  to (i) copy, display, distribute and implement the Advanced Message Queuing Protocol ("AMQP")
  Specification and (ii) the Licensed Claims that are held by the Authors, all for the purpose of
  implementing the Advanced Message Queuing Protocol Specification. Your license and any rights
  under this Agreement will terminate immediately without notice from any Author if you bring any
  claim, suit, demand, or action related to the Advanced Message Queuing Protocol Specification
  against any Author. Upon termination, you shall destroy all copies of the Advanced Message Queuing
  Protocol Specification in your possession or control.

  As used hereunder, "Licensed Claims" means those claims of a patent or patent application,
  throughout the world, excluding design patents and design registrations, owned or controlled, or
  that can be sublicensed without fee and in compliance with the requirements of this Agreement, by
  an Author or its affiliates now or at any future time and which would necessarily be infringed by
  implementation of the Advanced Message Queuing Protocol Specification. A claim is necessarily
  infringed hereunder only when it is not possible to avoid infringing it because there is no
  plausible non-infringing alternative for implementing the required portions of the Advanced
  Message Queuing Protocol Specification. Notwithstanding the foregoing, Licensed Claims shall not
  include any claims other than as set forth above even if contained in the same patent as Licensed
  Claims; or that read solely on any implementations of any portion of the Advanced Message Queuing
  Protocol Specification that are not required by the Advanced Message Queuing Protocol
  Specification, or that, if licensed, would require a payment of royalties by the licensor to
  unaffiliated third parties. Moreover, Licensed Claims shall not include (i) any enabling
  technologies that may be necessary to make or use any Licensed Product but are not themselves
  expressly set forth in the Advanced Message Queuing Protocol Specification (e.g., semiconductor
  manufacturing technology, compiler technology, object oriented technology, networking technology,
  operating system technology, and the like); or (ii) the implementation of other published
  standards developed elsewhere and merely referred to in the body of the Advanced Message Queuing
  Protocol Specification, or (iii) any Licensed Product and any combinations thereof the purpose or
  function of which is not required for compliance with the Advanced Message Queuing Protocol
  Specification. For purposes of this definition, the Advanced Message Queuing Protocol
  Specification shall be deemed to include both architectural and interconnection requirements
  essential for interoperability and may also include supporting source code artifacts where such
  architectural, interconnection requirements and source code artifacts are expressly identified as
  being required or documentation to achieve compliance with the Advanced Message Queuing Protocol
  Specification.

  As used hereunder, "Licensed Products" means only those specific portions of products (hardware,
  software or combinations thereof) that implement and are compliant with all relevant portions of
  the Advanced Message Queuing Protocol Specification.

  The following disclaimers, which you hereby also acknowledge as to any use you may make of the
  Advanced Message Queuing Protocol Specification:

  THE ADVANCED MESSAGE QUEUING PROTOCOL SPECIFICATION IS PROVIDED "AS IS," AND THE AUTHORS MAKE NO
  REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS
  OF THE ADVANCED MESSAGE QUEUING PROTOCOL SPECIFICATION ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE
  IMPLEMENTATION OF THE ADVANCED MESSAGE QUEUING PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD
  PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.

  THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
  DAMAGES ARISING OUT OF OR RELATING TO ANY USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED
  MESSAGE QUEUING PROTOCOL SPECIFICATION.

  The name and trademarks of the Authors may NOT be used in any manner, including advertising or
  publicity pertaining to the Advanced Message Queuing Protocol Specification or its contents
  without specific, written prior permission. Title to copyright in the Advanced Message Queuing
  Protocol Specification will at all times remain with the Authors.

  No other rights are granted by implication, estoppel or otherwise.

  Upon termination of your license or rights under this Agreement, you shall destroy all copies of
  the Advanced Message Queuing Protocol Specification in your possession or control.

  Trademarks
  ==========
  "JPMorgan", "JPMorgan Chase", "Chase", the JPMorgan Chase logo and the Octagon Symbol are
  trademarks of JPMorgan Chase & Co.

  RED HAT is a registered trademarks of Red Hat, Inc. in the US and other countries.

  Other company, product, or service names may be trademarks or service marks of others.

  Link to full AMQP specification:
  =================================
  http://www.amqp.org/confluence/display/AMQP/AMQP+Specification
-->

<!DOCTYPE amqp SYSTEM "amqp.dtd">

<amqp xmlns="http://www.amqp.org/schema/amqp.xsd"
      name="transport" label="working version">

  <!-- == Section: transport =================================================================== -->

  <section name="transport" label="transport overview">
    <doc>
      <p>
        The AMQP Network consists of <term>Nodes</term> connected via <term>Links</term>. Nodes are
        named entities responsible for the safe storage and/or delivery of <term>Messages</term>.
        Messages can originate from, terminate at, or be relayed by Nodes.
      </p>

      <p>
        A Link is a unidirectional route between two Nodes. Links attach to a Node at
        a <term>Terminus</term>. There are two kinds of Terminus: <term>Sources</term>
        and <term>Targets</term>. A Terminus is responsible for tracking the state of a particular
        stream of incoming or outgoing messages. Sources track outgoing messages and Targets track
        incoming messages. Messages may only travel along a Link if they meet the entry criteria at
        the Source.
      </p>

      <p>
        As a Message travels through the AMQP network, the responsibility for safe storage and
        delivery of the Message is transferred between the Nodes it encounters. The Link Protocol
        (defined in <xref name="links"/> ) manages the transfer of responsibility between the Source
        and Target.
      </p>

      <picture>
        <![CDATA[
  +------------+                             +------------+
 /    Node A    \                           /    Node B    \
+----------------+    +--filter            +----------------+
|                |   /                     |                |
|  MSG_3 <MSG_1> | _/                    _ |         MSG_1  |
|                |(_)------------------>(_)|                |
| <MSG_2> MSG_4  | |                     | |  MSG_2         |
|                | |    Link(Src,Tgt)    | |                |
+----------------+ |                     | +----------------+
                   |                     |
                  Src                   Tgt


            Key: <MSG_n> = old location of MSG_n
]]>
      </picture>

      <p>
        Nodes exist within a <term>Container</term>, and each Container may hold many Nodes.
        Examples of AMQP Nodes are Producers, Consumers, and Queues. Producers and Consumers are the
        elements within a client Application that generate and process Messages. Queues are entities
        within a Broker that store and forward Messages. Examples of containers are Brokers and
        Client Applications.
      </p>

      <picture>
        <![CDATA[
   +---------------+                       +----------+
   | <<Container>> | 1..1             0..n | <<Node>> |
   |---------------|<>-------------------->|----------|
   | container-id  |                       | name     |
   +---------------+                       +----------+
          /_\                                   /_\
           |                                     |
           |                                     |
     +-----+-----+                    +----------+----------+
     |           |                    |          |          |
     |           |                    |          |          |
+--------+  +--------+        +----------+  +----------+  +-------+
| Broker |  | Client |        | Producer |  | Consumer |  | Queue |
|--------|  |--------|        |----------|  |----------|  |-------|
|        |  |        |        |          |  |          |  |       |
+--------+  +--------+        +----------+  +----------+  +-------+
]]>
      </picture>

      <p>
        The AMQP Transport Specification defines a peer-to-peer protocol for transferring Messages
        between Nodes in the AMQP network. This portion of the specification is not concerned with
        the internal workings of any sort of Node, and only deals with the mechanics of
        unambiguously transferring a Message from one Node to another.
      </p>

      <p>
        Containers communicate via <term>Connections</term>. An AMQP Connection consists of a
        full-duplex, reliably ordered sequence of <term>Frames</term>. The precise requirement for a
        Connection is that if the n<sup>th</sup> Frame arrives, all Frames prior to n MUST also have
        arrived. It is assumed Connections are transient and may fail for a variety of reasons
        resulting in the loss of an unknown number of frames, but they are still subject to the
        aforementioned ordered reliability criteria. This is similar to the guarantee that TCP or
        SCTP provides for byte streams, and the specification defines a framing system used to parse
        a byte stream into a sequence of Frames for use in establishing an AMQP Connection (see
        <xref name="framing"/>).
      </p>

      <p>
        An AMQP Connection is divided into a negotiated number of independent unidirectional
        <term>Channels</term>. Each Frame is marked with the Channel number indicating its parent
        Channel, and the Frame sequence for each Channel is multiplexed into a single Frame sequence
        for the Connection.
      </p>

      <p>
        An AMQP <term>Session</term> correlates two unidirectional Channels to form a bidirectional,
        sequential conversation between two Containers. A single Connection may have multiple
        independent Sessions active simultaneously, up to the negotiated Channel limit. Both
        Connections and Sessions are modeled by each peer as <term>endpoints</term> that store local
        and last known remote state regarding the Connection or Session in question.
      </p>

      <picture title="Session &amp; Connection Endpoints">
        <![CDATA[
    Session<------+                           +------>Session
(ICH=1, OCH=1)    |                           |    (ICH=1, OCH=1)
                 \|/                         \|/
    Session<--> Connection <---------> Connection <-->Session
(ICH=2, OCH=3)   /|\                         /|\   (ICH=3, OCH=2)
                  |                           |
    Session<------+                           +------>Session
(ICH=3, OCH=2)                                     (ICH=2, OCH=3)

        Key: ICH -> Input Channel, OCH -> Output Channel
]]>
      </picture>

      <p>
        Sessions provide the context for communication between Sources and Targets. A <term>Link
        Endpoint</term> associates a Terminus with a <term>Session Endpoint</term>. Within a
        Session, the Link Protocol (defined in <xref name="links"/>) is used to establish Links
        between Sources and Targets and to transfer Messages across them. A single Session may be
        simultaneously associated with any number of Links.
      </p>

      <picture><![CDATA[
+-------------+
|    Link     |  Message Transport
+-------------+  (Node to Node)
| name        |
| source      |
| target      |
| timeout     |
+-------------+
     /|\ 0..n
      |
      |
      |
     \|/ 0..1
+------------+
|  Session   |  Frame Transport
+------------+  (Container to Container)
| name       |
+------------+
     /|\ 0..n
      |
      |
      |
     \|/ 1..1
+------------+
| Connection |  Frame Transport
+------------+  (Container to Container)
| principal  |
+------------+
]]>
      </picture>

      <p>
        A Frame is the unit of work carried on the wire. Connections have a negotiated maximum frame
        size allowing byte streams to be easily defragmented into complete frame bodies representing
        the independently parsable units formally defined in <xref name="performatives"/>. The
        following table lists all frame bodies and defines which endpoints handle them.
      </p>

      <picture><![CDATA[
Frame          Connection  Session  Link
========================================
open               H
begin              I          H
attach                        I      H
flow                          I      H
transfer                      I      H
disposition                   I      H
detach                        I      H
end                I          H
close              H
----------------------------------------

Key:
     H: handled by the endpoint

     I: intercepted (endpoint examines
        the frame, but delegates
        further processing to another
        endpoint)
]]>
      </picture>
    </doc>
  </section>

  <section name="version-negotiation" title="Version Negotiation"
           label="definition of version negotiation steps">
    <doc >
      <p>
        Prior to sending any Frames on a Connection, each peer MUST start by sending a protocol
        header that indicates the protocol version used on the Connection. The protocol header
        consists of the upper case ASCII letters "AMQP" followed by a protocol id of zero, followed
        by three unsigned bytes representing the major, minor, and revision of the protocol version
        (currently <xref name="MAJOR"/>, <xref name="MINOR"/>, <xref name="REVISION"/>). In total
        this is an 8-octet sequence:
      </p>

      <picture><![CDATA[
  4 OCTETS   1 OCTET   1 OCTET   1 OCTET   1 OCTET
+----------+---------+---------+---------+----------+
|  "AMQP"  |   %d0   |  major  |  minor  | revision |
+----------+---------+---------+---------+----------+
]]>
      </picture>

      <p>
        Any data appearing beyond the protocol header MUST match the version indicated by the
        protocol header. If the incoming and outgoing protocol headers do not match, both peers MUST
        close their outgoing stream and SHOULD read the incoming stream until it is terminated.
      </p>

      <p>
        The AMQP peer which acted in the role of the TCP client (i.e. the peer that opened the
        Connection) MUST immediately send its outgoing protocol header on establishment of the TCP
        Session. The AMQP peer which acted in the role of the TCP server MAY elect to wait until
        receiving the incoming protocol header before sending its own outgoing protocol header.
      </p>

      <p>
        Two AMQP peers agree on a protocol version as follows (where the words "client" and
        "server" refer to the roles being played by the peers at the TCP Connection level):
      </p>

      <ul>
        <li>
          <p>
            When the client opens a new socket Connection to a server, it MUST send a protocol
            header with the client's preferred protocol version.
          </p>
        </li>

        <li>
          <p>
            If the requested protocol version is supported, the server MUST send its own protocol
            header with the requested version to the socket, and then proceed according to the
            protocol definition.
          </p>
        </li>

        <li>
          <p>
            If the requested protocol version is <b>not</b> supported, the server MUST send a
            protocol header with a <b>supported</b> protocol version and then close the socket.
          </p>
        </li>

        <li>
          <p>
            When choosing a protocol version to respond with, the server SHOULD choose the highest
            supported version that is less than or equal to the requested version. If no such
            version exists, the server SHOULD respond with the highest supported version.
          </p>
        </li>

        <li>
          <p>
            If the server can't parse the protocol header, the server MUST send a valid protocol
            header with a supported protocol version and then close the socket.
          </p>
        </li>
      </ul>

      <p>
        Based on this behavior a client can discover which protocol versions a server supports by
        attempting to connect with its highest supported version and reconnecting with a version
        less than or equal to the version received back from the server.
      </p>

      <picture title="Version Negotiation Examples"><![CDATA[
TCP Client                               TCP Server
======================================================
AMQP%d0.1.0.0       ------------->
                    <-------------       AMQP%d0.1.0.0 (1)
                          ...            *proceed*

AMQP%d0.1.1.0       ------------->
                    <-------------       AMQP%d0.1.0.0 (2)
                                         *TCP CLOSE*

HTTP                ------------->
                    <-------------       AMQP%d0.1.0.0 (3)
                                         *TCP CLOSE*
------------------------------------------------------
  (1) Server accepts Connection for: AMQP, protocol=0,
      major=1, minor=0, revision=0

  (2) Server rejects Connection for: AMQP, protocol=0,
      major=1, minor=1, revision=0, Server responds
      that it supports: AMQP, protocol=0, major=1,
      minor=0, revision=0

  (3) Server rejects Connection for: HTTP. Server
      responds it supports: AMQP, protocol=0, major=1,
       minor=0, revision=0
 ]]>
      </picture>

      <p>
        Please note that the above examples use the literal notation defined in RFC 2234 for non
        alphanumeric values.
      </p>

      <p>
        The protocol id is not a part of the protocol version and thus the rule above regarding
        the highest supported version does not apply. A client might request use of a protocol id
        that is unacceptable to a server - for example, it might request a raw AMQP connection
        when the server is configured to require a TLS or SASL security layer (See <xref
        type="section" name="security-layers"/>). In this case, the server MUST send a protocol
        header with an <b>acceptable</b> protocol id (and version) and then close the socket. It MAY
        choose any protocol id.
      </p>

      <picture title="Protocol ID Rejection Example"><![CDATA[
TCP Client                               TCP Server
======================================================
AMQP%d0.1.0.0       ------------->
                    <-------------       AMQP%d3.1.0.0
                                         *TCP CLOSE*
------------------------------------------------------
      Server rejects Connection for: AMQP, protocol=0,
      major=1, minor=0, revision=0, Server responds
      that it requires: SASL security layer, protocol=3,
      major=1, minor=0, revision=0
 ]]>
      </picture>
    </doc>
  </section>

  <section name="framing" label="frame layout and encoding">
    <doc>
      <p>
        Frames are divided into three distinct areas: a fixed width frame header, a variable width
        extended header, and a variable width frame body.
      </p>

      <picture><![CDATA[
    required        optional        optional
+--------------+-----------------+------------+
| frame header | extended header | frame body |
+--------------+-----------------+------------+
    8 bytes        *variable*      *variable*
]]>
      </picture>

      <dl>
        <dt>frame header</dt>
        <dd><p>The frame header is a fixed size (8 byte) structure that precedes each frame. The
            frame header includes mandatory information required to parse the rest of the frame
            including size and type information.</p></dd>

        <dt>extended header</dt>
        <dd><p>The extended header is a variable width area preceding the frame body. This is an
            extension point defined for future expansion. The treatment of this area depends on the
            frame type.</p></dd>

        <dt>frame body</dt>
        <dd><p>The frame body is a variable width sequence of bytes the format of which depends on
            the frame type.</p></dd>
      </dl>
    </doc>

    <doc title="Frame Layout">
      <p>
        The diagram below shows the details of the general frame layout for all frame types.
      </p>

      <picture><![CDATA[
           +0       +1       +2       +3
       +-----------------------------------+ -.
     0 |                SIZE               |  |
       +-----------------------------------+  |---> Frame Header
     4 |  DOFF  |  TYPE  | <TYPE-SPECIFIC> |  |      (8 bytes)
       +-----------------------------------+ -'
       +-----------------------------------+ -.
     8 |                ...                |  |
       .                                   .  |---> Extended Header
       .          <TYPE-SPECIFIC>          .  |  (DOFF * 4 - 8) bytes
       |                ...                |  |
       +-----------------------------------+ -'
       +-----------------------------------+ -.
4*DOFF |                                   |  |
       .                                   .  |
       .                                   .  |
       .                                   .  |
       .          <TYPE-SPECIFIC>          .  |---> Frame Body
       .                                   .  |  (SIZE - DOFF * 4) bytes
       .                                   .  |
       .                                   .  |
       .                           ________|  |
       |                ...       |           |
       +--------------------------+          -'
]]>
      </picture>

      <dl>
        <dt>SIZE</dt>
        <dd><p>Bytes 0-3 of the frame header contain the frame size. This is an unsigned 32-bit
            integer that MUST contain the total frame size of the frame header, extended header, and
            frame body. The frame is malformed if the size is less than the size of the required
            frame header (8 bytes).</p></dd>

        <dt>DOFF</dt>
        <dd><p>Byte 4 of the frame header is the data offset. This gives the position of the body
            within the frame. The value of the data offset is unsigned 8-bit integer specifying a
            count of 4 byte words. Due to the mandatory 8 byte frame header, the frame is malformed
            if the value is less than 2.</p></dd>

        <dt>TYPE</dt>
        <dd><p>Byte 5 of the frame header is a type code. The type code indicates the format and
            purpose of the frame. The subsequent bytes in the frame header may be interpreted
            differently depending on the type of the frame. A type code of 0x00 indicates that the
            frame is an AMQP frame. (A type code of 0x01 indicates that the frame is a SASL frame,
            see <xref type="section" name="sasl"/>).
         </p></dd>
      </dl>
    </doc>

    <doc title="AMQP Frames">
      <p>
        Bytes 6 and 7 of an AMQP Frame contain the Channel number (see <xref name="transport"/>).
        The frame body is defined as a <i>performative</i> followed by an opaque <i>payload</i>. The
        performative MUST be one of those defined in <xref name="performatives"/> and is encoded as
        a described type in the AMQP type system.  The remaining bytes in the frame body form the
        payload for that frame. The presence and format of the payload is defined by the semantics
        of the given performative.
      </p>

      <picture><![CDATA[
              type: 0x00 - AMQP frame

           +0       +1       +2       +3
       +-----------------------------------+ -.
     0 |                SIZE               |  |
       +-----------------------------------+  |---> Frame Header
     4 |  DOFF  |  TYPE  |     CHANNEL     |  |      (8 bytes)
       +-----------------------------------+ -'
       +-----------------------------------+ -.
     8 |                ...                |  |
       .                                   .  |---> Extended Header
       .             <IGNORED>             .  |  (DOFF * 4 - 8) bytes
       |                ...                |  |
       +-----------------------------------+ -'
       +-----------------------------------+ -.
4*DOFF |           PERFORMATIVE:           |  |
       .      Open / Begin / Attach        .  |
       .   Flow / Transfer / Disposition   .  |
       .      Detach / End / Close         .  |
       |-----------------------------------|  |
       .                                   .  |---> Frame Body
       .                                   .  |  (SIZE - DOFF * 4) bytes
       .             PAYLOAD               .  |
       .                                   .  |
       .                           ________|  |
       |                ...       |           |
       +--------------------------+          -'
]]>
      </picture>

      <p>
        An AMQP frame with no body may be used to generate artificial traffic as needed to
        satisfy any negotiated idle time-out interval. See <xref name="doc-idle-time-out"/>.
      </p>
    </doc>
  </section>

  <!-- == Section: connections ================================================================= -->

  <section name="connections" label="connection life-cycle">
    <doc>
      <p>
        AMQP Connections are divided into a number of unidirectional Channels. A Connection Endpoint
        contains two kinds of Channel endpoints: incoming and outgoing. A Connection Endpoint maps
        incoming Frames other than <xref name="open"/> and <xref name="close"/> to an incoming
        Channel endpoint based on the incoming Channel number, as well as relaying Frames produced
        by outgoing Channel endpoints, marking them with the associated outgoing Channel number
        before sending them.
      </p>

      <p>
        This requires Connection endpoints to contain two mappings. One from incoming Channel number
        to incoming Channel endpoint, and one from outgoing Channel endpoint, to outgoing Channel
        number.
      </p>

      <picture><![CDATA[
                                  +-------OCHE X: 1
                                  |
                                  +-------OCHE Y: 7
                                  |
<=== Frame[CH=1], Frame[CH=7] <===+

===> Frame[CH=0], Frame[CH=1] ===>+
                                  |
                                  +------>0: ICHE A
                                  |
                                  +------>1: ICHE B

  OCHE: Outgoing Channel Endpoint
  ICHE: Incoming Channel Endpoint
]]>
      </picture>

      <p>
        Channels are unidirectional, and thus at each Connection endpoint the incoming and outgoing
        Channels are completely distinct. Channel numbers are scoped relative to direction, thus
        there is no causal relation between incoming and outgoing Channels that happen to be
        identified by the "same" number. This means that if a bidirectional endpoint is constructed
        from an incoming Channel endpoint and an outgoing Channel endpoint, the Channel number used
        for incoming Frames is not necessarily the same as the Channel number used for outgoing
        Frames.
      </p>

      <picture><![CDATA[
                                  +-------BIDI/O: 7
                                  |
<=== Frame[CH=1], Frame[CH=7] <===+

===> Frame[CH=0], Frame[CH=1] ===>+
                                  |
                                  +------>1: BIDI/I

  BIDI/I: Incoming half of a single bidirectional endpoint
  BIDI/O: Outgoing half of a single bidirectional endpoint
]]>
      </picture>

      <p>
        Although not strictly directed at the Connection endpoint, the <xref name="begin"/> and
        <xref name="end"/> Frames may be useful for the Connection endpoint to intercept as these
        Frames are how Sessions mark the beginning and ending of communication on a given Channel
        (see <xref name="sessions"/>).
      </p>
    </doc>

    <doc title="Opening a Connection">
      <p>
        Each AMQP Connection begins with an exchange of capabilities and limitations, including the
        maximum frame size. Prior to any explicit negotiation, the maximum frame size is
        <xref name="MIN-MAX-FRAME-SIZE"/> and the maximum channel number is 0. After establishing
        or accepting a TCP Connection and sending the protocol header, each peer must send an
        <xref type="type" name="open"/> frame before sending any other Frames. The
        <xref type="type" name="open"/> frame describes the capabilities and limits of that peer.
        The <xref type="type" name="open"/> frame can only be sent on channel 0. After sending the
        <xref type="type" name="open"/> frame each peer must read its partner's
        <xref type="type" name="open"/> frame and must operate within mutually acceptable
        limitations from this point forward.
      </p>

      <picture><![CDATA[
TCP Client              TCP Server
==================================
TCP-CONNECT             TCP-ACCEPT
PROTO-HDR               PROTO-HDR
OPEN        ---+   +--- OPEN
                \ /
wait             x      wait
                / \
proceed     <--+   +--> proceed

                ...
]]>
      </picture>
    </doc>

    <doc title="Pipelined Open">
      <p>
        For applications that use many short-lived Connections, it may be desirable to pipeline the
        Connection negotiation process. A peer may do this by starting to send subsequent frames
        before receiving the partner's Connection header or <xref type="type" name="open"/> frame.
        This is permitted so long as the pipelined frames are known a priori to conform to the
        capabilities and limitations of its partner. For example, this may be accomplished by
        keeping the use of the Connection within the capabilities and limits expected of all AMQP
        implementations as defined by the specification of the <xref type="type" name="open"/>
        frame.
      </p>

      <picture><![CDATA[
TCP Client                    TCP Server
=============================================
TCP-CONNECT                   TCP-ACCEPT
PROTO-HDR                     PROTO-HDR
OPEN              ---+   +--- OPEN
                      \ /
pipelined frame        x      pipelined frame
                      / \
proceed           <--+   +--> proceed

                      ...
---------------------------------------------

]]>
      </picture>
      <p>
        The use of pipelined frames by a peer cannot be distinguished by the peer's partner from
        non-pipelined use so long as the pipelined frames conform to the partner's capabilities and
        limitations.
      </p>
    </doc>

    <doc title="Closing a Connection">
      <p>
        Prior to closing a Connection, each peer MUST write a <xref type="type" name="close"/> frame
        with a code indicating the reason for closing. This frame MUST be the last thing ever
        written onto a Connection. After writing this frame the peer SHOULD continue to read from
        the Connection until it receives the partner's <xref type="type" name="close"/> frame (in
        order to guard against erroneously or maliciously implemented partners, a peer SHOULD
        implement a timeout to give its partner a reasonable time to receive and process the close
        before giving up and simply closing the underlying transport mechanism). A <xref type="type"
        name="close"/> frame may be received on any channel up to the maximum channel number
        negotiated in open. However, implementations SHOULD send it on channel 0, and MUST send it
        on channel 0 if pipelined in a single batch with the corresponding <xref name="open"/>.
      </p>

      <picture><![CDATA[
TCP Client         TCP Server
=============================
            ...

CLOSE     ------->
               +-- CLOSE
              /    TCP-CLOSE
TCP-CLOSE <--+
]]>
      </picture>

     <p>
       Implementations SHOULD NOT expect to be able to reuse open TCP sockets after <xref
       type="type" name="close"/> performatives have been exchanged. There is no requirement for an
       implementation to read from a socket after a <xref type="type" name="close"/> performative
       has been received.
     </p>

    </doc>

    <doc title="Simultaneous Close">
      <p>
        Normally one peer will initiate the Connection close, and the partner will send its close in
        response. However, because both endpoints may simultaneously choose to close the Connection
        for independent reasons, it is possible for a simultaneous close to occur. In this case, the
        only potentially observable difference from the perspective of each endpoint is the code
        indicating the reason for the close.
      </p>

      <picture><![CDATA[
TCP Client            TCP Server
================================
              ...

CLOSE     ---+   +--- CLOSE
              \ /
               x
              / \
TCP-CLOSE <--+   +--> TCP-CLOSE
]]>
      </picture>
    </doc>

    <doc name="doc-idle-time-out" title="Idle Time-out of a Connection">
      <p>
        Connections are subject to an idle time-out threshold. The time-out is triggered by a local
        peer when no frames are received after a threshold value is exceeded. The idle time-out is
        measured in milliseconds, and starts from the time the last frame is received. If the
        threshold is exceeded, then a peer should try to gracefully close the connection using a
        <xref type="type" name="close"/> frame with an error explaining why. If the remote peer does
        not respond gracefully within a threshold to this, then the peer may close the TCP socket.
      </p>

      <p>
        Each peer has its own (independent) idle time-out. At Connection open each peer communicates
        the maximum period between activity (frames) on the connection that it desires from its
        partner.  The <xref type="type" name="open"/> frame carries the idle-time-out field for this
        purpose. To avoid spurious time-outs, the value in idle-time-out should be half the peer's
        actual timeout threshold.
      </p>

      <p>
        If a peer can not, for any reason support a proposed idle time-out, then it should close
        the connection using a <xref type="type" name="close"/> frame with an error explaining why.
        There is no requirement for peers to support arbitrarily short or long idle time-outs.
      </p>

      <p>
        The use of idle time-outs is any addition to any network protocol level control.
        Implementations should make use of TCP keep-alive wherever possible in order to be good
        citizens.
      </p>

      <p>
        If a peer needs to satisfy the need to send traffic to prevent idle time-out, and has
        nothing to send, it may send an empty frame, i.e. a frame consisting solely of a frame
        header, with no frame body. This frame's channel can be any valid channel up to channel-max,
        but is otherwise to be ignored.  Implementations SHOULD use channel 0 for empty frames, and
        MUST use channel 0 if channel-max has not yet been negotiated (i.e. before an
        <xref name="open"/> frame has been received). Apart from this use, empty frames have no
        meaning.
       </p>

       <p>
         Empty frames can only be sent after the <xref type="type" name="open"/> frame is sent.
         As they are a frame, they should not be sent after the <xref type="type" name="close"/>
         frame has been sent.
       </p>

       <p>
         As an alternative to using an empty frame to prevent an idle time-out, if a connection
         is in a permissible state, an implementation MAY choose to send a flow frame for a valid
         session.
       </p>

       <p>
         If during operation a peer exceeds the remote peer's idle time-out's threshold, e.g.
         because it is heavily loaded, it SHOULD gracefully close the connection by using a
         <xref type="type" name="close"/> frame with an error explaining why.
       </p>
    </doc>

    <doc title="Connection States">
      <dl>
        <dt>START</dt>
        <dd><p>In this state a Connection exists, but nothing has been sent or received. This is the
            state an implementation would be in immediately after performing a socket connect or
            socket accept.</p></dd>

        <dt>HDR_RCVD</dt>
        <dd><p>In this state the Connection header has been received from our peer, but we have not
            yet sent anything.</p></dd>

        <dt>HDR_SENT</dt>
        <dd><p>In this state the Connection header has been sent to our peer, but we have not yet
            received anything.</p></dd>

        <dt>OPEN_PIPE</dt>
        <dd><p>In this state we have sent both the Connection header and the <xref type="type"
            name="open"/> frame, but we have not yet received anything.
            </p></dd>

        <dt>OC_PIPE</dt>
        <dd><p>In this state we have sent the Connection header, the <xref type="type" name="open"/>
            frame, any pipelined Connection traffic, and the <xref type="type" name="close"/> frame,
            but we have not yet received anything.</p></dd>

        <dt>OPEN_RCVD</dt>
        <dd><p>In this state we have sent and received the Connection header, and received an
            <xref type="type" name="open"/> frame from our peer, but have not yet sent an
            <xref type="type" name="open"/> frame.</p></dd>

        <dt>OPEN_SENT</dt>
        <dd><p>In this state we have sent and received the Connection header, and sent an
            <xref type="type" name="open"/> frame to our peer, but have not yet received an
            <xref type="type" name="open"/> frame.</p></dd>

        <dt>CLOSE_PIPE</dt>
        <dd><p>In this state we have send and received the Connection header, sent an
            <xref type="type" name="open"/> frame, any pipelined Connection traffic, and the
            <xref type="type" name="close"/> frame, but we have not yet received an
            <xref type="type" name="open"/> frame.</p></dd>

        <dt>OPENED</dt>
        <dd><p>In this state the Connection header and the <xref type="type" name="open"/> frame
            have both been sent and received.</p></dd>

        <dt>CLOSE_RCVD</dt>
        <dd><p>In this state we have received a <xref type="type" name="close"/> frame indicating
            that our partner has initiated a close. This means we will never have to read anything
            more from this Connection, however we can continue to write frames onto the Connection.
            If desired, an implementation could do a TCP half-close at this point to shutdown the
            read side of the Connection.</p></dd>

        <dt>CLOSE_SENT</dt>
        <dd><p>In this state we have sent a <xref type="type" name="close"/> frame to our partner.
            It is illegal to write anything more onto the Connection, however there may still be
            incoming frames. If desired, an implementation could do a TCP half-close at this point
            to shutdown the write side of the Connection.</p></dd>

        <dt>DISCARDING</dt>
        <dd><p>The DISCARDING state is a variant of the CLOSE_SENT state where the
            <xref name="close"/> is triggered by an error. In this case any incoming frames on
            the connection MUST be silently discarded until the peer's <xref name="close"/> frame
            is received.</p></dd>

        <dt>END</dt>
        <dd><p>In this state it is illegal for either endpoint to write anything more onto the
            Connection. The Connection may be safely closed and discarded.</p></dd>
      </dl>
    </doc>

    <doc title="Connection State Diagram">
      <p>
        The graph below depicts a complete state diagram for each endpoint. The boxes represent
        states, and the arrows represent state transitions. Each arrow is labeled with the action
        that triggers that particular transition.
      </p>

      <picture><![CDATA[
             R:HDR @=======@ S:HDR             R:HDR[!=S:HDR]
          +--------| START |-----+    +--------------------------------+
          |        @=======@     |    |                                |
         \|/                    \|/   |                                |
     @==========@             @==========@ S:OPEN                      |
+----| HDR_RCVD |             | HDR_SENT |------+                      |
|    @==========@             @==========@      |      R:HDR[!=S:HDR]  |
|   S:HDR |                      | R:HDR        |    +-----------------+
|         +--------+      +------+              |    |                 |
|                 \|/    \|/                   \|/   |                 |
|                @==========@               +-----------+ S:CLOSE      |
|                | HDR_EXCH |               | OPEN_PIPE |----+         |
|                @==========@               +-----------+    |         |
|           R:OPEN |      | S:OPEN              | R:HDR      |         |
|         +--------+      +------+      +-------+            |         |
|        \|/                    \|/    \|/                  \|/        |
|   @===========@             @===========@ S:CLOSE       +---------+  |
|   | OPEN_RCVD |             | OPEN_SENT |-----+         | OC_PIPE |--+
|   @===========@             @===========@     |         +---------+  |
|  S:OPEN |                      | R:OPEN      \|/           | R:HDR   |
|         |       @========@     |          +------------+   |         |
|         +------>| OPENED |<----+          | CLOSE_PIPE |<--+         |
|                 @========@                +------------+             |
|           R:CLOSE |    | S:CLOSE              | R:OPEN               |
|         +---------+    +-------+              |                      |
|        \|/                    \|/             |                      |
|   @============@          @=============@     |                      |
|   | CLOSE_RCVD |          | CLOSE_SENT* |<----+                      |
|   @============@          @=============@                            |
| S:CLOSE |                      | R:CLOSE                             |
|         |         @=====@      |                                     |
|         +-------->| END |<-----+                                     |
|                   @=====@                                            |
|                     /|\                                              |
|    S:HDR[!=R:HDR]    |                R:HDR[!=S:HDR]                 |
+----------------------+-----------------------------------------------+

                     R:<CTRL> = Received <CTRL>
                     S:<CTRL> = Sent <CTRL>
                     * Also could be DISCARDING if an error condition
                       triggered the CLOSE
]]>
      </picture>

      <picture><![CDATA[
State        Legal Sends     Legal Receives    Legal Connection Actions
=======================================================================
START        HDR             HDR
HDR_RCVD     HDR             OPEN
HDR_SENT     OPEN            HDR
HDR_EXCH     OPEN            OPEN
OPEN_RCVD    OPEN            *
OPEN_SENT    **              OPEN
OPEN_PIPE    **              HDR
CLOSE_PIPE   -               OPEN              TCP Close for Write
OC_PIPE      -               HDR               TCP Close for Write
OPENED       *               *
CLOSE_RCVD   *               -                 TCP Close for Read
CLOSE_SENT   -               *                 TCP Close for Write
DISCARDING   -               *                 TCP Close for Write
END          -               -                 TCP Close

*  = any frames
-  = no frames
** = any frame known a priori to conform to the
     peer's capabilities and limitations
]]>
      </picture>
    </doc>

  </section>

  <!-- == Section: sessions ==================================================================== -->

  <section name="sessions" label="context for active link communication">
    <doc>
      <p>
        A Session is a bidirectional sequential conversation between two containers that provides a
        grouping for related links. Sessions serve as the context for link communication. Any number
        of links of any directionality can be <i>attached</i> to a given Session. However, a link
        may be attached to at most one Session at a time.
      </p>

      <picture>
        <![CDATA[
Link A-------+                          +------>Link A
             |                          |
            \|/       (attached)        |
Link B<--- Session <--------------> Session <---Link B


Link C------>*        (detached)        *------>Link C
]]>
      </picture>

      <p>
        Messages transferred on a link are sequentially identified within the Session. A session may
        be viewed as multiplexing link traffic, much like a connection multiplexes session traffic.
        However, unlike the sessions on a connection, links on a session are not entirely
        independent since they share a common delivery sequence scoped to the session. This common
        sequence allows endpoints to efficiently refer to sets of deliveries regardless of the
        originating link. This is of particular benefit when a single application is receiving
        messages along a large number of different links. In this case the session
        provides <i>aggregation</i> of otherwise independent links into a single stream that can be
        efficiently acknowledged by the receiving application.
      </p>

    </doc>

    <doc title="Establishing a Session">
      <p>
        Sessions are established by creating a Session Endpoint, assigning it to an unused channel
        number, and sending a <xref type="type" name="begin"/> announcing the association of the
        Session Endpoint with the outgoing channel. Upon receiving the <xref type="type"
        name="begin"/> the partner will check the remote-channel field and find it empty. This
        indicates that the begin is referring to remotely initiated Session. The partner will
        therefore allocate an unused outgoing channel for the remotely initiated Session and
        indicate this by sending its own <xref type="type" name="begin"/> setting the
        remote-channel field to the incoming channel of the remotely initiated Session.
      </p>

      <p>
        To make it easier to monitor AMQP sessions, it is recommended that implementations always
        assign the lowest available unused channel number.
      </p>

      <p>
        The remote-channel field of a <xref type="type" name="begin"/> frame MUST be empty for a
        locally initiated Session, and MUST be set when announcing the endpoint created as a result
        of a remotely initiated Session.
      </p>

      <picture><![CDATA[
    Endpoint                                      Endpoint
    =====================================================================
    [CH3] BEGIN(name=...,        --------->
                remote-channel=null)
                                        +-- [CH7] BEGIN(name=...,
                                       /                remote-channel=3)
                                      /
                                 <---+

                                    ...

    ---------------------------------------------------------------------
]]>
      </picture>
    </doc>

    <doc title="Ending a Session">
      <p>
        Sessions end automatically when the Connection is closed or interrupted. Sessions are
        explicitly ended when either endpoint chooses to end the Session. When a Session is
        explicitly ended, an <xref type="type" name="end"/> frame is sent to announce the
        disassociation of the endpoint from its outgoing channel, and to carry error information
        when relevant.
      </p>

      <picture><![CDATA[
    Endpoint A                              Endpoint B
    ====================================================================

                                     ...

    [CH3] END(error=...)         --------->                          (1)
                                        +-- [CH7] END(error=...)
                                       /
                                      /
(2)                              <---+

                                     ...

    --------------------------------------------------------------------

      (1) At this point the session endpoint is disassociated from
          the outgoing channel on A, and the incoming channel on B.

      (2) At this point the session endpoint is disassociated from
          the outgoing channel on B, and the incoming channel on A.
]]>
      </picture>
    </doc>

    <doc title="Simultaneous End">
      <p>
        Due to the potentially asynchronous nature of Sessions, it is possible that both peers may
        simultaneously decide to end a Session. If this should happen, it will appear to each peer
        as though their partner's spontaneously initiated <xref type="type" name="end"/> frame is
        actually an answer to the peers initial <xref type="type" name="end"/> frame.
      </p>

      <picture><![CDATA[
    Endpoint A                            Endpoint B
    =================================================================

                                   ...

    [CH3] END(error=...)        --+   +-- [CH7] END(error=...)
(1)                                \ /                                (2)
                                    x
                                   / \
(3)                             <-+   +->                             (4)

                                   ...

    -----------------------------------------------------------------

      (1) At this point no more frames may be sent by A.

      (2) At this point no more frames may be sent by B.

      (3) At this point Endpoint A is fully ended.

      (4) At this point Endpoint B is fully ended.
]]>
      </picture>
    </doc>

    <doc title="Session Errors" >
      <p>
        When a Session is unable to process input, it MUST indicate this by issuing an END with an
        appropriate <xref name="error"/> indicating the cause of the problem. It MUST then proceed
        to discard all incoming frames from the remote endpoint until hearing the remote endpoint's
        corresponding <xref name="end"/> frame.
      </p>

      <picture><![CDATA[
Endpoint                      Endpoint
================================================
FRAME 1           ---------->
FRAME 2           ---------->
FRAME 3           ---+   +--- END(error=...)
                      \ /
                       x
                      / \
                  <--+   +--> *discarded*
END               ---------->
                      ...
================================================
]]>
      </picture>
    </doc>

    <doc title="Session States">
      <dl>
        <dt>UNMAPPED</dt>
        <dd><p>In the UNMAPPED state, the Session endpoint is not mapped to any incoming or outgoing
            channels on the Connection endpoint. In this state an endpoint cannot send or receive
            frames.</p></dd>

        <dt>BEGIN_SENT</dt>
        <dd><p>In the BEGIN_SENT state, the Session endpoint is assigned an outgoing channel number,
            but there is no entry in the incoming channel map. In this state the endpoint may send
            frames but cannot receive them.</p></dd>

        <dt>BEGIN_RCVD</dt>
        <dd><p>In the BEGIN_RCVD state, the Session endpoint has an entry in the incoming channel
            map, but has not yet been assigned an outgoing channel number. The endpoint may receive
            frames, but cannot send them.</p></dd>

        <dt>MAPPED</dt>
        <dd><p>In the MAPPED state, the Session endpoint has both an outgoing channel number and an
            entry in the incoming channel map. The endpoint may both send and receive
            frames.</p></dd>

        <dt>END_SENT</dt>
        <dd><p>In the END_SENT state, the Session endpoint has an entry in the incoming channel map,
            but is no longer assigned an outgoing channel number. The endpoint may receive frames,
            but cannot send them.</p></dd>

        <dt>END_RCVD</dt>
        <dd><p>In the END_RCVD state, the Session endpoint is assigned an outgoing channel number,
            but there is no entry in the incoming channel map. The endpoint may send frames, but
            cannot receive them.</p></dd>

        <dt>DISCARDING</dt>
        <dd><p>The DISCARDING state is a variant of the END_SENT state where the <xref name="end"/>
            is triggered by an error. In this case any incoming frames on the session MUST be
            silently discarded until the peer's <xref name="end"/> frame is received.</p></dd>
      </dl>

      <picture title="State Transitions"><![CDATA[
                        UNMAPPED<-------------------+
                           |                        |
                   +-------+-------+                |
           S:BEGIN |               | R:BEGIN        |
                   |               |                |
                  \|/             \|/               |
               BEGIN_SENT      BEGIN_RCVD           |
                   |               |                |
                   |               |                |
           R:BEGIN |               | S:BEGIN        |
                   +-------+-------+                |
                           |                        |
                          \|/                       |
                         MAPPED                     |
                           |                        |
             +-------------+-------------+          |
S:END(error) |       S:END |             | R:END    |
             |             |             |          |
            \|/           \|/           \|/         |
         DISCARDING     END_SENT      END_RCVD      |
             |             |             |          |
             |             |             |          |
       R:END |       R:END |             | S:END    |
             +-------------+-------------+          |
                           |                        |
                           |                        |
                           +------------------------+
]]>
      </picture>

      <p>
        There is no obligation to retain a Session Endpoint when it is in the UNMAPPED state, i.e.
        the UNMAPPED state is equivalent to a NONEXISTENT state.
      </p>
    </doc>

    <doc name="session-flow-control" title="Session Flow Control">
      <p>
        The Session Endpoint assigns each outgoing <xref name="transfer"/> frame an implicit
        <i>transfer-id</i> from a session scoped sequence. Each session endpoint maintains the
        following state to manage incoming and outgoing <xref name="transfer"/> frames:
      </p>

      <dl>
        <dt>next-incoming-id</dt>
        <dd><p>The <i>next-incoming-id</i> identifies the implicit transfer-id of the next incoming
            <xref name="transfer"/> frame.</p></dd>

        <dt>incoming-window</dt>
        <dd><p>The <i>incoming-window</i> defines the maximum number of incoming
            <xref name="transfer"/> frames that the endpoint can currently receive. This identifies
            a current maximum incoming transfer-id that can be computed by subtracting one from the
            sum of <i>incoming-window</i> and <i>next-incoming-id</i>.</p></dd>

        <dt>next-outgoing-id</dt>
        <dd><p>The <i>next-outgoing-id</i> is used to assign a unique transfer-id to all
            outgoing transfer frames on a given session. The <i>next-outgoing-id</i> may be
            initialized to an arbitrary value and is incremented after each successive
            <xref name="transfer"/> according to RFC-1982 serial number arithmetic.</p></dd>

        <dt>outgoing-window</dt>
        <dd><p>The <i>outgoing-window</i> defines the maximum number of outgoing
            <xref name="transfer"/> frames that the endpoint can currently send. This identifies a
            current maximum outgoing transfer-id that can be computed by subtracting one from the
            sum of <i>outgoing-window</i> and <i>next-outgoing-id</i>.</p></dd>

        <dt>remote-incoming-window</dt>
        <dd><p>The <i>remote-incoming-window</i> reflects the maximum number of outgoing transfers
          that can be sent without exceeding the remote endpoint's incoming-window. This value MUST
          be decremented after every <xref name="transfer"/> frame is sent, and recomputed when
          informed of the remote session endpoint state.</p></dd>

        <dt>remote-outgoing-window</dt>
        <dd><p>The <i>remote-outgoing-window</i> reflects the maximum number of incoming transfers
          that may arrive without exceeding the remote endpoint's outgoing-window. This value MUST
          be decremented after every incoming <xref name="transfer"/> frame is received, and
          recomputed when informed fo the remote session endpoint state. When this window shrinks,
          it is an indication of outstanding transfers. Settling outstanding transfers may cause the
          window to grow.</p></dd>
      </dl>

      <p>
        Once initialized, this state is updated by various events that occur in the lifespan of a
        session and its associated links:
      </p>

      <dl>
        <dt>sending a transfer</dt>
        <dd><p>Upon sending a transfer, the sending endpoint will increment its next-outgoing-id,
            decrement its remote-incoming-window, and may (depending on policy) decrement its
            outgoing-window.</p></dd>

        <dt>receiving a transfer</dt>
        <dd><p>Upon receiving a transfer, the receiving endpoint will increment the next-incoming-id
            to match the implicit transfer-id of the incoming transfer plus one, as well as
            decrementing the remote-outgoing-window, and may (depending on policy) decrement its
            incoming-window.</p></dd>

        <dt>receiving a flow</dt>
        <dd><p>When the endpoint receives a <xref name="flow"/> frame from its peer, it MUST update
            the <i>next-incoming-id</i> directly from the <i>next-outgoing-id</i> of the frame, as
            well as copy the <i>remote-outgoing-window</i> directly from the <i>outgoing-window</i>
            of the frame.</p>

          <p>
            The <i>remote-incoming-window</i> is computed as follows:
          </p>

          <p>
            <i>next-incoming-id<sub>flow</sub></i> + <i>incoming-window<sub>flow</sub></i>
            - <i>next-outgoing-id<sub>endpoint</sub></i>
          </p>

          <p>
            If the <i>next-incoming-id</i> field of the <xref name="flow"/> frame is not set,
            then <i>remote-incoming-window</i> is computed as follows:
          </p>

          <p>
            <i>initial-outgoing-id<sub>endpoint</sub></i> + <i>incoming-window<sub>flow</sub></i>
            - <i>next-outgoing-id<sub>endpoint</sub></i>
          </p>
        </dd>
      </dl>
    </doc>
  </section>

  <!-- == Section: links ======================================================================= -->

  <section name="links" label="link endpoints and the link protocol">
    <doc>
      <p>
        A Link provides a unidirectional transport for Messages between a Source and a Target. The
        primary responsibility of a Source or Target (a Terminus) is to maintain a record of the
        status of each active delivery attempt until such a time as it is safe to forget. These are
        referred to as <term>unsettled</term> deliveries. When a Terminus forgets the state
        associated with a delivery-tag, it is considered <term>settled</term>. Each delivery attempt
        is assigned a unique <term>delivery-tag</term> at the Source. The status of an active
        delivery attempt is known as the <term>Delivery State</term> of the delivery.
      </p>

      <p>
        Link Endpoints interface between a Terminus and a Session Endpoint, and maintain additional
        state used for active communication between the local and remote endpoints. Link Endpoints
        therefore come in two flavors: <term>Senders</term> and <term>Receivers</term>. When the
        sending application submits a Message to the Sender for transport, it also supplies the
        delivery-tag used by the Source to track the Delivery State. The Link Endpoint assigns each
        Message a unique <term>delivery-id</term> from a Session scoped sequence. These delivery-ids
        are used to efficiently reference subsets of the outstanding deliveries on a Session.
      </p>

      <p>
        Termini may exist beyond their associated Link Endpoints, so it is possible for a Session to
        terminate and the Termini to remain. A Link is said to be <term>suspended</term> if the
        Termini exist, but have no associated Link Endpoints. The process of associating new Link
        Endpoints with existing Termini and re-establishing communication is referred to
        as <term>resuming</term> a Link.
      </p>

      <p>
        The original Link Endpoint state is not necessary for resumption of a Link. Only the
        unsettled Delivery State maintained at the Termini is necessary for link resume, and this
        need not be stored directly. The form of delivery-tags is intentionally left open-ended so
        that they and their related Delivery State can, if desired, be (re)constructed from
        application state, thereby minimizing or eliminating the need to retain additional
        protocol-specific state in order to resume a Link.
      </p>
    </doc>

    <doc title="Naming a Link">
      <p>
        Links are named so that they may be recovered when communication is interrupted. Link names
        MUST uniquely identify the link amongst all links of the same direction between the two
        participating containers. Link names are only used when attaching a Link, so they may be
        arbitrarily long without a significant penalty.
      </p>
      <p>
        A link's name uniquely identifies the link from the container of the source to the
        container of the target node, e.g. if the container of the source node is A, and the
        container of the target node is B, the link may be globally identified by the (ordered)
        tuple <i>(A,B,&lt;name&gt;)</i>.
      </p>
      <p>
        Consequently, a link may only be active in one connection at a time. If an attempt is made
        to attach the link subsequently when it is not suspended, then the link can be 'stolen',
        i.e.  the second attach succeeds and the first attach must then be closed with a link error
        of <xref name="link-error" choice="stolen"/>. This behavior ensures that in the event of a
        connection failure occurring and being noticed by one party, that re-establishment has the
        desired effect.
      </p>
    </doc>

    <doc title="Link Handles">
      <p>
        Each Link Endpoint is assigned a numeric handle used by the peer as a shorthand to refer to
        the Link in all frames that reference the Link (<xref type="type" name="attach"/>,
        <xref type="type" name="detach"/>, <xref type="type" name="flow"/>, <xref type="type"
        name="transfer"/>, <xref type="type" name="disposition"/>). This handle is assigned by the
        initial <xref type="type" name="attach"/> frame and remains in use until the link is
        detached. The two Endpoints are not required to use the same handle. This means a peer is
        free to independently chose its handle when a Link Endpoint is associated with the Session.
        The locally chosen handle is referred to as the <term>output handle</term>. The remotely
        chosen handle is referred to as the <term>input handle</term>.
      </p>

      <p>
        At an Endpoint, a Link is considered to be <term>attached</term> when the Link Endpoint
        exists and has both input and output handles assigned at an active Session Endpoint. A Link
        is considered to be <term>detached</term> when the Link Endpoint exists, but is not assigned
        either input or output handles. A Link can be considered <term>half attached</term>
        (or <term>half detached</term>) when only one of the input or output handles is assigned.
      </p>

      <picture><![CDATA[
+-------------------+                             +-------------------+
|    name: Link_1   |                             |    name: Link_1   |
|  handle: i        |                             |  handle: j        |
|-------------------|                             |-------------------|
|    role: receiver |                             |    role: sender   |
|  source: A        |<---+                   +--->|  source: A        |
|  target: B        |    |                   |    |  target: B        |
+-------------------+    |                   |    +-------------------+
                         |                   |
                         |    +---------+    |
        ...          <---+--->| Session |<---+--->        ...
                         |    +---------+    |
                         |                   |
+-------------------+    |                   |    +-------------------+
|    name: Link_N   |    |                   |    |    name: Link_N   |
|  handle: k        |<---+                   +--->|  handle: l        |
|-------------------|                             |-------------------|
|    role: sender   |                             |    role: receiver |
|  source: C        |                             |  source: C        |
|  target: D        |                             |  target: D        |
+-------------------+                             +-------------------+
]]>
      </picture>
    </doc>

    <doc title="Establishing or Resuming a Link">
      <p>
        Links are established and/or resumed by creating a Link Endpoint associated with a local
        Terminus, assigning it to an unused handle, and sending an <xref type="type" name="attach"/>
        Frame. This frame carries the state of the newly created Link Endpoint, including the local
        and remote termini, one being the source and one being the target depending on the
        directionality of the Link Endpoint. On receipt of the <xref name="attach"/>, the remote
        Session Endpoint creates a corresponding Link Endpoint and informs its application of the
        attaching Link. The application attempts to locate the Terminus previously associated with
        the Link. This Terminus is associated with the Link Endpoint and may be updated if its
        properties do not match those sent by the remote Link Endpoint. If no such Terminus exists,
        the application MAY choose to create one using the properties supplied by the remote Link
        Endpoint. The Link Endpoint is then mapped to an unused handle, and an <xref type="type"
        name="attach"/> Frame is issued carrying the state of the newly created endpoint. Note that
        if the application chooses not to create a Terminus, the Session Endpoint will still create
        a Link Endpoint and issue an <xref type="type" name="attach"/> indicating that the Link
        Endpoint has no associated local terminus. In this case, the Session Endpoint MUST
        immediately detach the newly created Link Endpoint.
      </p>

      <picture title="Establishing a Link"><![CDATA[
Peer                                  Partner
================================================================
*create link endpoint*
ATTACH(name=N, handle=1,    ----------> *create link endpoint*
       role=sender,                +--- ATTACH(name=N, handle=2,
       source=A,                  /            role=receiver,
       target=B)                 /             source=A,
                                /              target=B)
                            <--+
                              ...
----------------------------------------------------------------
]]>
      </picture>

      <p>
        If there is no pre-existing Terminus, and the peer does not wish to create a new one, this
        is indicated by setting the local terminus (source or target as appropriate) to null.
      </p>

      <picture title="Refusing a Link"><![CDATA[
    Peer                                  Partner
    ================================================================
    *create link endpoint*
    ATTACH(name=N, handle=1,    ----------> *create link endpoint*  (1)
           role=sender,                +--- ATTACH(name=N, handle=2,
           source=A,                  /            role=receiver,
           target=B)                 /             source=A,
                                    /              target=-)
(2)                             <--+
                                       +--- DETACH(handle=2,
                                      /            closed=True)
                                     /
                                    /
                                <--+
    DETACH(handle=1,            ----------->
           closed=True)
                                  ...
    ----------------------------------------------------------------
      (1) The Link Endpoint is created, but no target is created.
      (2) At this point the link is established, but it is to a
          nonexistent target.
]]>
      </picture>

      <p>
        If either end of the Link is already associated with a Terminus, the <xref name="attach"/>
        frame MUST include its unsettled delivery state.
      </p>

      <picture title="Resuming a Link"><![CDATA[
    Peer                                   Partner
    ================================================================
    *existing source*
    ATTACH(name=N, handle=1,   ----------> *found existing target*
           role=sender,               +--- ATTACH(name=N, handle=2,  (1)
           source=X,                 /            role=receiver,
           target=Y,                /             source=X,
           unsettled=...)          /              target=Y,
(2)                            <--+               unsettled=...)
                                   ...
    ----------------------------------------------------------------
      (1) The target already exists, and its properties
          match the peer's expectations.
      (2) At this point the Link is reestablished with source=X,
          target=Y.
]]>
      </picture>


      <p>
        Note that the expected Terminus properties may not always match the actual Terminus
        properties reported by the remote endpoint. In this case, the Link is always considered to
        be between the Source as described by the Sender, and the Target as described by the
        Receiver. This can happen both when establishing and when resuming a link.
      </p>

      <p>
        When a link is established, an endpoint may not have all the capabilities necessary to
        create the terminus exactly matching the expectations of the peer. Should this happen, the
        endpoint MAY adjust the properties in order to succeed in creating the terminus. In this
        case the endpoint MUST report the actual properties of the terminus as created.
      </p>

      <p>
        When resuming a link, the Source and Target properties may have changed while the link was
        suspended. When this happens, the Termini properties communicated in the source and target
        fields of the <xref name="attach"/> frames may be in conflict. In this case, the Sender is
        considered to hold the authoritative version of the Source properties, the Receiver is
        considered to hold the authoritative version of the Target properties. As above, the
        resulting Link is constructed to be between the Source as described by the Sender, and the
        Target as described by the Receiver. Once the Link is resumed, either peer is free to
        continue if the updated properties are acceptable, or if not, <xref type="type"
        name="detach"/>.
      </p>

      <p>
        Note that a peer MUST take responsibility for verifying that the remote terminus meets its
        requirements. The remote peer SHOULD NOT attempt to pre-empt whether the terminus will meet
        the requirements of its partner. This is equally true both for creating and resuming links.
      </p>

      <picture title="Resuming an altered Link"><![CDATA[
    Peer                                 Partner
    ================================================================
    *existing source*
    ATTACH(name=N, handle=1,   ----------> *found existing target*
           role=sender,               +--- ATTACH(name=N, handle=2,  (1)
           source=A,                 /            role=receiver,
           target=B,                /             source=A,
           unsettled=...)          /              target=C,
(2)                            <--+               unsettled=...)
                                   ...
    ----------------------------------------------------------------
      (1) The Terminus already exists, but its state
          does not match the Peer's endpoint.
      (2) At this point the Link is established with source=A,
          target=C.
]]>
      </picture>


      <p>
        It is possible to resume a Link even if one of the Termini has lost nearly all its state.
        All that is required is the Link name and direction. This is referred to as
        <term>recovering</term> a Link. This is done by creating a new Link Endpoint with an empty
        source or target for incoming or outgoing Links respectively. The full Link state is then
        constructed from the authoritative source or target supplied by the other endpoint once the
        Link is established. If the remote peer has no record of the Link, then no terminus will be
        located, and local terminus (source or target as appropriate) field in the
        <xref name="attach"/> frame will be null.
      </p>

      <picture title="Recovering a Link"><![CDATA[
    Peer                                   Partner
    ================================================================
    *create link endpoint*
    ATTACH(name=N, handle=1,   ----------> *found existing target*
           role=sender,               +--- ATTACH(name=N, handle=2,  (1)
           source=X                  /            role=receiver,
           target=-)                /             source=X,
(2)                            <---+              target=Y)
                                   ...
    ----------------------------------------------------------------
      (1) The target already exists, and its properties are
          authoritative.
      (2) At this point the Link is reestablished with source=X,
          target=Y.
]]>
      </picture>
    </doc>

    <doc title="Detaching and Reattaching a Link">
      <p>
        A Session Endpoint can choose to unmap its output handle for a Link. In this case, the
        endpoint MUST send a <xref name="detach"/> frame to inform the remote peer that the handle
        is no longer attached to the Link Endpoint. Should both endpoints do this, the Link may
        return to a fully detached state. Note that in this case the Link Endpoints may still
        indirectly communicate via the Session, as there may be active deliveries on the link
        referenced via delivery-id.
      </p>

      <picture><![CDATA[
    Peer                                Partner
    =============================================================
    *create link endpoint*
    ATTACH(name=N, handle=1   ----------> *create link endpoint*
           role=sender,              +--- ATTACH(name=N, handle=2,
           source=A,                /            role=receiver,
           target=B)               /             source=A,
                                  /              target=B)
                              <--+
                                  ...
    *use link*                <---------> *use link*
                                  ...
    DETACH(handle=1)          ----------> *detach input handle*
(1) *detach output handle*    <---------- DETACH(handle=2)
                                  ...
    -------------------------------------------------------------
      (1) At this point both endpoints are detached.
]]>
      </picture>

      <p>
        When the state of a Link Endpoint changes, this is can be communicated by detaching and then
        reattaching with the updated state on the <xref name="attach"/> frame. This can be used to
        update the properties of the link endpoints, or to update the properties of the Termini.
      </p>

      <picture><![CDATA[
    Peer                                Partner
    =============================================================
                                  ...
    DETACH(handle=1)          ---+
                                  \
                                   \
                                    \
    *modify link endpoint*           \
                                      +--> *detach input handle*
    ATTACH(name=N, handle=1   ---+    +--- DETACH(handle=2)
           role=sender,           \  /
           source=A',              \/
           target=B')              /\
                                  /  \
     *detach input handle*    <--+    +--> *reattach input handle*
                                           *modify link endpoint*
                                      +--- ATTACH(name=N, handle=2
                                     /            role=receiver,
                                    /             source=A',
                                   /              target=B')
                                  /
(1)  *reattach input handle*  <--+
                                  ...
    *use link*               <---------> *use link*
                                  ...
    -------------------------------------------------------------
      (1) At this point the link is updated and attached.
]]>
      </picture>
    </doc>

    <doc title="Link Errors">
      <p>
        When an error occurs at a Link Endpoint, the endpoint MUST be detached with appropriate
        error information supplied in the error field of the <xref name="detach"/> frame. The Link
        Endpoint MUST then be destroyed. Should any input (other than a detach) related to the
        endpoint either via the input handle or delivery-ids be received, the session MUST be
        terminated with an <xref name="session-error" choice="errant-link"/> session-error. Since
        the Link Endpoint has been destroyed, the peer cannot reattach, and MUST resume the link in
        order to restore communication. In order to disambiguate the resume request from a pipelined
        re-attach the resuming <xref name="attach"/> performative MUST contain a non-null value for
        its unsettled field. Receipt of a pipelined <xref name="attach"/> MUST result in the session
        being terminated with an <xref name="session-error" choice="errant-link"/> session-error.
      </p>

    </doc>

    <doc name="closing-a-link" title="Closing a Link">
      <p>
        A peer closes a Link by sending the <xref type="type" name="detach"/> frame with the handle
        for the specified Link, and the closed flag set to true. The partner will destroy the
        corresponding Link endpoint, and reply with its own <xref type="type" name="detach"/> frame
        with the closed flag set to true.
      </p>

      <picture title="Closing a Link"><![CDATA[
    Peer                                Partner
    =============================================================
    *create link endpoint*
    ATTACH(name=N, handle=1   ----------> *create link endpoint*
           role=sender,              +--- ATTACH(name=N, handle=2,
           source=A,                /            role=receiver,
           target=B)               /             source=A,
                                  /              target=B)
                              <--+
                                  ...
    *use link*                <---------> *use link*
                                  ...
    DETACH(handle=1,          ----------> *destroy link endpoint*
           closed=True)
(1) *destroy link endpoint*   <---------- DETACH(handle=2,
                                                 closed=True)
    -------------------------------------------------------------
      (1) At this point both endpoints are destroyed.
]]>
      </picture>

      <p>
        Note that one peer may send a closing detach while its partner is sending a non-closing
        detach. In this case, the partner MUST signal that it has closed the link by reattaching and
        then sending a closing detach.
      </p>
    </doc>

    <doc name="flow-control" title="Flow Control">
      <p>
        Once attached, a Link is subject to flow control of Message transfers. Link Endpoints
        maintain the following flow control state. This state defines when it is legal to send
        transfers on an attached Link, as well as indicating when certain interesting conditions,
        such as insufficient messages to consume the currently available <i>link-credit</i>, or
        insufficient <i>link-credit</i> to send available messages:
      </p>

      <dl>
        <dt>delivery-count</dt>
        <dd><p>The <i>delivery-count</i> is initialized by the Sender when a Link Endpoint is
            created, and is incremented whenever a Message is sent (at the Sender) or received (at
            the Receiver).  Only the Sender may independently modify this field. The Receiver's
            value is calculated based on the last known value from the Sender and any subsequent
            Messages received on the Link.</p></dd>

        <dt>link-credit</dt>
        <dd><p>The <i>link-credit</i> variable defines the current maximum legal amount that the
            <i>delivery-count</i> may be increased. This identifies a <i>delivery-limit</i> that may
            be computed by adding the <i>link-credit</i> to the <i>delivery-count</i>.</p>

            <p>Only the Receiver can independently choose a value for this field. The Sender's value
            MUST always be maintained in such a way as to match the <i>delivery-limit</i> identified
            by the Receiver. This means that the Sender's link-credit variable MUST be set according
            to this formula when flow information is given by the receiver:</p>

            <p>
              <i>link-credit</i><sub>snd</sub> := <i>delivery-count</i><sub>rcv</sub> +
              <i>link-credit</i><sub>rcv</sub> - <i>delivery-count</i><sub>snd</sub>.
            </p>

            <p>
              In the event that the receiver does not yet know the <i>delivery-count</i>, i.e.
              <i>delivery-count</i><sub>rcv</sub> is unspecified, the Sender MUST assume that
              the <i>delivery-count</i><sub>rcv</sub> is the first
              <i>delivery-count</i><sub>snd</sub> sent from Sender to Receiver, i.e. the
              <i>delivery-count</i><sub>snd</sub> specified in the flow state carried by the initial
              <xref name="attach"/> frame from the Sender to the Receiver.
            </p>

            <p>
              Additionally, whenever the Sender increases <i>delivery-count</i>, it MUST decrease
              <i>link-credit</i> by the same amount in order to maintain the <i>delivery-limit</i>
              identified by the Receiver.
            </p>
        </dd>

        <dt>available</dt>
        <dd><p>The <i>available</i> variable is controlled by the Sender, and indicates to the
            Receiver, that the Sender could make use of the indicated amount of <i>link-credit</i>.
            Only the Sender can independently modify this field. The Receiver's value is calculated
            based on the last known value from the Sender and any subsequent incoming Messages
            received. The Sender MAY transfer Messages even if the available variable is zero.
            Should this happen, the Receiver MUST maintain a floor of zero in it's calculation of
            the value of available.</p></dd>

        <dt>drain</dt>
        <dd><p>The drain flag indicates how the Sender should behave when insufficient messages are
            available to consume the current link-credit. If set, the Sender will (after sending all
            available messages) advance the delivery-count as much as possible, consuming all
            link-credit, and send the flow state to the Receiver. Only the Receiver can
            independently modify this field. The Sender's value is always the last known value
            indicated by the Receiver.</p></dd>
      </dl>

      <p>
        If the link-credit is less than or equal to zero, i.e. the delivery-count is the same as or
        greater than the delivery-limit, it is illegal to send more messages. If the link-credit is
        reduced by the Receiver when transfers are in-flight, the Receiver MAY either handle the
        excess messages normally or detach the Link with a transfer-limit-exceeded error code.
      </p>

      <picture><![CDATA[
     +----------+                                    +----------+
     |  Sender  |---------------transfer------------>| Receiver |
     +----------+                                    +----------+
      \        / <----------------flow--------------- \        /
       +------+                                        +------+
          |
          |
          |
 if link-credit <= 0 then pause
]]>
      </picture>

      <p>
        If the Sender's drain flag is set and there are no available messages, the Sender MUST
        advance its delivery-count until link-credit is zero, and send its updated
        <xref name="flow"/> state to the Receiver.
      </p>

      <p>
        The delivery-count is an absolute value. While the value itself is conceptually unbounded,
        it is encoded as a 32-bit integer that wraps around and compares according to RFC-1982
        serial number arithmetic.
      </p>

      <p>
        The initial flow state of a Link Endpoint is determined as follows. The <i>link-credit</i>
        and <i>available</i> variables are initialized to zero. The <i>drain</i> flag is initialized
        to False. The Sender may choose an arbitrary point to initialize the <i>delivery-count</i>.
        This value is communicated in the initial <xref name="attach"/> frame. The Receiver
        initializes its <i>delivery-count</i> upon receiving the Sender's <xref name="attach"/>.
      </p>

      <picture><![CDATA[
                                flow state
                                    |
                                    | modifies
+------------------+                |               +------------------+
|      Sender      |    .----------------------.    |     Receiver     |
+------------------+     attach, transfer, flow     +------------------+
| delivery-count   |------------------------------->| delivery-count   |
| link-credit      |                                | link-credit      |
| available        |<-------------------------------| available        |
| drain            |              flow              | drain            |
+------------------+             '-----'            +------------------+
                                    |
                                    | modifies
                                    |
                                flow state
]]>
      </picture>

      <p>
        The flow control semantics defined in this section provide the primitives necessary to
        implement a wide variety of flow control strategies. Additionally, by manipulating the
        link-credit and drain flag, a Receiver can provide a variety of different higher level
        behaviors often useful to applications, including synchronous blocking fetch, synchronous
        fetch with a timeout, asynchronous notifications, and stopping/pausing.
      </p>

      <picture><![CDATA[
            +----------+                                    +----------+
            | Receiver |<--------------transfer-------------|  Sender  |
            +----------+                                    +----------+
             \        / -----------------flow--------------> \        /
              +------+                                        +------+
                  |
                  |
                  |
    sync-get: flow(link-credit=1, ...)      ---->
   timed-get: flow(link-credit=1, ...),
              *wait*,
              flow(drain=True, ...)         ---->
async-notify: flow(link-credit=delta, ...)  ---->
        stop: flow(link-credit=0, ...)      ---->
]]>
      </picture>
    </doc>

    <doc title="Synchronous Get">
      <p>
        A synchronous get of a message from a Link is accomplished by incrementing the link-credit,
        sending the updated <xref name="flow"/> state, and waiting indefinitely for a
        <xref name="transfer"/> to arrive.
      </p>

      <picture><![CDATA[
Receiver                                      Sender
=================================================================
                                      ...
flow(link-credit=1)               ---------->
                                        +---- transfer(...)
*block until transfer arrives*         /
                                  <---+
                                      ...
-----------------------------------------------------------------
]]>
      </picture>

      <p>
        Synchronous get with a timeout is accomplished by incrementing the link-credit, sending the
        updated <xref name="flow"/> state and waiting for the link-credit to be consumed. When the
        desired time has elapsed the Receiver then sets the drain flag and sends the newly updated
        <xref name="flow"/> state again, while continuing to wait for the link-credit to be
        consumed. Even if no messages are available, this condition will be met promptly because of
        the drain flag. Once the link-credit is consumed, the Receiver can unambiguously determine
        whether a message has arrived or whether the operation has timed out.
      </p>

      <picture><![CDATA[
    Receiver                                      Sender
    =================================================================
                                          ...
    flow(link-credit=1)               ---------->
  *wait for link-credit <= 0*
    flow(drain=True)                  ---+   +--- transfer(...)
                                          \ /
                                           x
                                          / \
(1)                                   <--+   +-->
(2)                                   <---------- flow(...)
                                          ...
    -----------------------------------------------------------------
      (1) If a message is available within the timeout, it will
          arrive at this point.
      (2) If a message is not available within the timeout, the
          drain flag will ensure that the Sender promptly advances the
          delivery-count until link-credit is consumed.
]]>
      </picture>
    </doc>

    <doc title="Asynchronous Notification">
      <p>
        Asynchronous notification can be accomplished as follows. The receiver maintains a target
        amount of link-credit for that Link. As <xref name="transfer">transfers</xref> arrive on the
        Link, the Sender's link-credit decreases as the delivery-count increases. When the Sender's
        link-credit falls below a threshold, the <xref name="flow"/> state may be sent to increase
        the Sender's link-credit back to the desired target.
      </p>

      <picture><![CDATA[
Receiver                                          Sender
=====================================================================
                                      ...
                                  <----------     transfer(...)
                                  <----------     transfer(...)
flow(link-credit=delta)           ---+   +---     transfer(...)
                                      \ /
                                       x
                                      / \
                                  <--+   +-->
                                  <----------     transfer(...)
                                  <----------     transfer(...)
flow(link-credit=delta)           ---+   +---     transfer(...)
                                      \ /
                                       x
                                      / \
                                  <--+   +-->
                                      ...
---------------------------------------------------------------------
  The incoming message rate for the Link is limited by the
  rate at which the Receiver updates the delivery-limit by
  issuing link-credit.
]]>
      </picture>
    </doc>

    <doc title="Stopping a Link">
      <p>
        Stopping the transfers on a given Link is accomplished by updating the link-credit to be
        zero and sending the updated <xref name="flow"/> state. Some transfers may be in-flight at
        the time the <xref name="flow"/> state is sent, so incoming transfers may still arrive on
        the Link. The echo field of the <xref name="flow"/> frame may be used to request the
        Sender's <xref name="flow"/> state be echoed back. This may be used to determine when the
        Link has finally quiesced.
      </p>

      <picture><![CDATA[
    Receiver                                       Sender
    ================================================================
                                           ...
                                       <---------- transfer(...)
    flow(...,                          ---+   +--- transfer(...)
         link-credit=0,                    \ /
         echo=True)                         x
                                           / \
(1)                                    <--+   +-->
(2)                                    <---------- flow(...)
                                           ...
    ----------------------------------------------------------------
      (1) In-flight transfers may still arrive until the flow state
          is updated at the Sender.
      (2) At this point no further transfers will arrive.
]]>
      </picture>
    </doc>

    <doc title="Messages">
      <p>
        The transport layer assumes as little as possible about Messages and allows alternative
        Message representations to be layered above. Message data is carried as the payload in
        frames containing the <xref name="transfer"/> performative. Messages can be fragmented
        across several <xref name="transfer"/> frames as indicated by the more flag of the <xref
        name="transfer"/> performative.
      </p>
    </doc>

    <doc title="Transferring a Message">
      <p>
        When an application initiates a message transfer, it assigns a delivery-tag used to track
        the state of the delivery while the message is in transit. A delivery is considered
        <i>unsettled</i> at the sender/receiver from the point at which it was sent/received until
        it has been <i>settled</i> by the sending/receiving application. Each delivery MUST be
        identified by a delivery-tag chosen by the sending application. The delivery-tag MUST be
        unique amongst all deliveries that could be considered unsettled by either end of the Link.
      </p>

      <p>
        Upon initiating a transfer, the application will supply the sending link endpoint (Sender)
        with the message data and its associated delivery-tag. The Sender will create an entry in
        its unsettled map, and send a transfer frame that includes the delivery-tag, its initial
        state, and its associated message data. For brevity on the wire, the delivery-tag is also
        associated with a delivery-id assigned by the session. The delivery-id is then used to refer
        to the delivery-tag in all subsequent interactions on that session.
      </p>

      <p>
        For simplicity the delivery-id is omitted in the following diagrams and the delivery-tag is
        itself used directly. These diagrams also assume that this interaction takes place in the
        context of a single established link, and as such omit other details that would be present
        on the wire in practice such as the channel number, link handle, fragmentation flags, etc,
        focusing only on the essential aspects of message transfer.
      </p>

      <picture title="Initial Transfer"><![CDATA[
  +------------------+
 /       Sender       \
+----------------------+
| unsettled:           |    transfer(delivery-tag=DT, settled=False,
|   ...                |             state=S_0, ...)
|   DT -> (local: S_0, |----------------------------------------------->
|          remote: ?)  |
|   ...                |
+----------------------+
]]>
      </picture>

      <p>
        Upon receiving the transfer, the receiving link endpoint (Receiver) will create an entry in
        its own unsettled map and make the transferred message data available to the application to
        process.
      </p>

      <picture title="Initial Receipt"><![CDATA[
                                                  +------------------+
                                                 /      Receiver      \
                                                +----------------------+
    transfer(delivery-tag=DT, settled=False,    | unsettled:           |
             state=S_0, ...)                    |   ...                |
----------------------------------------------->|   DT -> (local: S_1, |
                                                |          remote: S_0)|
                                                |   ...                |
                                                +----------------------+
]]>
      </picture>

      <p>
        Once notified of the received message data, the application processes the message,
        indicating the updated delivery state to the link endpoint as desired. Applications may wish
        to classify delivery states as <term>terminal</term> or <term>non-terminal</term> depending
        on whether an endpoint will ever update the state further once it has been reached. In some
        cases (e.g. large messages or transactions), the receiving application may wish to indicate
        non-terminal delivery states to the sender. This is done via the <xref name="disposition"/>
        frame.
      </p>

      <picture title="Indication of Non-Terminal State"><![CDATA[
                                                  +------------------+
                                                 /      Receiver      \
                                                +----------------------+
                                                | unsettled:           |
                                                |   ...                |
<-----------------------------------------------|   DT -> (local: S_2, |
    disp(role=receiver, ..., delivery-tag=DT,   |          remote: S_0)|
         settled=False, state=S_2, ...)         |   ...                |
                                                +----------------------+
]]>
      </picture>

      <p>
        Once the receiving application has finished processing the message, it indicates to the link
        endpoint a <i>terminal</i> delivery state that reflects the outcome of the application
        processing (successful or otherwise) and thus the outcome which the Receiver wishes to occur
        at the Sender. This state is communicated back to the Sender via the disposition frame.
      </p>

      <picture title="Indication of Presumptive Terminal State"><![CDATA[
                                                  +------------------+
                                                 /      Receiver      \
                                                +----------------------+
                                                | unsettled:           |
                                                |   ...                |
<-----------------------------------------------|   DT -> (local: T_0, |
    disp(role=receiver, ..., delivery-tag=DT,   |          remote: S_0)|
         settled=False, state=T_0, ...)         |   ...                |
                                                +----------------------+
]]>
      </picture>

      <p>
        Upon receiving the updated delivery state from the Receiver, the Sender will, if it has not
        already spontaneously attained a terminal state, update its view the state and communicate
        this back to the sending application.
      </p>

      <picture title="Receipt of Terminal State"><![CDATA[
  +------------------+
 /       Sender       \
+----------------------+
| unsettled:           |
|   ...                |
|   DT -> (local: S_0, |<-----------------------------------------------
|          remote: T_0)|    disp(role=receiver, ..., delivery-tag=DT,
|   ...                |         settled=False, state=T_0, ...)
+----------------------+
]]>
      </picture>

      <p>
        The sending application will then typically perform some action based on this terminal state
        and then settle the delivery, causing the Sender to remove the delivery-tag from its
        unsettled map. The Sender will then send its final delivery state along with an indication
        that the delivery is settled at the Sender. Note that this amounts to the Sender announcing
        that it is forever forgetting everything about the delivery-tag in question, and as such it
        is only possible to make such an announcement once, since after the Sender forgets, it has
        no way of remembering to make the announcement again. Should this frame get lost due to an
        interruption in communication, the Receiver will find out that the Sender has settled the
        delivery upon link recovery. When the Sender re-attaches the Receiver will examine the
        unsettled state of the Sender (i.e. what has <b>not</b> been forgotten) and from this can
        derive that the delivery in question has been settled (since its tag will not be in the
        unsettled state).
      </p>

      <picture title="Indication of Settlement"><![CDATA[
  +------------------+
 /       Sender       \
+----------------------+
| unsettled:           |    disp(role=sender, ..., delivery-tag=DT,
|   ...                |         settled=True, state=T_1, ...)
|   - -> -             |----------------------------------------------->
|   ...                |
+----------------------+
]]>
      </picture>

      <p>
        When the Receiver finds out that the Sender has settled the delivery, the Receiver will
        update its view of the remote state to indicate this, and then notify the receiving
        application.
      </p>

      <picture title="Receipt of Settlement"><![CDATA[
                                                  +------------------+
                                                 /      Receiver      \
                                                +----------------------+
     disp(role=sender, ..., delivery-tag=DT,    | unsettled:           |
          settled=True, state=T_1, ...)         |   ...                |
----------------------------------------------->|   DT -> (local: S_2, |
                                                |          remote: - ) |
                                                |   ...                |
                                                +----------------------+
]]>
      </picture>

      <p>
        The application may then perform some final action, e.g. remove the delivery-tag from a set
        kept for de-duplication, and then notify the Receiver that the delivery is settled. The
        Receiver will then remove the delivery-tag from its unsettled map. Note that because the
        Receiver knows that the delivery is already settled at the Sender, it makes no effort to
        notify the other endpoint that it is settling the delivery.
      </p>

      <picture title="Final Settlement"><![CDATA[
                                                  +------------------+
                                                 /      Receiver      \
                                                +----------------------+
                                                | unsettled:           |
                                                |   ...                |
<-----------------------------------------------|   - -> -             |
                                                |   ...                |
                                                +----------------------+
]]>
      </picture>

      <p>
        As alluded to above, it is possible for the sending application to transition a delivery to
        a terminal state at the Sender spontaneously (i.e. not as a consequence of a disposition
        that has been received from the Receiver). In this case the Sender should send a disposition
        to the Receiver, but not settle until the Receiver confirms, via a disposition in the
        opposite direction, that it has updated the state at its endpoint.
      </p>

      <p>
        This set of exchanges illustrates the basic principals of message transfer. While a delivery
        is unsettled the endpoints exchange the current state of the delivery. Eventually both
        endpoints reach a terminal state as indicated by the application. This triggers the other
        application to take some final action and settle the delivery, and once one endpoint
        settles, this usually triggers the application at the other endpoint to settle.
      </p>

      <p>
        This basic pattern can be modified in a variety of ways to achieve different guarantees, for
        example if the sending application settles the delivery <i>before</i> sending it, this
        results in an <i>at-most-once</i> guarantee. The Sender has indicated up front with his
        initial transmission that he has forgotten everything about this delivery and will therefore
        make no further attempts to send it. Should this delivery make it to the Receiver, the
        Receiver clearly has no obligation to respond with updates of the Receiver's delivery state,
        as they would be meaningless and ignored by the Sender.
      </p>

      <picture title="At-Most-Once"><![CDATA[
  +------------------+
 /       Sender       \
+----------------------+
| unsettled:           |    transfer(delivery-tag=DT, settled=True,
|   ...                |             state=T_0, ...)
|   - -> -             |----------------------------------------------->
|   ...                |
+----------------------+
]]>
      </picture>

      <p>
        Similarly, if we modify the basic scenario such that the receiving application chooses to
        settle immediately upon processing the message rather than waiting for the sender to settle
        first, we get an <i>at-least-once</i> guarantee. If the disposition frame indicated below is
        lost, then upon link recovery the Sender will not see the delivery-tag in the Receiver's
        unsettled map and will therefore assume the delivery was lost and resend it, resulting in
        duplicate processing of the message at the Receiver.
      </p>

      <picture title="At-Least-Once"><![CDATA[
                                                  +------------------+
                                                 /      Receiver      \
                                                +----------------------+
                                                | unsettled:           |
                                                |   ...                |
<-----------------------------------------------|   - -> -             |
    disp(role=receiver, ..., delivery-tag=DT,   |   ...                |
         settled=True, state=T_0, ...)          |                      |
                                                +----------------------+
]]>
      </picture>

      <p>
        As one might guess, the scenario presented initially where the sending application settles
        when the Receiver reaches a terminal state, and the receiving application settles when the
        Sender settles, results in an <i>exactly-once</i> guarantee. More generally if the Receiver
        settles prior to the Sender, it is possible for duplicate messages to occur, except in the
        case where the Sender settles before his initial transmission. Similarly, if the Sender
        settles before the Receiver reaches a terminal state, it is possible for messages to be
        lost.
      </p>

      <p>
        The Sender and Receiver policy regarding settling may either be pre-configured for the
        entire link, thereby allowing for optimized endpoint choices, or may be determined on an
        ad-hoc basis for each delivery. An application may also choose to settle at an endpoint
        independently of its delivery state, for example the sending application may choose to
        settle a delivery due to the message ttl expiring regardless of whether the Receiver has
        reached a terminal state.
      </p>

    </doc>

    <doc name="resuming-deliveries" title="Resuming Deliveries">
      <p>
        When a suspended link having unsettled deliveries is resumed, the <i>unsettled</i> field
        from the <xref name="attach"/> frame will carry the delivery-tags and delivery state of all
        deliveries considered unsettled by the issuing link endpoint. The set of delivery tags and
        delivery states contained in the unsettled maps from both endpoints can be divided into
        three categories:
      </p>

      <dl>
        <dt>Deliveries that only the Source considers unsettled</dt>
        <dd><p>Deliveries in this category MAY be resumed at the discretion of the sending
            application. If the sending application marks the resend attempt as a resumed delivery
            then it MUST be ignored by the receiver. (This allows the sender to pipeline resumes
            without risk of duplication at the sender).</p></dd>

        <dt>Deliveries that only the Target considers unsettled</dt>
        <dd><p>Deliveries in this category MUST be ignored by the Sender, and MUST be considered
            settled by the Receiver.</p></dd>

        <dt>Deliveries that both the Source and Target consider unsettled</dt>
        <dd><p>Deliveries in this category MUST be resumed by the Sender.</p></dd>
      </dl>

      <p>
        Note that in the case where an endpoint indicates that the unsettled map is incomplete, the
        absence of an entry in the unsettled map is not an indication of settlement. In this case
        the two endpoints must reduce the levels of unsettled state as much as they can by the
        Sender resuming and/or settling transfers that it observes that the Receiver considers
        unsettled.  Upon completion of this reduction of state, the two parties must suspend and
        re-attempt to resume the link.  Only when both sides have complete unsettled maps may new
        unsettled state be created by the sending of non-resuming transfers.
      </p>

      <p>
        A delivery is resumed much the same way it is initially transferred with the following
        exceptions:
      </p>

      <ul>
        <li><p>The resume flag of the <xref name="transfer"/> frame MUST be set to true when
            resuming a delivery.</p></li>
        <li><p>The Sender MAY omit message data when the Delivery State of the Receiver indicates
            retransmission is unnecessary.</p></li>
      </ul>

      <p>
        Note that unsettled delivery-tags do NOT have any valid delivery-ids associated until they
        are resumed, as the delivery-ids from their original link endpoints are meaningless to the
        new link endpoints.
      </p>
    </doc>

    <doc title="Transferring Large Messages">
      <p>
        Each <xref name="transfer"/> frame may carry an arbitrary amount of message data up to the
        limit imposed by the maximum frame size. For Messages that are too large to fit within the
        maximum frame size, additional data may be transferred in additional <xref name="transfer"/>
        frames by setting the more flag on all but the last <xref name="transfer"/> frame. When a
        message is split up into multiple <xref name="transfer"/> frames in this manner, messages
        being transferred along different links MAY be interleaved. However, messages transferred
        along a single link MUST NOT be interleaved.
      </p>

      <p>
        The sender may indicate an aborted attempt to deliver a Message by setting the abort flag on
        the last <xref type="type" name="transfer"/>. In this case the receiver MUST discard the
        Message data that was transferred prior to the abort.
      </p>

      <picture title="Outgoing Fragmentation State Diagram"><![CDATA[
              +------------+  S:XFR(M=1,A=0)
       +------|  NOT_SENT  |------+
       |      +------------+      |
       |                          |
       | S:XFR(M=0,A=0)           |
       |                          |     S:XFR(M=1,A=0)
       |                          |      +----------+
       |                          |      |          |
       |                         \|/    \|/         |
       |                       +------------+       |
       |      +----------------|  SENDING   |-------+
       |      | S:XFR(M=0,A=0) +------------+
       |      |                      |
       |      |                      |
       |      |                      | S:XFR(M=0,A=1)
       |      |                      |
      \|/    \|/                    \|/
    +------------+             +------------+
    |    SENT    |             |  ABORTED   |
    +------------+             +------------+

Key: S:XFR(M=?,A=?) --> Sent TRANSFER(more=?, aborted=?)
]]>
      </picture>

      <picture title="Incoming Fragmentation State Diagram"><![CDATA[
              +------------+  R:XFR(M=1,A=0)
       +------|  NOT_RCVD  |------+
       |      +------------+      |
       |                          |
       | R:XFR(M=0,A=0)           |
       |                          |     R:XFR(M=1,A=0)
       |                          |      +----------+
       |                          |      |          |
       |                         \|/    \|/         |
       |                       +------------+       |
       |      +----------------| RECEIVING  |-------+
       |      | R:XFR(M=0,A=0) +------------+
       |      |                      |
       |      |                      |
       |      |                      | R:XFR(M=0,A=1)
       |      |                      |
      \|/    \|/                    \|/
    +------------+             +------------+
    |  RECEIVED  |             |  ABORTED   |
    +------------+             +------------+

Key: R:XFR(M=?,A=?) --> Received TRANSFER(more=?, aborted=?)
]]>
      </picture>
    </doc>

  </section>

  <section name="performatives" label="composite types that appear as frame bodies">

    <!-- - Frame: open - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="open" source="list" provides="frame"
          label="negotiate Connection parameters">
      <doc>
        <p>
          The first frame sent on a connection in either direction MUST contain an Open body. (Note
          that the Connection header which is sent first on the Connection is *not* a frame.) The
          fields indicate the capabilities and limitations of the sending peer.
        </p>
      </doc>

      <descriptor name="amqp:open:list" code="0x00000000:0x00000010"/>

      <field name="container-id" type="string" mandatory="true"
             label="the id of the source container"/>

      <field name="hostname" type="string" label="the name of the target host">
        <doc>
          <p>
            The dns name of the host (either fully qualified or relative) to which the sending peer
            is connecting. It is not mandatory to provide the hostname. If no hostname is provided
            the receiving peer should select a default based on its own configuration. This field
            can be used by AMQP proxies to determine the correct back-end service to connect
            the client to.
          </p>

          <p>
            This field may already have been specified by the <xref name="sasl-init"/> frame, if a
            SASL layer is used, or, the server name indication extension as described in
            RFC-4366, if a TLS layer is used, in which case this field SHOULD be null or contain
            the same value. It is undefined what a different value to those already specific means.
          </p>
        </doc>
      </field>

      <field name="max-frame-size" type="uint" default="4294967295"
             label="proposed maximum frame size">
        <doc>
          <p>
            The largest frame size that the sending peer is able to accept on this Connection. If
            this field is not set it means that the peer does not impose any specific limit. A peer
            MUST NOT send frames larger than its partner can handle. A peer that receives an
            oversized frame MUST close the Connection with the framing-error error-code.
          </p>

          <p>
            Both peers MUST accept frames of up to <xref name="MIN-MAX-FRAME-SIZE"/> octets
            large.
          </p>
        </doc>
      </field>

      <field name="channel-max" type="ushort" default="65535"
             label="the maximum channel number that may be used on the Connection">
        <doc>
          <p>
            The channel-max value is the highest channel number that may be used on the Connection.
            This value plus one is the maximum number of Sessions that can be simultaneously active
            on the Connection. A peer MUST not use channel numbers outside the range that its
            partner can handle. A peer that receives a channel number outside the supported range
            MUST close the Connection with the framing-error error-code.
          </p>
        </doc>
      </field>

      <field name="idle-time-out" type="milliseconds" label="idle time-out">
        <doc>
          <p>
            The idle time-out required by the sender. A value of zero is the same as if it was
            not set (null). If the receiver is unable or unwilling to support the idle time-out
            then it should close the connection with an error explaining why (eg, because it is
            too small).
          </p>

          <p>
            If the value is not set, then the sender does not have an idle time-out. However,
            senders doing this should be aware that implementations MAY choose to use an
            internal default to efficiently manage a peer's resources.
          </p>
        </doc>
      </field>

      <field name="outgoing-locales" type="ietf-language-tag" multiple="true"
             label="locales available for outgoing text">
        <doc>
          <p>
            A list of the locales that the peer supports for sending informational text. This
            includes Connection, Session and Link error descriptions. A peer MUST support at least
            the <i>en-US</i> locale (see <xref name="ietf-language-tag"/>). Since this value is
            always supported, it need not be supplied in the outgoing-locales. A null value or an
            empty list implies that only <i>en-US</i> is supported.
          </p>
        </doc>
      </field>

      <field name="incoming-locales" type="ietf-language-tag" multiple="true"
             label="desired locales for incoming text in decreasing level of preference">
        <doc>
          <p>
            A list of locales that the sending peer permits for incoming informational text. This
            list is ordered in decreasing level of preference. The receiving partner will chose the
            first (most preferred) incoming locale from those which it supports. If none of the
            requested locales are supported, <i>en-US</i> will be chosen. Note that <i>en-US</i>
            need not be supplied in this list as it is always the fallback. A peer may determine
            which of the permitted incoming locales is chosen by examining the partner's supported
            locales as specified in the outgoing-locales field. A null value or an empty list
            implies that only <i>en-US</i> is supported.
          </p>
        </doc>
      </field>

      <field name="offered-capabilities" type="symbol" multiple="true"
             label="the extension capabilities the sender supports">
        <doc>
          <p>
            If the receiver of the offered-capabilities requires an extension capability which is
            not present in the offered-capability list then it MUST close the connection.
          </p>
          <p>
            A list of commonly defined connection capabilities and their meanings can be found here:
            <xref type="extern"
            name="http://www.amqp.org/specification/1.0/connection-capabilities"/>.
          </p>
        </doc>
      </field>

      <field name="desired-capabilities" type="symbol" multiple="true"
             label="the extension capabilities the sender may use if the receiver supports them">
        <doc>
          <p>
            The desired-capability list defines which extension capabilities the sender MAY use if
            the receiver offers them (i.e. they are in the offered-capabilities list received by the
            sender of the desired-capabilities). If the receiver of the desired-capabilities offers
            extension capabilities which are not present in the desired-capability list it received,
            then it can be sure those (undesired) capabilities will not be used on the
            Connection.
          </p>
        </doc>
      </field>

      <field name="properties" type="fields" label="connection properties">
        <doc>
          <p>
            The properties map contains a set of fields intended to indicate information about the
            connection and its container.
          </p>
          <p>
            A list of commonly defined connection properties and their meanings can be found here:
            <xref type="extern" name="http://www.amqp.org/specification/1.0/connection-properties"/>
          </p>
        </doc>
      </field>
    </type>

    <!-- - Frame: begin  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="begin" source="list" provides="frame"
          label="begin a Session on a channel">
      <doc>
        <p>
          Indicate that a Session has begun on the channel.
        </p>
      </doc>

      <descriptor name="amqp:begin:list" code="0x00000000:0x00000011"/>

      <field name="remote-channel" type="ushort" label="the remote channel for this Session">
        <doc>
          <p>
            If a Session is locally initiated, the remote-channel MUST NOT be set. When an endpoint
            responds to a remotely initiated Session, the remote-channel MUST be set to the channel
            on which the remote Session sent the begin.
          </p>
        </doc>
      </field>

      <field name="next-outgoing-id" type="transfer-number" mandatory="true"
             label="the transfer-id of the first transfer id the sender will send">
        <doc>
          <p>See <xref type="doc" name="session-flow-control"/>.</p>
        </doc>
      </field>

      <field name="incoming-window" type="uint" mandatory="true"
             label="the initial incoming-window of the sender">
        <doc>
          <p>See <xref name="session-flow-control"/>.</p>
        </doc>
      </field>

      <field name="outgoing-window" type="uint" mandatory="true"
             label="the initial outgoing-window of the sender">
        <doc>
          <p>See <xref name="session-flow-control"/>.</p>
        </doc>
      </field>

      <field name="handle-max" type="handle" default="4294967295"
             label="the maximum handle value that may be used on the Session">
        <doc>
          <p>
            The handle-max value is the highest handle value that may be used on the Session.
            A peer MUST NOT attempt to attach a Link using a handle value outside the range that its
            partner can handle. A peer that receives a handle outside the supported range MUST close
            the Connection with the framing-error error-code.
          </p>
        </doc>
      </field>

      <field name="offered-capabilities" type="symbol" multiple="true"
             label="the extension capabilities the sender supports">
        <doc>
          <p>
            A list of commonly defined session capabilities and their meanings can be found here:
            <xref type="extern" name="http://www.amqp.org/specification/1.0/session-capabilities"/>.
          </p>
        </doc>
      </field>

      <field name="desired-capabilities" type="symbol" multiple="true"
             label="the extension capabilities the sender may use if the receiver supports them"/>

      <field name="properties" type="fields" label="session properties">
        <doc>
          <p>
            The properties map contains a set of fields intended to indicate information about the
            session and its container.
          </p>
          <p>
            A list of commonly defined session properties and their meanings can be found here:
            <xref type="extern" name="http://www.amqp.org/specification/1.0/session-properties"/>.
          </p>
        </doc>
      </field>
    </type>

    <!-- - Frame: attach - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="attach" source="list" provides="frame"
          label="attach a Link to a Session">
      <doc>
        <p>
          The <xref type="type" name="attach"/> frame indicates that a Link Endpoint has been
          attached to the Session. The opening flag is used to indicate that the Link Endpoint is
          newly created.
        </p>
      </doc>

      <descriptor name="amqp:attach:list" code="0x00000000:0x00000012"/>

      <field name="name" type="string" mandatory="true" label="the name of the link">
        <doc>
          <p>
            This name uniquely identifies the link from the container of the source to the container
            of the target node, e.g. if the container of the source node is A, and the container of
            the target node is B, the link may be globally identified by the (ordered) tuple
            <i>(A,B,&lt;name&gt;)</i>.
          </p>
        </doc>
      </field>

      <field name="handle" type="handle" mandatory="true">
        <doc>
          <p>
            The handle MUST NOT be used for other open Links. An attempt to attach using a handle
            which is already associated with a Link MUST be responded to with an immediate
            <xref name="close"/> carrying a Handle-in-use <xref name="session-error"/>.
           </p>
           <p>
             To make it easier to monitor AMQP link attach frames, it is recommended that
             implementations always assign the lowest available handle to this field.
           </p>
        </doc>
      </field>

      <field name="role" type="role" mandatory="true" label="role of the link endpoint"/>

      <field name="snd-settle-mode" type="sender-settle-mode" default="mixed"
             label="settlement mode for the Sender">

        <doc>
          <p>
            Determines the settlement policy for deliveries sent at the Sender. When set at the
            Receiver this indicates the desired value for the settlement mode at the Sender.  When
            set at the Sender this indicates the actual settlement mode in use.
          </p>
        </doc>
      </field>

      <field name="rcv-settle-mode" type="receiver-settle-mode" default="first"
             label="the settlement mode of the Receiver">
        <doc>
          <p>
            Determines the settlement policy for unsettled deliveries received at the Receiver. When
            set at the Sender this indicates the desired value for the settlement mode at the
            Receiver. When set at the Receiver this indicates the actual settlement mode in use.
          </p>
        </doc>
      </field>

      <field name="source" type="*" requires="source" label="the source for Messages">
        <doc>
          <p>
            If no source is specified on an outgoing Link, then there is no source currently
            attached to the Link. A Link with no source will never produce outgoing Messages.
          </p>
        </doc>
      </field>

      <field name="target" type="*" requires="target" label="the target for Messages">
        <doc>
          <p>
            If no target is specified on an incoming Link, then there is no target currently
            attached to the Link. A Link with no target will never permit incoming Messages.
          </p>
        </doc>
      </field>

      <field name="unsettled" type="map" label="unsettled delivery state">
        <doc>
          <p>
            This is used to indicate any unsettled delivery states when a suspended link is resumed.
            The map is keyed by delivery-tag with values indicating the delivery state. The local
            and remote delivery states for a given delivery-tag MUST be compared to resolve any
            in-doubt deliveries. If necessary, deliveries MAY be resent, or resumed based on the
            outcome of this comparison. See <xref name="resuming-deliveries"/>.
          </p>

          <p>
            If the local unsettled map is too large to be encoded within a frame of the agreed
            maximum frame size then the session may be ended with the frame-size-too-small error
            (see <xref name="amqp-error"/>). The endpoint SHOULD make use of the ability to send an
            incomplete unsettled map (see below) to avoid sending an error.
          </p>

          <p>
            The unsettled map MUST NOT contain null valued keys.
          </p>

          <p>
            When reattaching (as opposed to resuming), the unsettled map MUST be null.
          </p>
        </doc>
      </field>

      <field name="incomplete-unsettled" type="boolean" default="false">
        <doc>
          <p>
            If set to true this field indicates that the unsettled map provided is not complete.
            When the map is incomplete the recipient of the map cannot take the absence of a
            delivery tag from the map as evidence of settlement. On receipt of an incomplete
            unsettled map a sending endpoint MUST NOT send any new deliveries (i.e. deliveries where
            resume is not set to true) to its partner (and a receiving endpoint which sent an
            incomplete unsettled map MUST detach with an error on receiving a transfer which does
            not have the resume flag set to true).
          </p>
        </doc>
      </field>

      <field name="initial-delivery-count" type="sequence-no">
        <doc>
          <p>
            This MUST NOT be null if role is sender, and it is ignored if the role is receiver. See
            <xref name="flow-control"/>.
          </p>
        </doc>
      </field>


      <field name="max-message-size" type="ulong"
             label="the maximum message size supported by the link endpoint">
        <doc>
          <p>
            This field indicates the maximum message size supported by the link endpoint. Any
            attempt to deliver a message larger than this results in a message-size-exceeded
            <xref name="link-error"/>. If this field is zero or unset, there is no maximum size
            imposed by the link endpoint.
          </p>
        </doc>
      </field>

      <field name="offered-capabilities" type="symbol" multiple="true"
             label="the extension capabilities the sender supports">
        <doc>
          <p>
            A list of commonly defined session capabilities and their meanings can be found here:
            <xref type="extern" name="http://www.amqp.org/specification/1.0/link-capabilities"/>.
          </p>
        </doc>
      </field>

      <field name="desired-capabilities" type="symbol" multiple="true"
             label="the extension capabilities the sender may use if the receiver supports them"/>

      <field name="properties" type="fields" label="link properties">
        <doc>
          <p>
            The properties map contains a set of fields intended to indicate information about the
            link and its container.
          </p>
          <p>
            A list of commonly defined link properties and their meanings can be found here:
            <xref type="extern" name="http://www.amqp.org/specification/1.0/link-properties"/>
          </p>
        </doc>
      </field>
    </type>

    <!-- - Frame: flow - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="flow" source="list" provides="frame" label="update link state">
      <doc>
        <p>Updates the flow state for the specified Link.</p>
      </doc>

      <descriptor name="amqp:flow:list" code="0x00000000:0x00000013"/>

      <field name="next-incoming-id" type="transfer-number">
        <doc>
          <p>
            Identifies the expected transfer-id of the next incoming <xref name="transfer"/> frame.
            This value is not set if and only if the sender has not yet received the
            <xref name="begin"/> frame for the session. See
            <xref type="doc" name="session-flow-control"/> for more details.
          </p>
        </doc>
      </field>

      <field name="incoming-window" type="uint" mandatory="true">
        <doc>
          <p>
            Defines the maximum number of incoming <xref name="transfer"/> frames that the endpoint
            can currently receive. See <xref type="doc" name="session-flow-control"/> for more
            details.
          </p>
        </doc>
      </field>

      <field name="next-outgoing-id" type="transfer-number" mandatory="true">
        <doc>
          <p>
            The transfer-id that will be assigned to the next outgoing <xref name="transfer"/>
            frame. See <xref type="doc" name="session-flow-control"/> for more details.
          </p>
        </doc>
      </field>

      <field name="outgoing-window" type="uint" mandatory="true">
        <doc>
          <p>
            Defines the maximum number of outgoing <xref name="transfer"/> frames that the endpoint
            could potentially currently send, if it was not constrained by restrictions imposed by
            its peer's incoming-window. See <xref type="doc" name="session-flow-control"/> for more
            details.
          </p>
        </doc>
      </field>

      <field name="handle" type="handle">
        <doc>
          <p>
            If set, indicates that the flow frame carries flow state information for the local Link
            Endpoint associated with the given handle.  If not set, the flow frame is carrying only
            information pertaining to the Session Endpoint.
          </p>
          <p>
            If set to a handle that is not currently associated with an attached Link, the
            recipient MUST respond by ending the session with an <xref choice="unattached-handle"
            name="session-error"/> session error.
          </p>
        </doc>
      </field>

      <field name="delivery-count" type="sequence-no" label="the endpoint's delivery-count">
        <doc>
          <p>
            When the handle field is not set, this field MUST NOT be set.
          </p>
          <p>
            When the handle identifies that the flow state is being sent from the Sender Link
            Endpoint to Receiver Link Endpoint this field MUST be set to the current delivery-count
            of the Link Endpoint.
          </p>
          <p>
            When the flow state is being sent from the Receiver Endpoint to the Sender Endpoint this
            field MUST be set to the last known value of the corresponding Sending Endpoint. In the
            event that the Receiving Link Endpoint has not yet  seen the initial
            <xref name="attach"/> frame from the Sender this field MUST NOT be set.
          </p>
          <p>
            See <xref type="doc" name="flow-control"/> for more details.
          </p>
        </doc>
      </field>

      <field name="link-credit" type="uint"
             label="the current maximum number of Messages that can be received">
        <doc>
          <p>
            The current maximum number of Messages that can be handled at the Receiver
            Endpoint of the Link. Only the receiver endpoint can independently set this value. The
            sender endpoint sets this to the last known value seen from the receiver. See
            <xref type="doc" name="flow-control"/> for more details.
          </p>
          <p>
            When the handle field is not set, this field MUST NOT be set.
          </p>
        </doc>
      </field>

      <field name="available" type="uint" label="the number of available Messages">
        <doc>
          <p>
            The number of Messages awaiting credit at the link sender endpoint. Only the
            sender can independently set this value. The receiver sets this to the last known value
            seen from the sender. See <xref type="doc" name="flow-control"/> for more details.
          </p>
          <p>
            When the handle field is not set, this field MUST NOT be set.
          </p>
        </doc>
      </field>

      <field name="drain" type="boolean" default="false" label="indicates drain mode">
        <doc>
          <p>
            When flow state is sent from the sender to the receiver, this field contains the actual
            drain mode of the sender. When flow state is sent from the receiver to the sender, this
            field contains the desired drain mode of the receiver. See <xref type="doc"
            name="flow-control"/> for more details.
          </p>
          <p>
            When the handle field is not set, this field MUST NOT be set.
          </p>
        </doc>
      </field>

      <field name="echo" type="boolean" default="false"
             label="request link state from other endpoint"/>

      <field name="properties" type="fields" label="link state properties">
        <doc>
          <p>
            A list of commonly defined link state properties and their meanings can be found here:
            <xref type="extern" name="http://www.amqp.org/specification/1.0/link-state-properties"/>
          </p>
        </doc>
      </field>
    </type>

    <!-- - Frame: transfer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="transfer" source="list" provides="frame"
          label="transfer a Message">
      <doc>
        <p>
          The transfer frame is used to send Messages across a Link. Messages may be carried by a
          single transfer up to the maximum negotiated frame size for the Connection. Larger
          Messages may be split across several transfer frames.
        </p>
      </doc>

      <descriptor name="amqp:transfer:list" code="0x00000000:0x00000014"/>

      <field name="handle" type="handle" mandatory="true">
        <doc>
          <p>Specifies the Link on which the Message is transferred.</p>
        </doc>
      </field>

      <field name="delivery-id" type="delivery-number" label="alias for delivery-tag">
        <doc>
          <p>
            The delivery-id MUST be supplied on the first transfer of a multi-transfer delivery. On
            continuation transfers the delivery-id MAY be omitted. It is an error if the delivery-id
            on a continuation transfer differs from the delivery-id on the first transfer of a
            delivery.
          </p>
        </doc>
      </field>

      <field name="delivery-tag" type="delivery-tag">
        <doc>
          <p>
            Uniquely identifies the delivery attempt for a given Message on this Link. This field
            MUST be specified for the first transfer of a multi transfer message and may only be
            omitted for continuation transfers.
          </p>
        </doc>
      </field>

      <field name="message-format" type="message-format" label="indicates the message format">
        <doc>
          <p>
            This field MUST be specified for the first transfer of a multi transfer message and may
            only be omitted for continuation transfers.
          </p>
        </doc>
      </field>

      <field name="settled" type="boolean">
        <doc>
          <p>
             If not set on the first (or only) transfer for a delivery, then the settled flag MUST
             be interpreted as being false. For subsequent transfers if the settled flag is left
             unset then it MUST be interpreted as true if and only if the value of the settled flag
             on any of the preceding transfers was true; if no preceding transfer was sent with
             settled being true then the value when unset MUST be taken as false.
          </p>
          <p>
             If the negotiated value for snd-settle-mode at attachment is <xref
             name="sender-settle-mode" choice="settled"/>, then this field MUST be true on at least
             one transfer frame for a delivery (i.e. the delivery must be settled at the Sender at
             the point the delivery has been completely transferred).
          </p>
          <p>
             If the negotiated value for snd-settle-mode at attachment is <xref
             name="sender-settle-mode" choice="unsettled"/>, then this field MUST be false (or
             unset) on every transfer frame for a delivery (unless the delivery is aborted).
          </p>
        </doc>
      </field>

      <field name="more" type="boolean" default="false"
             label="indicates that the Message has more content">
        <doc>
          <p>
            Note that if both the more and aborted fields are set to true, the aborted flag takes
            precedence. That is a receiver should ignore the value of the more field if the
            transfer is marked as aborted. A sender SHOULD NOT set the more flag to true if it
            also sets the aborted flag to true.
          </p>
        </doc>
      </field>

      <field name="rcv-settle-mode" type="receiver-settle-mode">
        <doc>
          <p>
            If <xref name="receiver-settle-mode" choice="first"/>, this indicates that the
            Receiver MUST settle the delivery once it has arrived without waiting for the Sender to
            settle first.
          </p>
          <p>
            If <xref name="receiver-settle-mode" choice="second"/>, this indicates that the
            Receiver MUST NOT settle until sending its disposition to the Sender and receiving a
            settled disposition from the sender.
          </p>
          <p>
            If not set, this value is defaulted to the value negotiated on link attach.
          </p>
          <p>
            If the negotiated link value is <xref name="receiver-settle-mode" choice="first"/>,
            then it is illegal to set this field to <xref name="receiver-settle-mode"
            choice="second"/>.
          </p>
          <p>
            If the message is being sent settled by the Sender, the value of this field is ignored.
          </p>
          <p>
            The (implicit or explicit) value of this field does not form part of the transfer state,
            and is not retained if a link is suspended and subsequently resumed.
          </p>
        </doc>
      </field>

      <field name="state" type="*" requires="delivery-state"
             label="the state of the delivery at the sender">
        <doc>
          <p>
            When set this informs the receiver of the state of the delivery at the sender. This is
            particularly useful when transfers of unsettled deliveries are resumed after a resuming
            a link. Setting the state on the transfer can be thought of as being equivalent to
            sending a disposition immediately before the <xref name="transfer"/> performative, i.e.
            it is the state of the delivery (not the transfer) that existed at the point the frame
            was sent.
          </p>
          <p>
            Note that if the <xref name="transfer"/> performative (or an earlier <xref
            name="disposition"/> performative referring to the delivery) indicates that the delivery
            has attained a terminal state, then no future <xref name="transfer"/> or <xref
            name="disposition"/> sent by the sender can alter that terminal state.
          </p>
        </doc>
      </field>

      <field name="resume" type="boolean" default="false" label="indicates a resumed delivery">
        <doc>
          <p>
            If true, the resume flag indicates that the transfer is being used to reassociate an
            unsettled delivery from a dissociated link endpoint. See
            <xref name="resuming-deliveries"/> for more details.
          </p>
          <p>
            The receiver MUST ignore resumed deliveries that are not in its local unsettled map. The
            sender MUST NOT send resumed transfers for deliveries not in its local unsettled map.
          </p>
          <p>
            If a resumed delivery spans more than one transfer performative, then the resume flag
            MUST be set to true on the first transfer of the resumed delivery.  For subsequent
            transfers for the same delivery the resume flag may be set to true, or may be omitted.
          </p>
          <p>
            In the case where the exchange of unsettled maps makes clear that all message data has
            been successfully transferred to the receiver, and that only the final state (and
            potentially settlement) at the sender needs to be conveyed, then a resumed delivery may
            carry no payload and instead act solely as a vehicle for carrying the terminal state of
            the delivery at the sender.
           </p>
        </doc>
      </field>

      <field name="aborted" type="boolean" default="false"
             label="indicates that the Message is aborted">
        <doc>
          <p>
            Aborted Messages should be discarded by the recipient (any payload within the frame
            carrying the performative MUST be ignored). An aborted Message is implicitly settled.
          </p>
        </doc>
      </field>

      <field name="batchable" type="boolean" default="false" label="batchable hint">
        <doc>
          <p>
            If true, then the issuer is hinting that there is no need for the peer to urgently
            communicate updated delivery state. This hint may be used to artificially increase the
            amount of batching an implementation uses when communicating delivery states, and
            thereby save bandwidth.
          </p>
          <p>
            If the message being delivered is too large to fit within a single frame, then the
            setting of batchable to true on any of the <xref name="transfer"/> performatives for the
            delivery is equivalent to setting batchable to true for all the <xref name="transfer"/>
            performatives for the delivery.
          </p>
          <p>
            The batchable value does not form part of the transfer state, and is not retained if
            a link is suspended and subsequently resumed.
          </p>
        </doc>
      </field>
    </type>

    <!-- - Frame: disposition  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="disposition" source="list" provides="frame"
          label="inform remote peer of delivery state changes">
      <doc>
        <p>
          The disposition frame is used to inform the remote peer of local changes in the state of
          deliveries. The disposition frame may reference deliveries from many different links
          associated with a session, although all links MUST have the directionality indicated by
          the specified <i>role</i>.
        </p>
        <p>
          Note that it is possible for a disposition sent from sender to receiver to refer to a
          delivery which has not yet completed (i.e. a delivery which is spread over multiple
          frames and not all frames have yet been sent). The use of such interleaving is
          discouraged in favor of carrying the modified state on the next <xref name="transfer"/>
          performative for the delivery.
        </p>
        <p>
          The disposition performative may refer to deliveries on links that are no longer attached.
          As long as the links have not been closed or detached with an error then the deliveries
          are still "live" and the updated state MUST be applied.
        </p>
      </doc>

      <descriptor name="amqp:disposition:list" code="0x00000000:0x00000015"/>

      <field name="role" type="role" mandatory="true" label="directionality of disposition">
        <doc>
          <p>
            The role identifies whether the disposition frame contains information
            about <i>sending</i> link endpoints or <i>receiving</i> link endpoints.
          </p>
        </doc>
      </field>

      <field name="first" type="delivery-number" mandatory="true" label="lower bound of deliveries">
        <doc>
          <p>
            Identifies the lower bound of delivery-ids for the deliveries in this set.
          </p>
        </doc>
      </field>

      <field name="last" type="delivery-number" label="upper bound of deliveries">
        <doc>
          <p>
            Identifies the upper bound of delivery-ids for the deliveries in this set. If not set,
            this is taken to be the same as <i>first</i>.
          </p>
        </doc>
      </field>

      <field name="settled" type="boolean" default="false" label="indicates deliveries are settled">
        <doc>
          <p>
            If true, indicates that the referenced deliveries are considered settled by the issuing
            endpoint.
          </p>
        </doc>
      </field>

      <field name="state" type="*" requires="delivery-state" label="indicates state of deliveries">
        <doc>
          <p>
            Communicates the state of all the deliveries referenced by this disposition.
          </p>
        </doc>
      </field>

      <field name="batchable" type="boolean" default="false" label="batchable hint">
        <doc>
          <p>
            If true, then the issuer is hinting that there is no need for the peer to urgently
            communicate the impact of the updated delivery states. This hint may be used to
            artificially increase the amount of batching an implementation uses when communicating
            delivery states, and thereby save bandwidth.
          </p>
        </doc>
      </field>
    </type>

    <!-- - Frame: detach - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="detach" source="list" provides="frame"
          label="detach the Link Endpoint from the Session" >
      <doc>
        <p>
          Detach the Link Endpoint from the Session. This un-maps the handle and makes it available
          for use by other Links.
        </p>
      </doc>

      <descriptor name="amqp:detach:list" code="0x00000000:0x00000016"/>

      <field name="handle" type="handle" mandatory="true"
             label="the local handle of the link to be detached"/>

      <field name="closed" type="boolean" default="false"
             label="if true then the sender has closed the link">
        <doc>
          <p>See <xref name="closing-a-link"/>.</p>
        </doc>
      </field>

      <field name="error" type="error" label="error causing the detach">
        <doc>
          <p>
            If set, this field indicates that the Link is being detached due to an error condition.
            The value of the field should contain details on the cause of the error.
          </p>
        </doc>
      </field>
    </type>

    <!-- - Frame: end  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="end" source="list" provides="frame" label="end the Session">
      <doc>
        <p>Indicates that the Session has ended.</p>
      </doc>

      <descriptor name="amqp:end:list" code="0x00000000:0x00000017"/>

      <field name="error" type="error" label="error causing the end">
        <doc>
          <p>
            If set, this field indicates that the Session is being ended due to an error condition.
            The value of the field should contain details on the cause of the error.
          </p>
        </doc>
      </field>
    </type>

    <!-- - Frame: close  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <type class="composite" name="close" source="list" provides="frame"
          label="signal a Connection close">
      <doc>
        <p>
          Sending a close signals that the sender will not be sending any more frames (or bytes of
          any other kind) on the Connection. Orderly shutdown requires that this frame MUST be
          written by the sender. It is illegal to send any more frames (or bytes of any other kind)
          after sending a close frame.
        </p>
      </doc>

      <descriptor name="amqp:close:list" code="0x00000000:0x00000018"/>

      <field name="error" type="error" label="error causing the close">
        <doc>
          <p>
            If set, this field indicates that the Connection is being closed due to an error
            condition. The value of the field should contain details on the cause of the error.
          </p>
        </doc>
      </field>
    </type>

  </section>

  <section name="definitions" label="supporting definitions">

    <type class="restricted" name="role" source="boolean" label="link endpoint role">
      <choice name="sender" value="false" />
      <choice name="receiver" value="true" />
    </type>

    <type class="restricted" name="sender-settle-mode" source="ubyte"
          label="settlement policy for a Sender">
      <choice name="unsettled" value="0">
        <doc>
          <p>
            The Sender will send all deliveries initially unsettled to the Receiver.
          </p>
        </doc>
      </choice>
      <choice name="settled" value="1">
        <doc>
          <p>
            The Sender will send all deliveries settled to the Receiver.
          </p>
        </doc>
      </choice>
      <choice name="mixed" value="2">
        <doc>
          <p>
            The Sender may send a mixture of settled and unsettled deliveries to the Receiver.
          </p>
        </doc>
      </choice>
    </type>

    <type class="restricted" name="receiver-settle-mode" source="ubyte"
          label="settlement policy for a Receiver">
      <choice name="first" value="0">
        <doc>
          <p>
            The Receiver will spontaneously settle all incoming transfers.
          </p>
        </doc>
      </choice>
      <choice name="second" value="1">
        <doc>
          <p>
            The Receiver will only settle after sending the <xref name="disposition"/> to the Sender
            and receiving a <xref name="disposition"/> indicating settlement of the delivery from
            the sender.
          </p>
        </doc>
      </choice>
    </type>

    <type class="restricted" name="handle" source="uint" label="the handle of a Link">
      <doc>
        <p>
          An alias established by the <xref type="type" name="attach"/> frame and subsequently used
          by endpoints as a shorthand to refer to the Link in all outgoing frames. The two endpoints
          may potentially use different handles to refer to the same Link. Link handles may be
          reused once a Link is closed for both send and receive.
        </p>
      </doc>
    </type>

    <type class="restricted" name="seconds" source="uint" label="a duration measured in seconds"/>

    <type class="restricted" name="milliseconds" source="uint"
          label="a duration measured in milliseconds"/>

    <type class="restricted" name="delivery-tag" source="binary">
       <doc>
         <p>
           A delivery-tag may be up to 32 octets of binary data.
         </p>
      </doc>
    </type>

    <type class="restricted" name="delivery-number" source="sequence-no"/>

    <type class="restricted" name="transfer-number" source="sequence-no"/>

    <type class="restricted" name="sequence-no" source="uint" label="32-bit RFC-1982 serial number">
      <doc>
        <p>
          A sequence-no encodes a serial number as defined in RFC-1982. The arithmetic, and
          operators for these numbers are defined by RFC-1982.
        </p>
      </doc>
    </type>

    <type class="restricted" name="message-format" source="uint" label="32-bit message format code">
      <doc>
        <p>
          The upper three octets of a message format code identify a particular message format. The
          lowest octet indicates the version of said message format. Any given version of a format
          is forwards compatible with all higher versions.
        </p>

        <picture><![CDATA[
      3 octets      1 octet
 +----------------+---------+
 | message format | version |
 +----------------+---------+
 |                          |
msb                        lsb
]]>
      </picture>
      </doc>
    </type>

    <type class="restricted" name="ietf-language-tag" source="symbol"
          label="an IETF language tag as defined by BCP 47">
      <doc>
        <p>
          IETF language tags are abbreviated language codes as defined in the IETF Best Current
          Practice <xref type="extern" name="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">BCP-47
          </xref> (incorporating <xref type="extern"
          name="http://www.rfc-editor.org/rfc/rfc5646.txt">RFC-5646</xref>). A list of registered
          subtags is maintained in the <xref type="extern"
          name="http://www.iana.org/assignments/language-subtag-registry">IANA Language Subtag
          Registry</xref>.
        </p>
        <p>
          All AMQP implementations should understand at the least the IETF language tag
          <i>en-US</i> (note that this uses a hyphen separator, not an underscore).
        </p>
      </doc>
    </type>

    <type class="restricted" name="fields" source="map" label="a mapping from field name to value">
      <doc>
        <p>
          The <i>fields</i> type is a map where the keys are restricted to be of type <xref
          name="symbol"/> (this excludes the possibility of a null key). There is no further
          restriction implied by the <i>fields</i> type on the allowed values for the entries or the
          set of allowed keys.
        </p>
      </doc>
    </type>

    <type class="composite" name="error" source="list" label="details of an error">

      <descriptor name="amqp:error:list" code="0x00000000:0x0000001d"/>

      <field name="condition" type="symbol" requires="error-condition" mandatory="true"
             label="error condition">
        <doc>
          <p>A symbolic value indicating the error condition.</p>
        </doc>
      </field>

      <field name="description" type="string" label="descriptive text about the error condition">
        <doc>
          <p>
            This text supplies any supplementary details not indicated by the condition field. This
            text can be logged as an aid to resolving issues.
          </p>
        </doc>
      </field>

      <field name="info" type="fields" label="map carrying information about the error condition"/>
    </type>

    <type class="restricted" name="amqp-error" source="symbol" provides="error-condition"
          label="shared error conditions">

      <choice name="internal-error" value="amqp:internal-error">
        <doc>
          <p>
            An internal error occurred. Operator intervention may be required to resume normal
            operation.
          </p>
        </doc>
      </choice>

      <choice name="not-found" value="amqp:not-found">
        <doc>
          <p>A peer attempted to work with a remote entity that does not exist.</p>
        </doc>
      </choice>

      <choice name="unauthorized-access" value="amqp:unauthorized-access">
        <doc>
          <p>
            A peer attempted to work with a remote entity to which it has no access due to security
            settings.
          </p>
        </doc>
      </choice>

      <choice name="decode-error" value="amqp:decode-error">
        <doc>
          <p>Data could not be decoded.</p>
        </doc>
      </choice>

      <choice name="resource-limit-exceeded" value="amqp:resource-limit-exceeded">
        <doc>
          <p>A peer exceeded its resource allocation.</p>
        </doc>
      </choice>

      <choice name="not-allowed" value="amqp:not-allowed">
        <doc>
          <p>
            The peer tried to use a frame in a manner that is inconsistent with the semantics
            defined in the specification.
          </p>
        </doc>
      </choice>

      <choice name="invalid-field" value="amqp:invalid-field">
        <doc>
          <p>
            An invalid field was passed in a frame body, and the operation could not proceed.
          </p>
        </doc>
      </choice>

      <choice name="not-implemented" value="amqp:not-implemented">
        <doc>
          <p>The peer tried to use functionality that is not implemented in its partner.</p>
        </doc>
      </choice>

      <choice name="resource-locked" value="amqp:resource-locked">
        <doc>
          <p>
            The client attempted to work with a server entity to which it has no access because
            another client is working with it.
          </p>
        </doc>
      </choice>

      <choice name="precondition-failed" value="amqp:precondition-failed">
        <doc>
          <p>
            The client made a request that was not allowed because some precondition failed.
          </p>
        </doc>
      </choice>

      <choice name="resource-deleted" value="amqp:resource-deleted">
        <doc>
          <p>A server entity the client is working with has been deleted.</p>
        </doc>
      </choice>

      <choice name="illegal-state" value="amqp:illegal-state">
        <doc>
          <p>
            The peer sent a frame that is not permitted in the current state of the Session.
          </p>
        </doc>
      </choice>

      <choice name="frame-size-too-small" value="amqp:frame-size-too-small">
        <doc>
          <p>
            The peer cannot send a frame because the smallest encoding of the performative with the
            currently valid values would be too large to fit within a frame of the agreed maximum
            frame size. When transferring a message the message data can be sent in multiple <xref
            name="transfer"/> frames thereby avoiding this error. Similarly when attaching a link
            with a large unsettled map the endpoint may make use of the incomplete-unsettled flag to
            avoid the need for overly large frames.
          </p>
        </doc>
      </choice>
    </type>

    <type class="restricted" name="connection-error" source="symbol" provides="error-condition"
          label="symbols used to indicate connection error conditions">

      <choice name="connection-forced" value="amqp:connection:forced">
        <doc>
          <p>
            An operator intervened to close the Connection for some reason. The client may retry at
            some later date.
          </p>
        </doc>
      </choice>

      <choice name="framing-error" value="amqp:connection:framing-error">
        <doc>
          <p>A valid frame header cannot be formed from the incoming byte stream.</p>
        </doc>
      </choice>

      <choice name="redirect" value="amqp:connection:redirect">
        <doc>
          <p>
            The container is no longer available on the current connection. The peer should
            attempt reconnection to the container using the details provided in the info map.
          </p>
          <dl>
            <dt>hostname</dt>
            <dd>
              <p>
                 the hostname of the container. This is the value that should be supplied in the
                 <i>hostname</i> field of the <xref name="open"/> frame, and suring the SASL and
                 TLS negotiation (if used).
              </p>
            </dd>
            <dt>network-host</dt>
            <dd>
              <p>
                the DNS hostname or IP address of the machine hosting the container.
              </p>
            </dd>
            <dt>port</dt>
            <dd>
              <p>
                the port number on the machine hosting the container.
              </p>
            </dd>
          </dl>
        </doc>
      </choice>

    </type>

    <type class="restricted" name="session-error" source="symbol" provides="error-condition"
          label="symbols used to indicate session error conditions">

      <choice name="window-violation" value="amqp:session:window-violation">
        <doc>
          <p>
            The peer violated incoming window for the session.
          </p>
        </doc>
      </choice>

      <choice name="errant-link" value="amqp:session:errant-link">
        <doc>
          <p>
            Input was received for a link that was detached with an error.
          </p>
        </doc>
      </choice>

      <choice name="handle-in-use" value="amqp:session:handle-in-use">
        <doc>
          <p>
            An attach was received using a handle that is already in use for an attached Link.
          </p>
        </doc>
      </choice>

      <choice name="unattached-handle" value="amqp:session:unattached-handle">
        <doc>
          <p>
            A frame (other than attach) was received referencing a handle which is not currently
            in use of an attached Link.
          </p>
        </doc>
      </choice>
    </type>

    <type class="restricted" name="link-error" source="symbol" provides="error-condition"
          label="symbols used to indicate link error conditions">

      <choice name="detach-forced" value="amqp:link:detach-forced">
        <doc>
          <p>
            An operator intervened to detach for some reason.
          </p>
        </doc>
      </choice>

      <choice name="transfer-limit-exceeded" value="amqp:link:transfer-limit-exceeded">
        <doc>
          <p>The peer sent more Message transfers than currently allowed on the link.</p>
        </doc>
      </choice>

      <choice name="message-size-exceeded" value="amqp:link:message-size-exceeded">
        <doc>
          <p>The peer sent a larger message than is supported on the link.</p>
        </doc>
      </choice>

      <choice name="redirect" value="amqp:link:redirect">
        <doc>
          <p>The address provided cannot be resolved to a terminus at the current container.
             The info map may contain the following information to allow the client to locate
             the attach to the terminus.
          </p>
          <dl>
            <dt>hostname</dt>
            <dd>
              <p>
                 the hostname of the container hosting the terminus. This is the value that should
                 be supplied in the <i>hostname</i> field of the <xref name="open"/> frame, and
                 during SASL and TLS negotiation (if used).
              </p>
            </dd>
            <dt>network-host</dt>
            <dd>
              <p>
                the DNS hostname or IP address of the machine hosting the container.
              </p>
            </dd>
            <dt>port</dt>
            <dd>
              <p>
                the port number on the machine hosting the container.
              </p>
            </dd>
            <dt>address</dt>
            <dd>
              <p>
                the address of the terminus at the container.
              </p>
            </dd>
          </dl>
        </doc>
      </choice>

      <choice name="stolen" value="amqp:link:stolen">
        <doc>
          <p>
            The link has been attached elsewhere, causing the existing attachment to be forcibly
            closed.
          </p>
        </doc>
      </choice>

    </type>

    <definition name="PORT" value="5672" label="the IANA assigned port number for AMQP">
      <doc>
        <p>
          The standard AMQP port number that has been assigned by IANA for TCP, UDP, and SCTP.
        </p>
      </doc>

      <doc>
        <p>
          There are currently no UDP or SCTP mappings defined for AMQP. The port number is reserved
          for future transport mappings to these protocols.
        </p>
      </doc>
    </definition>

    <definition name="SECURE-PORT" value="5671" label="the IANA assigned port number
        for secure AMQP (amqps)">
      <doc>
        <p>
          The standard AMQP port number that has been assigned by IANA for secure TCP using TLS.
        </p>
      </doc>

      <doc>
        <p>
          Implementations listening on this port should NOT expect a protocol handshake before TLS
          is negotiated.
        </p>
      </doc>
    </definition>

    <definition name="MAJOR" value="1" label="major protocol version" />
    <definition name="MINOR" value="0" label="minor protocol version" />
    <definition name="REVISION" value="0" label="protocol revision" />

    <definition name="MIN-MAX-FRAME-SIZE" value="512"
                label="the lower bound for the agreed maximum frame size (in bytes)">
      <doc>
        <p>
          During the initial Connection negotiation, the two peers must agree upon a maximum frame
          size. This constant defines the minimum value to which the maximum frame size can be set.
          By defining this value, the peers can guarantee that they can send frames of up to this
          size until they have agreed a definitive maximum frame size for that
          Connection.
        </p>
      </doc>
    </definition>
  </section>

</amqp>
