mirror of
https://github.com/moparisthebest/xeps
synced 2024-10-31 15:35:07 -04:00
427 lines
22 KiB
XML
427 lines
22 KiB
XML
|
<?xml version='1.0' encoding='UTF-8'?>
|
||
|
<!DOCTYPE xep SYSTEM 'xep.dtd' [
|
||
|
<!ENTITY % ents SYSTEM 'xep.ent'>
|
||
|
%ents;
|
||
|
]>
|
||
|
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
|
||
|
<!--
|
||
|
© XMPP Standards Foundation, 2015
|
||
|
Author: Peter Waher
|
||
|
-->
|
||
|
<xep>
|
||
|
<header>
|
||
|
<title>Quality of Service</title>
|
||
|
<abstract>This specification describes a generic method whereby messages can be sent between clients using a predefined Quality of Service level.</abstract>
|
||
|
&LEGALNOTICE;
|
||
|
<number>xxxx</number>
|
||
|
<status>ProtoXEP</status>
|
||
|
<type>Standards Track</type>
|
||
|
<sig>Standards</sig>
|
||
|
<approver>Council</approver>
|
||
|
<dependencies>
|
||
|
<spec>XMPP Core</spec>
|
||
|
<spec>XEP-0030</spec>
|
||
|
<spec>XEP-0337</spec>
|
||
|
</dependencies>
|
||
|
<supersedes/>
|
||
|
<supersededby/>
|
||
|
<shortname>qos</shortname>
|
||
|
&peterwaher;
|
||
|
<revision>
|
||
|
<version>0.0.1</version>
|
||
|
<date>2015-11-12</date>
|
||
|
<initials>pw</initials>
|
||
|
<remark>
|
||
|
<p>First draft.</p>
|
||
|
</remark>
|
||
|
</revision>
|
||
|
</header>
|
||
|
<section1 topic='Introduction' anchor='intro'>
|
||
|
<p>
|
||
|
Sometimes it is important for the sender of a message to control the Quality of Service level (or QoS level) of the message.
|
||
|
In other protocols, such as queueing, such QoS levels are built into the protocol itself. XMPP lacks an intrinsic QoS level management feature,
|
||
|
which has left application developers to define proprietary solutions when such have been required. This document however, provides a generic
|
||
|
solution and can be combined with any type of message structure defined either proprietarily or in another XEP.
|
||
|
The handling of the Quality of Service level is done prior to parsing the contents of the message. It defines three generic
|
||
|
Quality of Service levels that can be used regardless of what type of message is being sent:
|
||
|
</p>
|
||
|
<dl>
|
||
|
<di>
|
||
|
<dt>Unacknowledged service - At most once</dt>
|
||
|
<dd>
|
||
|
<p>
|
||
|
The message is sent at most once to its destination. The delivery of the message is not guaranteed. This QoS level
|
||
|
should only be used of the loss of messages is not critical to the application.
|
||
|
</p>
|
||
|
<p>
|
||
|
Example: A sensor sending a stream of current values. If a value is lost might not matter much since the next message
|
||
|
provides a new current value, overriding any lost value.
|
||
|
</p>
|
||
|
</dd>
|
||
|
</di>
|
||
|
<di>
|
||
|
<dt>Acknowledged service - At least once</dt>
|
||
|
<dd>
|
||
|
<p>
|
||
|
The message is sent at least once to its destination. Sending of the message is repeated until message has been acknowledged.
|
||
|
It is not guaranteed that the message is delivered only once. Asynchronous conditions may arise where the message is delivered more
|
||
|
than once. If an acknowledgement is not received, at least the sender may become aware that the message was not delivered
|
||
|
properly. The At least once QoS level requires twice as many messages to be transported in the network as compared to
|
||
|
the At most once QoS level.
|
||
|
</p>
|
||
|
<p>
|
||
|
Example: Any idempotent control action such as setting the light to a certain level. It is important that the control action
|
||
|
is received, but not how many of them are received. Any identical control action that follows makes no difference in output or
|
||
|
performance.
|
||
|
</p>
|
||
|
</dd>
|
||
|
</di>
|
||
|
<di>
|
||
|
<dt>Assured service - Exactly once</dt>
|
||
|
<dd>
|
||
|
<p>
|
||
|
The message is sent and delivered exactly once to its destination. The delivery of the message is divided into two acknowledged
|
||
|
message transfers. First, the message is transferred to the other side, but not parsed. The second operation, the message is requested
|
||
|
to be parsed and delivered. Both these steps are idempotent, making sure that the contents of the message is delivered exactly once.
|
||
|
If not possible to deliver the message, the sender will be made aware of this fact. The Exactly once QoS level requires
|
||
|
four times as many messages to be transported in the network as compared to the At most once QoS level and twice as many
|
||
|
messages to be transported as compared to the At least once QoS level.
|
||
|
</p>
|
||
|
<p>
|
||
|
Example: Any control action or counting operation that is not idempotent, such as sending a control action when a button is
|
||
|
pressed, whenever an event has occurred or a transaction. If counting events, transactions, or accumulating consumption, it is
|
||
|
vital that messages are not processed twice, since it will change the end result.
|
||
|
</p>
|
||
|
</dd>
|
||
|
</di>
|
||
|
</dl>
|
||
|
</section1>
|
||
|
<section1 topic='Use Cases' anchor='usecases'>
|
||
|
<section2 topic='Unacknowledged service - At most once' anchor='unack'>
|
||
|
<p>
|
||
|
To send a message that is received at most once to its destination, a normal message stanza is used, as defined by the XMPP
|
||
|
protocol itself. The delivery of the message is not guaranteed. This QoS level should only be used of the loss of messages is not critical
|
||
|
to the application.
|
||
|
</p>
|
||
|
<p>
|
||
|
Example: A sensor sending a stream of current values. If a value is lost might not matter much since the next message
|
||
|
provides a new current value, overriding any lost value.
|
||
|
</p>
|
||
|
<example caption='Sensor sending a momentary value'>
|
||
|
<![CDATA[
|
||
|
<message
|
||
|
from='temperaturesensor@example.org/34892374'
|
||
|
to='user@example.org/938089023'>
|
||
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
|
||
|
<node nodeId='Temp01'>
|
||
|
<timestamp value='2015-11-11T22:01:30'>
|
||
|
<numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
|
||
|
</timestamp>
|
||
|
</node>
|
||
|
</fields>
|
||
|
</message>]]>
|
||
|
</example>
|
||
|
</section2>
|
||
|
<section2 topic='Acknowledged service - At least once' anchor='ack'>
|
||
|
<p>
|
||
|
To send a message that is received at least once to its destination, an iq stanza of type set is sent containing an
|
||
|
acknowledged element from the "urn:xmpp:qos" namespace. The acknowledged element in turn contains the message to be delivered.
|
||
|
The iq stanza must have an id attribute that is used to identify if the stanza has been received or not. When an acknowledged
|
||
|
message is received, an empty response is returned to acknowledge the receipt. Parsing the message is done after sending the response.
|
||
|
If no response is received by the sending side within a given time frame, an number of retries should be made, using an interval or drop-off
|
||
|
algorithm. These time frames and number of attempts are implementation specific.
|
||
|
</p>
|
||
|
<p>
|
||
|
It is not guaranteed that the message is delivered only once. Asynchronous conditions may arise where the message is delivered more
|
||
|
than once. If an acknowledgement is not received, at least the sender may become aware that the message was not delivered.
|
||
|
The At least once QoS level requires twice as many messages to be transported in the network as compared to
|
||
|
the At most once QoS level.
|
||
|
</p>
|
||
|
<p>
|
||
|
Example: Any idempotent control action such as setting the light to a certain level. It is important that the control action
|
||
|
is received, but not how many of them are received. Any identical control action that follows makes no difference in output or
|
||
|
performance.
|
||
|
</p>
|
||
|
<example caption='Setting light level'>
|
||
|
<![CDATA[
|
||
|
<iq id='123' type='set'
|
||
|
from='controller@example.org/34892374'
|
||
|
to='lightswitch@example.org/938089023'>
|
||
|
<qos:acknowledged xmlns:qos='urn:xmpp:qos'>
|
||
|
<message>
|
||
|
<set xmlns='urn:xmpp:iot:control'>
|
||
|
<int name='Light' value='80'/>
|
||
|
</set>
|
||
|
</message>
|
||
|
</qos:acknowledged>
|
||
|
</iq>
|
||
|
|
||
|
<iq id='123' type='result'
|
||
|
from='lightswitch@example.org/938089023'
|
||
|
to='controller@example.org/34892374'/>
|
||
|
]]>
|
||
|
</example>
|
||
|
<p>
|
||
|
Note: The to and from attributes in the embedded message stanza are left empty.
|
||
|
</p>
|
||
|
</section2>
|
||
|
<section2 topic='Assured service - Exactly once' anchor='assured'>
|
||
|
<p>
|
||
|
To send a message that is received exactly once to its destination, an iq stanza of type set is sent containing an
|
||
|
assured element from the "urn:xmpp:qos" namespace. The assured element in turn contains the message to be delivered.
|
||
|
The iq stanza must have an id attribute that is used to identify if the stanza has been received or not, just as in the
|
||
|
acknowledged case. But to keep track of the message begin sent, a msgId attribute has to be provided as well. When an assured
|
||
|
message is received, a received response is returned to acknowledge the receipt. This received response echoes the msgId
|
||
|
attribute as well. But the message is not parsed and delivered at this point, only temporarily stored on the receiving end.
|
||
|
If multiple messages are received using the same msgId from the same sender, they are simply ignored, as one is already held in
|
||
|
memory. Still, the received response is returned as normal.
|
||
|
</p>
|
||
|
<p>
|
||
|
When the sender receives the received response, it sends a new iq set stanza, this time with a deliver payload,
|
||
|
to tell the receiving end to parse and deliver the message, if in memory, and remove it from memory. The receiver acknowledges the message
|
||
|
by returning an empty iq result stanza. If receiving multiple requests using the same msgId, it will acknowledge each one. But
|
||
|
only one message will be parsed and delivered, as it will have been removed from the temporary storage on the receiving end. For both the
|
||
|
assured and deliver messages, a retry mechanism similar to the one used for acknowledged service is to be used.
|
||
|
</p>
|
||
|
<p>
|
||
|
The Exactly once QoS level requires twice as many messages to be transported in the network as compared to the At least once
|
||
|
QoS level, and four times the number of messages as compared to the At most once QoS level.
|
||
|
</p>
|
||
|
<p>
|
||
|
Example: Any control action or counting operation that is not idempotent, such as sending a control action when a button is
|
||
|
pressed, or whenever an event has occurred. If counting events, or accumulating consumption, it is vital that messages are not
|
||
|
processed twice, since it will change the end result.
|
||
|
</p>
|
||
|
<example caption='Counting cars or individuals in a closed space'>
|
||
|
<![CDATA[
|
||
|
<iq id='123' type='set'
|
||
|
from='entrance@example.org/34892374'
|
||
|
to='counter@example.org/938089023'>
|
||
|
<qos:assured xmlns:qos='urn:xmpp:qos' msgId='984232334'>
|
||
|
<message>
|
||
|
<log xmlns='urn:xmpp:eventlog' timestamp='2015-11-12T09:07:12Z' id='Entered'>
|
||
|
<message>Entered.</message>
|
||
|
</buy>
|
||
|
</message>
|
||
|
</qos:assured>
|
||
|
</iq>
|
||
|
|
||
|
<iq id='123' type='result'
|
||
|
from='counter@example.org/938089023'>
|
||
|
to='entrance@example.org/34892374'>
|
||
|
<received msgId='984232334'/>
|
||
|
</iq>
|
||
|
|
||
|
<iq id='124' type='set'
|
||
|
from='entrance@example.org/34892374'
|
||
|
to='counter@example.org/938089023'>
|
||
|
<qos:deliver xmlns:qos='urn:xmpp:qos' msgId='984232334'/>
|
||
|
</iq>
|
||
|
|
||
|
<iq id='124' type='result'
|
||
|
from='counter@example.org/938089023'>
|
||
|
to='entrance@example.org/34892374'/>
|
||
|
</iq>
|
||
|
|
||
|
...
|
||
|
|
||
|
<iq id='456' type='set'
|
||
|
from='exit@example.org/34892374'
|
||
|
to='counter@example.org/938089023'>
|
||
|
<qos:assured xmlns:qos='urn:xmpp:qos' msgId='4645623466'>
|
||
|
<message>
|
||
|
<log xmlns='urn:xmpp:eventlog' timestamp='2015-11-12T11:23:54Z' id='Left'>
|
||
|
<message>Left.</message>
|
||
|
</buy>
|
||
|
</message>
|
||
|
</qos:assured>
|
||
|
</iq>
|
||
|
|
||
|
<iq id='456' type='result'
|
||
|
from='counter@example.org/938089023'>
|
||
|
to='exit@example.org/34892374'>
|
||
|
<received msgId='4645623466'/>
|
||
|
</iq>
|
||
|
|
||
|
<iq id='457' type='set'
|
||
|
from='exit@example.org/34892374'
|
||
|
to='counter@example.org/938089023'>
|
||
|
<qos:deliver xmlns:qos='urn:xmpp:qos' msgId='4645623466'/>
|
||
|
</iq>
|
||
|
|
||
|
<iq id='457' type='result'
|
||
|
from='counter@example.org/938089023'>
|
||
|
to='exit@example.org/34892374'/>
|
||
|
</iq>]]>
|
||
|
</example>
|
||
|
<p>
|
||
|
Note: The to and from attributes in the embedded message stanza are left empty.
|
||
|
</p>
|
||
|
</section2>
|
||
|
</section1>
|
||
|
<section1 topic='Determining Support' anchor='support'>
|
||
|
<p>
|
||
|
If an entity supports signing forms as specified herein, it MUST advertise that fact by returning a feature of
|
||
|
"urn:xmpp:qos" in response to &xep0030; information requests.
|
||
|
</p>
|
||
|
<example caption="Service discovery information request">
|
||
|
<![CDATA[
|
||
|
<iq type='get'
|
||
|
from='example.org'
|
||
|
to='device@example.org'
|
||
|
id='disco1'>
|
||
|
<query xmlns='http://jabber.org/protocol/disco#info'/>
|
||
|
</iq>]]>
|
||
|
</example>
|
||
|
<example caption="Service discovery information response">
|
||
|
<![CDATA[
|
||
|
<iq type='result'
|
||
|
from='device@example.org'
|
||
|
to='example.org'
|
||
|
id='disco1'>
|
||
|
<query xmlns='http://jabber.org/protocol/disco#info'>
|
||
|
...
|
||
|
<feature var='urn:xmpp:qos'/>
|
||
|
...
|
||
|
</query>
|
||
|
</iq>]]>
|
||
|
</example>
|
||
|
<p>
|
||
|
In order for an application to determine whether an entity supports this protocol, where possible it SHOULD use the dynamic,
|
||
|
presence-based profile of service discovery defined in &xep0115;. However, if an application has not received entity capabilities
|
||
|
information from an entity, it SHOULD use explicit service discovery instead.
|
||
|
</p>
|
||
|
</section1>
|
||
|
<section1 topic='Implementation Notes' anchor='impl'>
|
||
|
<section2 topic='Offline messages' anchor='offline'>
|
||
|
<p>
|
||
|
When sending messages using unacknowledged service, i.e. using the normal message stanza, it can be subject to offline message
|
||
|
storage if the recipient if offline. This might result in delivery of the message at a later time.
|
||
|
</p>
|
||
|
</section2>
|
||
|
<section2 topic='Resource part' anchor='resource'>
|
||
|
<p>
|
||
|
Message routing using unacknowledged service might be handled somewhat differently as compared to acknowledged and assured service,
|
||
|
since the first uses the message stanza and the latter two the iq stanza, which require a fill JID in order to reach its destination.
|
||
|
For consistency, full JIDs should be used also for unacknowledged messaging service, if possible.
|
||
|
</p>
|
||
|
</section2>
|
||
|
<section2 topic='Generic implementation' anchor='generic'>
|
||
|
<p>
|
||
|
If implementing support for this XEP, make sure implementation is generic and put on a lower level than other XEP-specific processing
|
||
|
of incoming stanzas. Messages received using this server should be fed into the normal message processing and handling after the QoS level
|
||
|
has been ascertained. This makes it possible to use QoS levels for any type of message being sent and received.
|
||
|
</p>
|
||
|
</section2>
|
||
|
<section2 topic='Persistence' anchor='persistence'>
|
||
|
<p>
|
||
|
One decision each implementation of assured QoS has to make, is where to persist incoming messages between reception of message and
|
||
|
the delivery to underlying message processing logic. Should they be persisted in internal memory, persistent Flash/EEProm, as local files
|
||
|
or in a database? Such implementation specific concerns are left to the implementor, as this XEP only concerns itself with the communication
|
||
|
layer between parties. But the choice of solution might affect to what level a message is ascertained to be delivered: Will delivery be
|
||
|
guaranteed, even beyond a system reset at the receiving end? Or a system reset at the sending side? If delivery of the message has to be
|
||
|
ascertained even if a system reset at the sending side is allowed, persistance of the request must also be made on the sending side.
|
||
|
(To some extent, this latter concern even affects acknowledged service.)
|
||
|
</p>
|
||
|
</section2>
|
||
|
<section2 topic='Message IDs' anchor='msdId'>
|
||
|
<p>
|
||
|
Outstanding message IDs used in assured delivery, must be unique for the sender (counting the Full JID as the sender). If running
|
||
|
short on Message IDs, such can be reclaimed after the receipt of a successful delivery of a previous message. Message IDs can be
|
||
|
sequence numbers, or hash values of the contents of the message.
|
||
|
</p>
|
||
|
</section2>
|
||
|
</section1>
|
||
|
<section1 topic='Security Considerations' anchor='security'>
|
||
|
<section2 topic='To and from attributes' anchor='tofrom'>
|
||
|
<p>
|
||
|
The to and from attributes of embedded message elements should be ignored and left out by the sender, except in the case of
|
||
|
unacknowledged service, where the message element is the message stanza itself. In the case of acknowledged and assured quality of
|
||
|
service levels, the message element MUST have its to and from attributes overwritten by the corresponding attributes of the iq
|
||
|
stanza being used. This, to avoid the injection of messages with unauthenticated and unauthorized identities.
|
||
|
</p>
|
||
|
</section2>
|
||
|
<section2 topic='Memory attacks' anchor='memory'>
|
||
|
<p>
|
||
|
As incoming message using the assured quality of service level is temporarily stored on the receiving end, the receiver might become
|
||
|
vulnerable to memory attacks if not implementing some basic counter measures:
|
||
|
</p>
|
||
|
<ol>
|
||
|
<li>
|
||
|
<p>
|
||
|
Do not accept messages using assured service from untrusted sources, for instance from MUC rooms or senders not in the
|
||
|
roster. If deemed untrusted, an iq error of type <strong>not-allowed</strong> should be returned instead of the
|
||
|
<strong>received</strong> element expected in normal flow.
|
||
|
</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>
|
||
|
Set a limit on the number and size of assured messages that can be simultaneously received from a single source. If a source
|
||
|
sends more than this, the <strong>resource-constraint</strong> error should be returned instead of accepting the message.
|
||
|
</p>
|
||
|
</li>
|
||
|
<li>
|
||
|
<p>
|
||
|
Set a total limit on the number and size of assured messages that can be simultaneously received from all sources. If anybody
|
||
|
sends a message that will exceed this amount, the <strong>resource-constraint</strong> error should be returned instead of
|
||
|
accepting the message.
|
||
|
</p>
|
||
|
</li>
|
||
|
</ol>
|
||
|
<p>
|
||
|
Whenever invalid use of the assured messaging service is detected, wether it be from untrusted sources or spam, an event should be
|
||
|
logged using &xep0337; so that the source of the error can be found and appropriate counter measures taken.
|
||
|
</p>
|
||
|
</section2>
|
||
|
</section1>
|
||
|
<section1 topic='IANA Considerations' anchor='iana'>
|
||
|
<p>This document requires no interaction with &IANA;.</p>
|
||
|
</section1>
|
||
|
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
|
||
|
<p>
|
||
|
The <link url="#schema">protocol schema</link> needs to be added to the list of <link url="http://xmpp.org/resources/schemas/">XMPP protocol schemas</link>.
|
||
|
</p>
|
||
|
</section1>
|
||
|
<section1 topic='XML Schema' anchor='schema'>
|
||
|
<code>
|
||
|
<![CDATA[
|
||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||
|
<xs:schema
|
||
|
xmlns:xs='http://www.w3.org/2001/XMLSchema'
|
||
|
targetNamespace='urn:xmpp:qos'
|
||
|
xmlns='urn:xmpp:qos'
|
||
|
xmlns:jbc='jabber:client'
|
||
|
elementFormDefault='qualified'>
|
||
|
|
||
|
<xs:import namespace='jabber:client'/>
|
||
|
|
||
|
<xs:element name='acknowledged' type='EmbeddedMessage'/>
|
||
|
<xs:element name='assured' type='Assured'/>
|
||
|
<xs:element name='received' type='WithMessageId'/>
|
||
|
<xs:element name='deliver' type='WithMessageId'/>
|
||
|
|
||
|
<xs:complexType name='EmbeddedMessage'>
|
||
|
<xs:sequence minOccurs='1' maxOccurs='1'>
|
||
|
<xs:element ref='jbc:message'/>
|
||
|
</xs:sequence>
|
||
|
</xs:complexType>
|
||
|
|
||
|
<xs:complexType name='Assured'>
|
||
|
<xs:complexContent>
|
||
|
<xs:extension base='EmbeddedMessage'>
|
||
|
<xs:attribute ref='msgId' use='required'/>
|
||
|
</xs:extension>
|
||
|
</xs:complexContent>
|
||
|
</xs:complexType>
|
||
|
|
||
|
<xs:attribute name='msgId' type='xs:string'/>
|
||
|
|
||
|
<xs:complexType name='WithMessageId'>
|
||
|
<xs:attribute ref='msgId' use='required'/>
|
||
|
</xs:complexType>
|
||
|
|
||
|
</xs:schema>
|
||
|
]]>
|
||
|
</code>
|
||
|
</section1>
|
||
|
</xep>
|