mirror of
https://github.com/moparisthebest/xeps
synced 2024-11-21 08:45:04 -05:00
ProtoXEP - Quality of Service (o.b.o Peter Waher)
This commit is contained in:
parent
12139d5ca7
commit
2476089c80
427
inbox/qos.xml
Normal file
427
inbox/qos.xml
Normal file
@ -0,0 +1,427 @@
|
||||
<?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>
|
Loading…
Reference in New Issue
Block a user