Jabber Next-Gen
Described here is the next generation protocol that builds upon the powerful
heritage of the original Jabber routing and streaming protocols while also
eliminating their shortcomings.
The basic concept is built around streams and identities, every stream connection
is assigned a unique temporary identity. Each stream also wraps all
routeable xml and does no parsing of it's contents. There is only one
stream namespace, and no namespaces are used or parsed within the routing
layer.
Stream Namespace
First, we send:
<jabber xmlns="jabber:root">
Response:
<jabber xmlns="jabber:root" jid="guid@ccm1.foo.net">
The stream then consists of a few basic elements, the most important being
the <route/>. Each route can contain any child elements in any
namespace. The sender and recipient of the route must be a valid Jabber
ID. Every stream has at least one such id associated with it as given
in the root element, and only the associated ids may be used as a sender.
Additional sender ids are bound to the stream as requested and authorized.
Streams can also perform chunking, or breaking apart large elements
so that additional elements can be delivered simultaneously.
The jabber root namespace contains the following elements:
- <route to="jid" from="jid">...</route>
- The route element contains one or more additional route elements,
or elements in another namespace. Each element is treated as if it
were in it's own identical parent route element (multiple children for convenience
only, no implicit meaning or special treatment).
- to: (required) The recipient jid.
- from: (required) The sending jid, must be the given stream
jid or a bound jid.
- id: (optional) Always preserved across any routing and in
any error responses. Set by sender.
- expire: (optional) The number of seconds that the route is
valid for. Defaults to 15 (?). A value of 0 implies the packet
is to never be queued or delayed for any reason (dns lookup, component wait
queue, etc), higher values allow longer wait times when being routed. Must
be decrimented if delayed but not beyond expiration.
- <error to="jid" from="jid" code="404">...</error>
- Identical to route, contains the children elements from a failed
route. It cannot be contained in anything else (can't be bounced).
Errors are only generated due to problems with the routing or processing
of a child element in a route.
- code: (required) Error code identifying the type of error.
- desc: (optional) Additional data relevant to the error code,
extended description, etc.
- <bind type="..." jid="...."/>
- Used to bind new addresses to the stream. Any child elements
are in another namespace relevant to authentication/authorization (plain-text
passwords, digest, 0k, dialback, etc).
- type: (required) get, set, fail, result
- jid: (required) The new jid to be bound to this stream. After
being bound, the jid can be used in a from attribute on a route.
- <chunk>...</chunk>
- No child elements, only contains <![CDATA[...]]>. Upon
receiving the cdata, it is reassembled and then parsed, and the parsed xml
is a single element in the jabber:root namespace (a route or error element).
- type:(optional) "set" to enable or set the requested chunking
byte mark, "new" to indicate a new sequence of chunks, and "last" to mark
the last chunk in a sequence.
- bytes: (optional) Used in a set to request the other end of
the stream to chunk any elements over that number of bytes before sending.
Used in a new to indicate the total number of bytes of the packet being chunked.
- id:(optional) Each stream of chunks must have a unique identifier
associated with it.
State Preservation
When entities are interacting through Jabber they will often create state
that is dependent upon the existence of the stream. In the original
protocol this very important feature was fundamentally built in and not extensible,
that when a (client only) socket was broken, the session manager would internally
be notified and be responsible for notifying anyone subscribed to their presence.
State can easily be preserved in this new protocol in a generic and extensible
way. When the sender needs to send something that may require the recipient
to have knowledge of a change in the connection state (such as sending status/availability
information), it first sends the route and children elements that would be
delivered upon a disconnect, in a parent route to the given primary stream
jid. When the other end of the stream receives a route to it's own
jid, it stores the children routes in a queue using the first route's id
attribute as a unique key. The queue is then processed upon disconnect
and all stored routes are delivered. If the state changes before disconnect,
or the recipient no longer needs to be notified, another route with the same
id is sent with no children, which would empty anything in the queue based
on that id key.
Discussion
Fundamental problems fixed:
- Full and clean namespace usage, no namespacing is intermixed with
the routing layer and namespaces only reside in the child elements being
routed.
- IM is not integrated with the routing, all stream and routing semantics
are independent of any application.
- All routing is fully independent from the xml data being routed.
- Multi-point routing is supported (a route can be forwarded inside
another route)
- Unified identity access, one single stream and binding method can
be used for access to any identity (client, user, server-server, and services).
All session creation, presence management, and other services and application
logic are independent from this fundamental routing layer.
Examples
A message (after we've bound to a jid):
<route to="foo@jabber.org" from="jer@jabber.org/bar">
<message xmlns="jabber:message"
type="chat"><body>heya</body></message>
</route>
Multiples:
<route to="bar.net" from="jer@jabber.org/bar" id="q0">
<foo xmlns="http://foo.org/foo.dtd"><do>...</do></foo>
<bar xmlns="http://bar.net/bar.dtd"/>
</route>
Responses:
<route to="jer@jabber.org/bar" from="bar.net" id="q0">
<foo xmlns="http://foo.org/foo.dtd"><done/></foo>
</route>
<error to="jer@jabber.org/bar" from="bar.net" code="501"
id="q0">
<bar xmlns="http://bar.net/bar.dtd"/>
</error>
A forwarded message:
<route from="jer@home.jeremie.com" to="jer@jabber.org/bar">
<route from="foo@bar.net" to="jer@jabber.org">
<message xmlns="jabber:message"
type="chat"><body>heya</body></message>
</route>
</route>