<?xml version="1.0"?>
<!--
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
-
-->

<!--
- NOTE: if you make changes to this XML you must update CLUSTER_VERSION
- in src/qpid/cluster/Cluster.cpp
-->

<amqp major="0" minor="10" port="5672">

  <!-- Controls sent between cluster nodes. -->

  <class name = "cluster" code = "0x80" label="Qpid clustering extensions.">
    <doc>Qpid extension class to allow clustered brokers to communicate.</doc>

    <!-- New joiner requests an update to url. -->
    <control name="update-request" code="0x1">
      <field name="url" type="str16"/>
    </control>

    <!-- Sender offers an update to a new joiner. -->
    <control name = "update-offer" code="0x2">
      <field name="updatee" type="uint64"/>
    </control>

    <!-- Sender retracts an offer to a new joiner. -->
    <control name = "retract-offer" code="0x3">
      <field name="updatee" type="uint64"/>
    </control>

    <!-- Possible states for persistent store -->
    <domain name="store-state" type="uint8">
      <enum>
	<choice name="no-store" value="0"/>
	<choice name="empty-store" value="1"/>
	<choice name="clean-store" value="2"/>
	<choice name="dirty-store" value="3"/>
      </enum>
    </domain>

    <!-- Status exchanged when new members join the cluster. -->
    <control name="initial-status" code="0x5">
      <field name="version" type="uint32"/>
      <field name="active" type="bit"/>
      <field name="cluster-id" type="uuid"/>>
      <field name="store-state" type="store-state"/>
      <field name="shutdown-id" type="uuid"/>
      <field name="first-config" type="str16"/>
      <field name="urls" type="array"/>	       <!-- Array of str16 -->
    </control>

    <!-- New member or updater is ready as an active member. -->
    <control name="ready" code="0x10">
      <field name="url" type="str16"/>
    </control>

    <control name="config-change" code="0x11" label="Raw cluster membership.">
      <field name="members" type="vbin16"/> <!-- packed member-id array -->
      <field name="joined" type="vbin16"/> <!-- packed member-id array -->
      <field name="left" type="vbin16"/> <!-- packed member-id array -->
    </control>

    <domain name="error-type" type="uint8" label="Types of error">
      <enum>
	<choice name="none" value="0"/>
	<choice name="session" value="1"/>
	<choice name="connection" value="2"/>
      </enum>
    </domain>

    <!-- Check for error consistency across the cluster -->
    <control name="error-check" code="0x14">
      <field name="type" type="error-type"/>
      <field name="frame-seq" type="sequence-no"/>
    </control>

    <!-- Synchronize timer tasks across the cluster -->
    <control name="timer-wakeup" code="0x15">
      <field name="name" type="str16"/>
    </control>

    <control name="timer-drop" code="0x16">
      <field name="name" type="str16"/>
    </control>

    <!-- Shut down the entire cluster -->
    <control name="shutdown" code="0x20">
      <field name="shutdown-id" type="uuid"/>
    </control>

    <!-- Deliver a message to a queue -->
    <control name="deliver-to-queue" code="0x21">
      <field name="queue" type="str16"/>
      <field name="message" type="vbin32"/>
    </control>

    <!-- Update the cluster time -->
    <control name="clock" code="0x22">
      <field name="time" type="uint64"/>
    </control>

  </class>

  <!-- Controls associated with a specific connection. -->

  <class name="cluster-connection" code="0x81" label="Qpid clustering extensions.">

    <!-- Announce a new connection -->
    <control name="announce" code="0x1">
      <field name="management-id" type="str16"/>
      <!-- Security Strength Factor (ssf): if the transport provides
      encryption (e.g. ssl), ssf is the bit length of the key.  Zero if no
      encryption provided. -->
      <field name="ssf" type="uint32"/>
      <!-- external auth id (e.g. ssl client certificate id) -->
      <field name="authid" type="str16"/>
      <!-- exclude certain sasl mechs, used with ssl and sasl-external -->
      <field name="nodict" type="bit"/>
      <!-- User name as negotiated by SASL -->
      <field name="username" type="str32"/>
      <!-- Frames forming the initial connection negotiation.  -->
      <field name="initial-frames" type="str32"/>
    </control>

    <!-- Marks the cluster-wide point when a connection is considered closed. -->
    <control name="deliver-close" code="0x2"/>

    <!-- Permission to generate output up to the limit. -->
    <control name="deliver-do-output" code="0x3">
      <field name="limit" type="uint32"/>
    </control>

    <!-- Abort a connection that is sending invalid data. -->
    <control name="abort" code="0x4"/>

    <!-- Update controls. Sent to a new broker in joining mode.
	 A connection is updated as followed:
	 - send the shadow's management ID in shadow-perpare on the update connection
	 - open the shadow as a normal connection.
	 - attach sessions, create consumers, set flow with normal AMQP cokmmands.
	 - send /reset additional session state with controls below.
	 - send shadow-ready to mark end of shadow update.
	 - send membership when entire update is complete.
    -->
    <!-- Send the user-id for an update connection. -->
    <control name="shadow-set-user" code="0x0E">
      <field name="user-id" type="str16"/>
    </control>

    <!-- Prepare to send a shadow connection with the given ID. -->
    <control name="shadow-prepare" code="0x0F">
      <field name="management-id" type="str16"/>
    </control>

    <!-- Consumer state that cannot be set by standard AMQP controls. -->
    <control name="consumer-state" code="0x10">
      <field name="name" type="str8"/>
      <field name="blocked" type="bit"/>
      <field name="notifyEnabled" type="bit"/>
      <field name="position" type="sequence-no"/>
      <field name="used-msg-credit" type="uint32"/>
      <field name="used-byte-credit" type="uint32"/>
    </control>

    <!-- Delivery-record for outgoing messages sent but not yet accepted. -->
    <control name="delivery-record" code ="0x11">
      <field name="queue" type="str8"/>
      <field name="position" type="sequence-no"/>
      <field name="tag" type="str8"/>
      <field name="id" type="sequence-no"/>
      <field name="acquired" type="bit"/> <!--If not set, message is on update queue. -->
      <field name="accepted" type="bit"/>
      <field name="cancelled" type="bit"/>
      <field name="completed" type="bit"/>
      <field name="ended" type="bit"/>
      <field name="windowing" type="bit"/>
      <field name="enqueued" type="bit"/>
      <field name="credit" type="uint32"/>
    </control>

    <!-- Tx transaction state. -->
    <control name="tx-start" code="0x12"/>
    <control name="tx-accept" code="0x13"> <field name="commands" type="sequence-set"/> </control>
    <control name="tx-dequeue" code="0x14"> <field name="queue" type="str8"/> </control>
    <control name="tx-enqueue" code="0x15"> <field name="queue" type="str8"/> </control>
    <control name="tx-publish" code="0x16">
      <field name="queues" type="array"/>  <!--Array of str8 -->
      <field name="delivered" type="bit"/>
    </control>
    <control name="tx-end" code="0x17"/>
    <control name="accumulated-ack" code="0x18"> <field name="commands" type="sequence-set"/> </control>

    <!-- Consumers in the connection's output task -->
    <control name="output-task" code="0x19">
      <field name="channel" type="uint16"/>
      <field name="name" type="str8"/>
    </control>

    <!-- Dtx transaction state. -->
    <control name="dtx-start" code="0x1A">
      <field name="xid" type="str16"/>
      <field name="ended" type="bit"/>
      <field name="suspended" type="bit"/>
      <field name="failed" type="bit"/>
      <field name="expired" type="bit"/>
    </control>
    <control name="dtx-end" code="0x1B"/>

    <control name="dtx-ack" code="0x1C"/>

    <control name="dtx-buffer-ref" code="0x1D">
      <field name="xid" type="str16"/>
      <field name="index" type="uint32"/>
      <field name="suspended" type="bit"/>
    </control>

    <control name="dtx-work-record" code="0x1E">
      <field name="xid" type="str16"/>
      <field name="prepared" type="bit"/>
      <field name="timeout" type="uint32"/>
    </control>

    <!-- Complete a session state update. -->
    <control name="session-state" code="0x1F">
      <!-- Target session deduced from channel number.  -->
      <field name="replay-start" type="sequence-no"/>	       <!-- Replay frames will start from this point.-->
      <field name="command-point" type="sequence-no"/>	       <!-- Id of next command sent -->
      <field name="sent-incomplete" type="sequence-set"/>      <!-- Commands sent and incomplete. -->

      <field name="expected" type="sequence-no"/>	       <!-- Next command expected. -->
      <field name="received" type="sequence-no"/>	       <!-- Received up to here (>= expected) -->
      <field name="unknown-completed" type="sequence-set"/>    <!-- Completed but not known to peer. -->
      <field name="received-incomplete" type="sequence-set"/>  <!-- Received and incomplete -->
      <field name="dtx-selected" type="bit"/>
    </control>

    <!-- Complete a shadow connection update. -->
    <control name="shadow-ready" code="0x20" label="End of shadow connection update.">
      <field name="member-id" type="uint64"/>
      <field name="connection-id" type="uint64"/>
      <field name="management-id" type="str16"/>
      <field name="user-name" type="str8"/>
      <field name="fragment" type="str32"/>
      <field name="send-max" type="uint32"/>
    </control>

    <!-- Complete a cluster state update. -->
    <control name="membership" code="0x21" label="Cluster membership details.">
      <field name="joiners" type="map"/> <!-- member-id -> URL -->
      <field name="members" type="map"/> <!-- member-id -> state -->
      <field name="frame-seq" type="sequence-no"/> <!-- frame sequence number -->
    </control>

    <!-- Updater cannot fulfill an update offer. -->
    <control name = "retract-offer" code="0x22"/>

    <!-- Set the position of a replicated queue. -->
    <control name="queue-position" code="0x30">
      <field name="queue" type="str8"/>
      <field name="position" type="sequence-no"/>
    </control>

    <!-- Replicate encoded exchanges/queues. -->
    <control name="exchange" code="0x31"><field name="encoded" type="str32"/></control>

    <!-- Add a listener to a queue -->
    <control name="add-queue-listener" code="0x34">
      <field name="queue" type="str8"/>
      <field name="consumer" type="uint32"/>
    </control>

    <!-- added by jrd.  propagate a management-setup-state widget -->
    <control name="management-setup-state" code="0x36">
      <field name="objectNum" type="uint64"/>
      <field name="bootSequence" type="uint16"/>
      <field name="broker-id" type="uuid"/>
      <field name="vendor" type="str32"/>
      <field name="product" type="str32"/>
      <field name="instance" type="str32"/>
    </control>

    <!-- Replicate encoded config objects - e.g. links and bridges. -->
    <control name="config" code="0x37"><field name="encoded" type="str32"/></control>

    <!-- Set the fairshare delivery related state of a replicated queue. -->
    <control name="queue-fairshare-state" code="0x38">
      <field name="queue" type="str8"/>
      <field name="position" type="uint8"/>
      <field name="count" type="uint8"/>
    </control>

    <!-- Replicate a QueueObserver for a given queue. -->
    <control name="queue-observer-state" code="0x39">
      <field name="queue" type="str8"/>
      <field name="observer-id" type="str8"/>
      <field name="state" type="map"/>    <!-- "name"=value -->
    </control>

    <!-- Update the cluster time -->
    <control name="clock" code="0x40">
      <field name="time" type="uint64"/>
    </control>

    <!-- Update a queue's dequeue rate -->
    <control name="queue-dequeue-since-purge-state" code="0x41">
      <field name="queue" type="str8"/>
      <field name="dequeueSincePurge" type="uint32"/>
    </control>


  </class>

</amqp>
