protocol — XML Stream implementation

This module contains the XMLStream class, which implements the XML stream protocol used by XMPP. It makes extensive use of the aioxmpp.xml module and the aioxmpp.xso subpackage to parse and serialize XSOs received and sent on the stream.

In addition, helper functions to work with XMLStream instances are provided; these are not included in the class itself because they provide additional functionality solely based on the public interface of the class. Separating them helps with testing.

class aioxmpp.protocol.XMLStream(to, features_future=None, sorted_attributes=False, base_logger=<Logger aioxmpp (WARNING)>, default_namespace='jabber:client', from_=None, loop=None)[source]

XML stream implementation. This is an streaming asyncio.Protocol which translates the received bytes into XSOs.

Parameters
  • to (JID) – Domain of the server the stream connects to.

  • features_future (asyncio.Future) – Use features_future() instead.

  • sorted_attributes (bool) – Sort attributes deterministically on output (debug option; not part of the public interface)

  • default_namespace (str) – Set the default namespace to advertise on the stream header.

  • from – The value of the from attribute of the stream header.

  • base_logger (logging.Logger) – Parent logger for this stream

Tpye fromfrom_

JID or None

to must identify the remote server to connect to. This is used as the to attribute on the stream header.

features_future may be a future. The XML stream will set the first StreamFeatures node it receives as the result of the future. The future will also receive any pre-stream-features exception.

sorted_attributes is a testing/debugging option to enable sorted output of the XML attributes emitted on the stream. See XMPPXMLGenerator for details. Do not use outside of unit testing code, as it has a negative performance impact.

base_logger may be a logging.Logger instance to use. The XML stream will create a child called XMLStream at that logger and use that child for logging purposes. This eases debugging and allows for connection-specific loggers.

Deprecated since version 0.12: Using features_future as positional or keyword argument is deprecated and will be removed in version 1.0. Use features_future() to obtain a future instead.

Receiving XSOs:

stanza_parser

A XSOParser instance which is wired to a XMPPXMLProcessor which processes the received bytes.

To receive XSOs over the XML stream, use stanza_parser and register class callbacks on it using add_class().

error_handler

This should be assigned a callable, taking two arguments: a xso.XSO instance, which is the partial(!) top-level stream element and an exception indicating the failure.

Partial here means that it is not guaranteed that anything but the attributes on the partial XSO itself are there. Any children or text payload is most likely missing, as it probably caused the error.

New in version 0.4.

Sending XSOs:

send_xso(obj)[source]

Send an XSO over the stream.

Parameters

obj (XSO) – The object to send.

Raises

Calling send_xso() while the stream is disconnected, disconnecting or still waiting for the remote to send a stream header causes ConnectionError to be raised. If the stream got disconnected due to a transport or stream error, that exception is re-raised instead of the ConnectionError.

Changed in version 0.9: Exceptions occurring during serialisation of obj are re-raised and no content is sent over the stream. The stream is still valid and usable afterwards.

Manipulating stream state:

async starttls(ssl_context, post_handshake_callback=None)[source]

Start TLS on the transport and wait for it to complete.

The ssl_context and post_handshake_callback arguments are forwarded to the transports aioopenssl.STARTTLSTransport.starttls() coroutine method.

If the transport does not support starttls, RuntimeError is raised; support for starttls can be discovered by querying can_starttls().

After starttls() returns, you must call reset(). Any other method may fail in interesting ways as the internal state is discarded when starttls succeeds, for security reasons. reset() re-creates the internal structures.

reset()[source]

Reset the stream by discarding all state and re-sending the stream header.

Calling reset() when the stream is disconnected or currently disconnecting results in either ConnectionError being raised or the exception which caused the stream to die (possibly a received stream error or a transport error) to be reraised.

reset() puts the stream into STREAM_HEADER_SENT state and it cannot be used for sending XSOs until the peer stream header has been received. Usually, this is not a problem as stream resets only occur during stream negotiation and stream negotiation typically waits for the peers feature node to arrive first.

close()[source]

Close the XML stream and the underlying transport.

This gracefully shuts down the XML stream and the transport, if possible by writing the eof using asyncio.Transport.write_eof() after sending the stream footer.

After a call to close(), no other stream manipulating or sending method can be called; doing so will result in a ConnectionError exception or any exception caused by the transport during shutdown.

