aboutsummaryrefslogtreecommitdiff
path: root/src/base
diff options
context:
space:
mode:
authorLinus Jahn <lnj@kaidan.im>2020-07-26 20:33:07 +0200
committerLinus Jahn <lnj@kaidan.im>2021-01-09 14:37:47 +0100
commit8570b4c56616547e5fa2530e6b9733fb37cf02a3 (patch)
treedd25156ba0680c964eef13828cb1de0bdf7b48ee /src/base
parent9d181aa8e4d31612391586785144dfefa75356ff (diff)
downloadqxmpp-8570b4c56616547e5fa2530e6b9733fb37cf02a3.tar.gz
QXmppStream: Move stream management into separate class
Diffstat (limited to 'src/base')
-rw-r--r--src/base/QXmppStream.cpp145
-rw-r--r--src/base/QXmppStream.h6
-rw-r--r--src/base/QXmppStreamManagement.cpp130
-rw-r--r--src/base/QXmppStreamManagement_p.h36
4 files changed, 188 insertions, 129 deletions
diff --git a/src/base/QXmppStream.cpp b/src/base/QXmppStream.cpp
index c5862e6c..2b0c0f05 100644
--- a/src/base/QXmppStream.cpp
+++ b/src/base/QXmppStream.cpp
@@ -47,7 +47,7 @@ static bool randomSeeded = false;
class QXmppStreamPrivate
{
public:
- QXmppStreamPrivate();
+ QXmppStreamPrivate(QXmppStream *stream);
QString dataBuffer;
QSslSocket *socket;
@@ -55,17 +55,13 @@ public:
// incoming stream state
QString streamOpenElement;
- bool streamManagementEnabled;
- QMap<unsigned int, QByteArray> unacknowledgedStanzas;
- unsigned int lastOutgoingSequenceNumber;
- unsigned int lastIncomingSequenceNumber;
+ // stream management
+ QXmppStreamManager streamManager;
};
-QXmppStreamPrivate::QXmppStreamPrivate()
+QXmppStreamPrivate::QXmppStreamPrivate(QXmppStream *stream)
: socket(nullptr),
- streamManagementEnabled(false),
- lastOutgoingSequenceNumber(0),
- lastIncomingSequenceNumber(0)
+ streamManager(stream)
{
}
@@ -76,7 +72,7 @@ QXmppStreamPrivate::QXmppStreamPrivate()
///
QXmppStream::QXmppStream(QObject *parent)
: QXmppLoggable(parent),
- d(new QXmppStreamPrivate)
+ d(new QXmppStreamPrivate(this))
{
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
// Make sure the random number generator is seeded
@@ -100,7 +96,8 @@ QXmppStream::~QXmppStream()
///
void QXmppStream::disconnectFromHost()
{
- d->streamManagementEnabled = false;
+ d->streamManager.handleDisconnect();
+
if (d->socket) {
if (d->socket->state() == QAbstractSocket::ConnectedState) {
sendData(QByteArrayLiteral("</stream:stream>"));
@@ -120,7 +117,7 @@ void QXmppStream::disconnectFromHost()
///
void QXmppStream::handleStart()
{
- d->streamManagementEnabled = false;
+ d->streamManager.handleStart();
d->dataBuffer.clear();
d->streamOpenElement.clear();
}
@@ -159,15 +156,12 @@ bool QXmppStream::sendPacket(const QXmppStanza &packet)
QXmlStreamWriter xmlStream(&data);
packet.toXml(&xmlStream);
- // store packet for possible later stream resumption
- if (d->streamManagementEnabled && packet.isXmppStanza()) {
- d->unacknowledgedStanzas.insert(++d->lastOutgoingSequenceNumber, data);
- }
-
// send packet
bool success = sendData(data);
- if (packet.isXmppStanza())
- sendAcknowledgementRequest();
+
+ // handle stream management
+ d->streamManager.handlePacketSent(packet, data);
+
return success;
}
@@ -313,19 +307,12 @@ void QXmppStream::processData(const QString &data)
// process stanzas
auto stanza = doc.documentElement().firstChildElement();
for (; !stanza.isNull(); stanza = stanza.nextSiblingElement()) {
- if (QXmppStreamManagementAck::isStreamManagementAck(stanza)) {
- handleAcknowledgement(stanza);
- } else if (QXmppStreamManagementReq::isStreamManagementReq(stanza)) {
- sendAcknowledgement();
- } else {
- handleStanza(stanza);
-
- if (stanza.tagName() == QLatin1String("message") ||
- stanza.tagName() == QLatin1String("presence") ||
- stanza.tagName() == QLatin1String("iq")) {
- ++d->lastIncomingSequenceNumber;
- }
- }
+ // handle possible stream management packets first
+ if (d->streamManager.handleStanza(stanza))
+ continue;
+
+ // process all other kinds of packets
+ handleStanza(stanza);
}
// process stream end
@@ -344,34 +331,7 @@ void QXmppStream::processData(const QString &data)
///
void QXmppStream::enableStreamManagement(bool resetSequenceNumber)
{
- d->streamManagementEnabled = true;
-
- if (resetSequenceNumber) {
- d->lastOutgoingSequenceNumber = 0;
- d->lastIncomingSequenceNumber = 0;
-
- // resend unacked stanzas
- if (!d->unacknowledgedStanzas.isEmpty()) {
- const auto oldUnackedStanzas = d->unacknowledgedStanzas;
- d->unacknowledgedStanzas.clear();
-
- for (const auto &value : oldUnackedStanzas) {
- d->unacknowledgedStanzas.insert(++d->lastOutgoingSequenceNumber, value);
- sendData(value);
- }
-
- sendAcknowledgementRequest();
- }
- } else {
- // resend unacked stanzas
- if (!d->unacknowledgedStanzas.isEmpty()) {
- for (const auto &value : std::as_const(d->unacknowledgedStanzas)) {
- sendData(value);
- }
-
- sendAcknowledgementRequest();
- }
- }
+ d->streamManager.enableStreamManagement(resetSequenceNumber);
}
///
@@ -381,7 +341,7 @@ void QXmppStream::enableStreamManagement(bool resetSequenceNumber)
///
unsigned int QXmppStream::lastIncomingSequenceNumber() const
{
- return d->lastIncomingSequenceNumber;
+ return d->streamManager.lastIncomingSequenceNumber();
}
///
@@ -392,66 +352,5 @@ unsigned int QXmppStream::lastIncomingSequenceNumber() const
///
void QXmppStream::setAcknowledgedSequenceNumber(unsigned int sequenceNumber)
{
- for (auto 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
-///
-/// \since QXmpp 1.0
-///
-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}.
-///
-/// \since QXmpp 1.0
-///
-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}.
-///
-/// \since QXmpp 1.0
-///
-void QXmppStream::sendAcknowledgementRequest()
-{
- if (!d->streamManagementEnabled)
- return;
-
- // prepare packet
- QByteArray data;
- QXmlStreamWriter xmlStream(&data);
- QXmppStreamManagementReq::toXml(&xmlStream);
-
- // send packet
- sendData(data);
+ d->streamManager.setAcknowledgedSequenceNumber(sequenceNumber);
}
diff --git a/src/base/QXmppStream.h b/src/base/QXmppStream.h
index 86b044ca..0015705b 100644
--- a/src/base/QXmppStream.h
+++ b/src/base/QXmppStream.h
@@ -79,12 +79,6 @@ protected:
unsigned int lastIncomingSequenceNumber() const;
void setAcknowledgedSequenceNumber(unsigned int sequenceNumber);
-private:
- // XEP-0198: Stream Management
- void handleAcknowledgement(QDomElement &element);
- void sendAcknowledgement();
- void sendAcknowledgementRequest();
-
public Q_SLOTS:
virtual void disconnectFromHost();
virtual bool sendData(const QByteArray &);
diff --git a/src/base/QXmppStreamManagement.cpp b/src/base/QXmppStreamManagement.cpp
index 45f0b94c..e2fc621c 100644
--- a/src/base/QXmppStreamManagement.cpp
+++ b/src/base/QXmppStreamManagement.cpp
@@ -24,6 +24,7 @@
#include "QXmppConstants_p.h"
#include "QXmppGlobal.h"
#include "QXmppStanza_p.h"
+#include "QXmppStream.h"
#include "QXmppStreamManagement_p.h"
QXmppStreamManagementEnable::QXmppStreamManagementEnable(const bool resume, const unsigned max)
@@ -324,3 +325,132 @@ void QXmppStreamManagementReq::toXml(QXmlStreamWriter *writer)
writer->writeDefaultNamespace(ns_stream_management);
writer->writeEndElement();
}
+
+QXmppStreamManager::QXmppStreamManager(QXmppStream *stream)
+ : stream(stream)
+{
+}
+
+unsigned int QXmppStreamManager::lastIncomingSequenceNumber() const
+{
+ return m_lastIncomingSequenceNumber;
+}
+
+void QXmppStreamManager::handleDisconnect()
+{
+ m_enabled = false;
+}
+
+void QXmppStreamManager::handleStart()
+{
+ m_enabled = false;
+}
+
+void QXmppStreamManager::handlePacketSent(const QXmppStanza &packet, const QByteArray &data)
+{
+ if (m_enabled && packet.isXmppStanza()) {
+ m_unacknowledgedStanzas.insert(++m_lastOutgoingSequenceNumber, data);
+ sendAcknowledgementRequest();
+ }
+}
+
+bool QXmppStreamManager::handleStanza(const QDomElement &stanza)
+{
+ if (QXmppStreamManagementAck::isStreamManagementAck(stanza)) {
+ handleAcknowledgement(stanza);
+ return true;
+ }
+ if (QXmppStreamManagementReq::isStreamManagementReq(stanza)) {
+ sendAcknowledgement();
+ return true;
+ }
+
+ if (stanza.tagName() == QLatin1String("message") ||
+ stanza.tagName() == QLatin1String("presence") ||
+ stanza.tagName() == QLatin1String("iq")) {
+ m_lastIncomingSequenceNumber++;
+ }
+ return false;
+}
+
+void QXmppStreamManager::enableStreamManagement(bool resetSequenceNumber)
+{
+ m_enabled = true;
+
+ if (resetSequenceNumber) {
+ m_lastOutgoingSequenceNumber = 0;
+ m_lastIncomingSequenceNumber = 0;
+
+ // resend unacked stanzas
+ if (!m_unacknowledgedStanzas.isEmpty()) {
+ const auto oldUnackedStanzas = m_unacknowledgedStanzas;
+ m_unacknowledgedStanzas.clear();
+
+ for (const auto &value : oldUnackedStanzas) {
+ m_unacknowledgedStanzas.insert(++m_lastOutgoingSequenceNumber, value);
+ stream->sendData(value);
+ }
+
+ sendAcknowledgementRequest();
+ }
+ } else {
+ // resend unacked stanzas
+ if (!m_unacknowledgedStanzas.isEmpty()) {
+ for (const auto &value : std::as_const(m_unacknowledgedStanzas)) {
+ stream->sendData(value);
+ }
+
+ sendAcknowledgementRequest();
+ }
+ }
+}
+
+void QXmppStreamManager::setAcknowledgedSequenceNumber(unsigned int sequenceNumber)
+{
+ for (auto it = m_unacknowledgedStanzas.begin(); it != m_unacknowledgedStanzas.end();) {
+ if (it.key() <= sequenceNumber) {
+ it = m_unacknowledgedStanzas.erase(it);
+ } else {
+ break;
+ }
+ }
+}
+
+void QXmppStreamManager::handleAcknowledgement(const QDomElement &element)
+{
+ if (!m_enabled)
+ return;
+
+ QXmppStreamManagementAck ack;
+ ack.parse(element);
+ setAcknowledgedSequenceNumber(ack.seqNo());
+}
+
+void QXmppStreamManager::sendAcknowledgement()
+{
+ if (!m_enabled)
+ return;
+
+ // prepare packet
+ QByteArray data;
+ QXmlStreamWriter xmlStream(&data);
+ QXmppStreamManagementAck ack(m_lastIncomingSequenceNumber);
+ ack.toXml(&xmlStream);
+
+ // send packet
+ stream->sendData(data);
+}
+
+void QXmppStreamManager::sendAcknowledgementRequest()
+{
+ if (!m_enabled)
+ return;
+
+ // prepare packet
+ QByteArray data;
+ QXmlStreamWriter xmlStream(&data);
+ QXmppStreamManagementReq::toXml(&xmlStream);
+
+ // send packet
+ stream->sendData(data);
+}
diff --git a/src/base/QXmppStreamManagement_p.h b/src/base/QXmppStreamManagement_p.h
index ab250109..389276d7 100644
--- a/src/base/QXmppStreamManagement_p.h
+++ b/src/base/QXmppStreamManagement_p.h
@@ -30,6 +30,9 @@
#include <QDomDocument>
#include <QXmlStreamWriter>
+class QXmppStream;
+
+//
// W A R N I N G
// -------------
//
@@ -191,4 +194,37 @@ public:
/// \endcond
};
+//
+// This manager is used in the QXmppStream. It contains the parts of stream
+// management that are shared between server and client connections.
+//
+class QXmppStreamManager
+{
+public:
+ explicit QXmppStreamManager(QXmppStream *stream);
+
+ unsigned int lastIncomingSequenceNumber() const;
+
+ void handleDisconnect();
+ void handleStart();
+ void handlePacketSent(const QXmppStanza &packet, const QByteArray &data);
+ bool handleStanza(const QDomElement &stanza);
+
+ void enableStreamManagement(bool resetSequenceNumber);
+ void setAcknowledgedSequenceNumber(unsigned int sequenceNumber);
+
+private:
+ void handleAcknowledgement(const QDomElement &element);
+
+ void sendAcknowledgement();
+ void sendAcknowledgementRequest();
+
+ QXmppStream *stream;
+
+ bool m_enabled = false;
+ QMap<unsigned int, QByteArray> m_unacknowledgedStanzas;
+ unsigned int m_lastOutgoingSequenceNumber = 0;
+ unsigned int m_lastIncomingSequenceNumber = 0;
+};
+
#endif