diff options
Diffstat (limited to 'src/base/QXmppStream.cpp')
| -rw-r--r-- | src/base/QXmppStream.cpp | 122 |
1 files changed, 119 insertions, 3 deletions
diff --git a/src/base/QXmppStream.cpp b/src/base/QXmppStream.cpp index 9ea20856..215bf86b 100644 --- a/src/base/QXmppStream.cpp +++ b/src/base/QXmppStream.cpp @@ -27,11 +27,13 @@ #include "QXmppLogger.h" #include "QXmppStanza.h" #include "QXmppStream.h" +#include "QXmppStreamManagement_p.h" #include "QXmppUtils.h" #include <QBuffer> #include <QDomDocument> #include <QHostAddress> +#include <QMap> #include <QRegExp> #include <QSslSocket> #include <QStringList> @@ -51,10 +53,15 @@ public: // incoming stream state QByteArray streamStart; + + bool streamManagementEnabled; + QMap<unsigned, QByteArray> unacknowledgedStanzas; + unsigned lastOutgoingSequenceNumber; + unsigned lastIncomingSequenceNumber; }; QXmppStreamPrivate::QXmppStreamPrivate() - : socket(0) + : socket(0), streamManagementEnabled(false), lastOutgoingSequenceNumber(0), lastIncomingSequenceNumber(0) { } @@ -86,6 +93,7 @@ QXmppStream::~QXmppStream() void QXmppStream::disconnectFromHost() { + d->streamManagementEnabled = false; if (d->socket) { if (d->socket->state() == QAbstractSocket::ConnectedState) { sendData(streamRootElementEnd); @@ -140,8 +148,15 @@ bool QXmppStream::sendPacket(const QXmppStanza &packet) QXmlStreamWriter xmlStream(&data); packet.toXml(&xmlStream); + bool isXmppStanza = packet.isXmppStanza(); + if (isXmppStanza && d->streamManagementEnabled) + d->unacknowledgedStanzas[++d->lastOutgoingSequenceNumber] = data; + // send packet - return sendData(data); + bool success = sendData(data); + if (isXmppStanza) + sendAcknowledgementRequest(); + return success; } /// Returns the QSslSocket used for this stream. @@ -253,7 +268,17 @@ void QXmppStream::_q_socketReadyRead() // process stanzas QDomElement nodeRecv = doc.documentElement().firstChildElement(); while (!nodeRecv.isNull()) { - handleStanza(nodeRecv); + if (QXmppStreamManagementAck::isStreamManagementAck(nodeRecv)) + handleAcknowledgement(nodeRecv); + else if (QXmppStreamManagementReq::isStreamManagementReq(nodeRecv)) + sendAcknowledgement(); + else { + handleStanza(nodeRecv); + if(nodeRecv.tagName() == QLatin1String("message") || + nodeRecv.tagName() == QLatin1String("presence") || + nodeRecv.tagName() == QLatin1String("iq")) + ++d->lastIncomingSequenceNumber; + } nodeRecv = nodeRecv.nextSiblingElement(); } @@ -262,4 +287,95 @@ void QXmppStream::_q_socketReadyRead() disconnectFromHost(); } +/// Enables Stream Management acks / reqs (XEP-0198). +/// +/// \param resetSequenceNumber Indicates if the sequence numbers should be resetted. +/// This must be done iff the stream is not resumed. +void QXmppStream::enableStreamManagement(bool resetSequenceNumber) +{ + d->streamManagementEnabled = true; + + if (resetSequenceNumber) { + d->lastOutgoingSequenceNumber = 0; + d->lastIncomingSequenceNumber = 0; + + // resend unacked stanzas + if (!d->unacknowledgedStanzas.empty()) { + QMap<unsigned, QByteArray> oldUnackedStanzas = d->unacknowledgedStanzas; + d->unacknowledgedStanzas.clear(); + for (QMap<unsigned, QByteArray>::iterator it = oldUnackedStanzas.begin(); it != oldUnackedStanzas.end(); ++it) { + d->unacknowledgedStanzas[++d->lastOutgoingSequenceNumber] = it.value(); + sendData(it.value()); + } + sendAcknowledgementRequest(); + } + } else { + // resend unacked stanzas + if (!d->unacknowledgedStanzas.empty()) { + for (QMap<unsigned, QByteArray>::iterator it = d->unacknowledgedStanzas.begin(); it != d->unacknowledgedStanzas.end(); ++it) + sendData(it.value()); + sendAcknowledgementRequest(); + } + } +} +/// Returns the sequence number of the last incoming stanza (XEP-0198). +unsigned QXmppStream::lastIncomingSequenceNumber() const +{ + return d->lastIncomingSequenceNumber; +} + +/// Sets the last acknowledged sequence number for outgoing stanzas (XEP-0198). +void QXmppStream::setAcknowledgedSequenceNumber(unsigned sequenceNumber) +{ + for (QMap<unsigned, QByteArray>::iterator it = d->unacknowledgedStanzas.begin(); it != d->unacknowledgedStanzas.end(); ) { + if (it.key() <= sequenceNumber) + it = d->unacknowledgedStanzas.erase(it); + else + ++it; + } +} + +/// Handles an incoming acknowledgement from XEP-0198. +/// +/// \param element +void QXmppStream::handleAcknowledgement(QDomElement &element) +{ + if (!d->streamManagementEnabled) + return; + + QXmppStreamManagementAck ack; + ack.parse(element); + setAcknowledgedSequenceNumber(ack.seqNo()); +} + +/// Sends an acknowledgement as defined in XEP-0198. +void QXmppStream::sendAcknowledgement() +{ + if (!d->streamManagementEnabled) + return; + + // prepare packet + QByteArray data; + QXmlStreamWriter xmlStream(&data); + QXmppStreamManagementAck ack(d->lastIncomingSequenceNumber); + ack.toXml(&xmlStream); + + // send packet + sendData(data); +} + +/// Sends an acknowledgement request as defined in XEP-0198. +void QXmppStream::sendAcknowledgementRequest() +{ + if (!d->streamManagementEnabled) + return; + + // prepare packet + QByteArray data; + QXmlStreamWriter xmlStream(&data); + QXmppStreamManagementReq::toXml(&xmlStream); + + // send packet + sendData(data); +} |
