From d30bee2b6820408ed4a3dae07a854184dffcc0ab Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Sun, 12 Aug 2007 15:50:59 +0000 Subject: [PATCH] Yet another fix for reentrant SSL messages git-svn-id: https://mumble.svn.sourceforge.net/svnroot/mumble/trunk@730 05730e5d-ab1b-0410-a4ac-84af385074fa --- src/Connection.cpp | 76 ++++++++++++++++++++++++++++++---------------- src/Connection.h | 6 +++- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/Connection.cpp b/src/Connection.cpp index 44d1865df..a83653a69 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -42,12 +42,14 @@ #include #endif +int Connection::iReceiveLevel = 0; +QSet Connection::qsReceivers; + Connection::Connection(QObject *p, QSslSocket *qtsSock) : QObject(p) { qtsSocket = qtsSock; qtsSocket->setParent(this); iPacketLength = -1; bDisconnectedEmitted = false; - bReentry = false; dUDPPingAvg = dUDPPingVar = 0.0L; dTCPPingAvg = dTCPPingVar = 0.0L; @@ -61,6 +63,7 @@ Connection::Connection(QObject *p, QSslSocket *qtsSock) : QObject(p) { } Connection::~Connection() { + qsReceivers.remove(this); } int Connection::activityTime() const { @@ -69,38 +72,59 @@ int Connection::activityTime() const { void Connection::socketRead() { // QSslSocket will, during writes, emit readyRead. Meaning we'd reenter from the message handlers. - // That is bad, and furthermore the remaining data will be parsed on the next run through, so - // there's no need. - if (bReentry) + // At the same time, DBus connections don't like getting multiple concurrent requests. + // So, this is a big workaround to serialize user requests. + + int iPrevLevel = iReceiveLevel; + + iReceiveLevel = 2; + + if (iPrevLevel == 2) { + // Recursive entry. Put on list and ignore. + qsReceivers.insert(this); return; - bReentry = true; + } else if (iPrevLevel == 1) { + // We're iterating from the topmost one. + qsReceivers.remove(this); + } - int iAvailable; + int iAvailable = qtsSocket->bytesAvailable(); - while (1) { - iAvailable = qtsSocket->bytesAvailable(); - - if (iPacketLength == -1) { - if (iAvailable < 3) - break; - - unsigned char a_ucBuffer[3]; - - qtsSocket->read(reinterpret_cast(a_ucBuffer), 3); - iPacketLength = ((a_ucBuffer[0] << 16) & 0xff0000) + ((a_ucBuffer[1] << 8) & 0xff00) + a_ucBuffer[2]; - iAvailable -= 3; + if (iPacketLength == -1) { + if (iAvailable < 3) { + iReceiveLevel = iPrevLevel; + return; } - if ((iPacketLength != -1) && (iAvailable >= iPacketLength)) { - QByteArray qbaBuffer = qtsSocket->read(iPacketLength); - emit message(qbaBuffer); - iPacketLength = -1; - qtLastPacket.restart(); - } else { - break; + unsigned char a_ucBuffer[3]; + + qtsSocket->read(reinterpret_cast(a_ucBuffer), 3); + iPacketLength = ((a_ucBuffer[0] << 16) & 0xff0000) + ((a_ucBuffer[1] << 8) & 0xff00) + a_ucBuffer[2]; + iAvailable -= 3; + } + + if ((iPacketLength != -1) && (iAvailable >= iPacketLength)) { + QByteArray qbaBuffer = qtsSocket->read(iPacketLength); + iPacketLength = -1; + qtLastPacket.restart(); + iAvailable -= iPacketLength; + if (iAvailable >= 3) + qsReceivers.insert(this); + + emit message(qbaBuffer); + } + + // At this point, the current *this might be destroyed. + + if (iPrevLevel == 0) { + iReceiveLevel = 1; + QSet::const_iterator i = qsReceivers.constBegin(); + while (i != qsReceivers.constEnd()) { + (*i)->socketRead(); + i = qsReceivers.constBegin(); } } - bReentry = false; + iReceiveLevel = iPrevLevel; } void Connection::socketError(QAbstractSocket::SocketError) { diff --git a/src/Connection.h b/src/Connection.h index 40635238e..4bf24e2de 100644 --- a/src/Connection.h +++ b/src/Connection.h @@ -38,12 +38,14 @@ class Message; class Connection : public QObject { Q_OBJECT + private: + static int iReceiveLevel; + static QSet qsReceivers; protected: QSslSocket *qtsSocket; QTime qtLastPacket; int iPacketLength; bool bDisconnectedEmitted; - bool bReentry; protected slots: void socketRead(); void socketError(QAbstractSocket::SocketError); @@ -55,6 +57,8 @@ class Connection : public QObject { void connectionClosed(QString reason); void message(QByteArray &); void handleSslErrors(const QList &); + + void recheckBuffer(); public: Connection(QObject *parent, QSslSocket *qtsSocket); ~Connection();