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, sorted_attributes=False, base_logger=<logging.Logger object at 0x7f9ae21c76d8>, loop=None)[source]

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

to must be a domain JID which identifies the domain to which the stream shall connect.

features_future must be a asyncio.Future instance; the XML stream will set the first StreamFeatures node it receives as the result of the future.

sorted_attributes is mainly for unittesting purposes; this is an argument to the XMPPXMLGenerator and slows down the XML serialization, but produces deterministic results, which is important for testing. Generally, it is preferred to leave this argument at its default.

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.

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 obj over the stream.

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.

Manipulating stream state:

coroutine 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 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.

Signals:

signal on_closing()

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).

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

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

Enumerations

class aioxmpp.protocol.Mode[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[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.