aboutsummaryrefslogtreecommitdiff
path: root/src/base/QXmppStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/QXmppStream.cpp')
-rw-r--r--src/base/QXmppStream.cpp122
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);
+}