Calling close() while the stream is closing or closed is a no-op.

abort()[source]

Abort the stream by writing an EOF if possible and closing the transport.

The transport is closed using asyncio.BaseTransport.close(), so buffered data is sent, but no more data will be received. The stream is in State.CLOSED state afterwards.

This also works if the stream is currently closing, that is, waiting for the peer to send a stream footer. In that case, the stream will be closed locally as if the stream footer had been received.

New in version 0.5.

Controlling debug output:

mute()[source]

A context-manager which prohibits logging of data sent over the stream.

Data sent over the stream is replaced with <!-- some bytes omitted -->. This is mainly useful during authentication.

Waiting for stream state changes:

error_future()[source]

Return a future which will receive the next XML stream error as exception.

It is safe to cancel the future at any time.

features_future()[source]

Return a future which will receive the next XML stream features (as return value) or the next XML stream error (as exception), whichever happens first.

It is safe to cancel this future at any time.

Monitoring stream aliveness:

deadtime_soft_limit

This is part of the timeout handling of XMLStream objects. The timeout handling works like this:

  • There exist two timers, soft and hard limit.

  • Reception of any data resets both timers.

  • When the soft limit timer is triggered, the on_deadtime_soft_limit_tripped() signal is emitted. Nothing else happens. The user is expected to do something which would cause the server to send data to prevent the hard limit from tripping.

  • When the hard limit timer is triggered, the stream is considered dead and it is aborted and closed with an appropriate ConnectionError.

This attribute controls the timeout for the soft limit timer, as datetime.timedelta. The default is None, which disables the timer altogether.

New in version 0.10.

deadtime_hard_limit

This is part of the timeout handling of XMLStream objects. See deadtime_soft_limit for details.

This attribute controls the timeout for the hard limit timer, as datetime.timedelta. The default is None, which disables the timer altogether.

Setting the hard limit timer to None means that the XMLStream will never timeout by itself.

New in version 0.10.

Signals:

signal on_closing(reason)

A Signal which fires when the underlying transport of the stream reports an error or when a stream error is received. The signal is fired with the corresponding exception as the only argument.

If the stream gets closed by the application without any error, the argument is None.

By the time the callback fires, the stream is already unusable for sending stanzas. It may however still receive stanzas, if the stream shutdown was initiated by the application and the peer has not yet send its stream footer.

If the application is not able to handle these stanzas, it is legitimate to disconnect their handlers from the stanza_parser; the stream will be able to deal with unhandled top level stanzas correctly at this point (by ignoring them).

signal on_deadtime_soft_limit_tripped()

Emits when the soft limit dead time has been exceeded.

See deadtime_soft_limit for general information on the timeout handling.

New in version 0.10.

Timeouts:

shutdown_timeout

The maximum time to wait for the peer </stream:stream> before forcing to close the transport and considering the stream closed.

Utilities for XML streams

async aioxmpp.protocol.send_and_wait_for(xmlstream, send, wait_for, timeout=None, cb=None)[source]
async aioxmpp.protocol.reset_stream_and_get_features(xmlstream, timeout=None)[source]

Enumerations

class aioxmpp.protocol.Mode(value)[source]

Possible modes of connection for an XML stream. These define the namespaces used.

C2S

A client stream connected to a server. This is the default mode and, currently, the only available mode.

class aioxmpp.protocol.State(value)[source]

The possible states of a XMLStream:

READY

The initial state; this is the case when no underlying transport is connected.

STREAM_HEADER_SENT

After a asyncio.Transport calls XMLStream.connection_made() on the xml stream, it sends the stream header and enters this state.

OPEN

When the stream header of the peer is received, this state is entered and the XML stream can be used for sending and receiving XSOs.

CLOSING

After XMLStream.close() is called, this state is entered. We sent a stream footer and an EOF, if the underlying transport supports this. We still have to wait for the peer to close the stream.

In this state and all following states, ConnectionError instances are raised whenever an attempt is made to write to the stream. The exact instance depends on the reason of the closure.

In this state, the stream waits for the remote to send a stream footer and the connection to shut down. For application purposes, the stream is already closed.

At this point, the stream is properly closed on the XML stream level. This is the point where XMLStream.close_and_wait() returns.

CLOSED

This state is entered when the connection is lost in any way. This is the final state.