# `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=<Logger aioxmpp (WARNING)>, loop=None)

  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. The future will also receive any pre-stream-features exception.

  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)

    Send an XSO over the stream.

    Parameters: | obj (`XSO`) – The object to send.

    Raises:

    - ConnectionError – if the connection is not fully established yet.
    - aioxmpp.errors.StreamError – if a stream error was received or sent.
    - OSError – if the stream got disconnected due to a another permanent transport error
    - Exception – if serialisation of obj failed

    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 occuring 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:

  coroutine `starttls`(ssl_context, post_handshake_callback=None)

    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`()

    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`()

    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`()

    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`()

    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.

  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

coroutine `aioxmpp.protocol.``send_and_wait_for`(xmlstream, send, wait_for, timeout=None, cb=None)

coroutine `aioxmpp.protocol.``reset_stream_and_get_features`(xmlstream, timeout=None)

## Enumerations

class `aioxmpp.protocol.``Mode`

  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`

  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.

  `CLOSING_STREAM_FOOTER_RECEIVED`

    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.