Yet another fix for reentrant SSL messages

git-svn-id: https://mumble.svn.sourceforge.net/svnroot/mumble/trunk@730 05730e5d-ab1b-0410-a4ac-84af385074fa
This commit is contained in:
Thorvald Natvig 2007-08-12 15:50:59 +00:00
parent 6551302f57
commit d30bee2b68
2 changed files with 55 additions and 27 deletions

View File

@ -42,12 +42,14 @@
#include <winsock2.h>
#endif
int Connection::iReceiveLevel = 0;
QSet<Connection *> 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<char *>(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<char *>(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<Connection *>::const_iterator i = qsReceivers.constBegin();
while (i != qsReceivers.constEnd()) {
(*i)->socketRead();
i = qsReceivers.constBegin();
}
}
bReentry = false;
iReceiveLevel = iPrevLevel;
}
void Connection::socketError(QAbstractSocket::SocketError) {

View File

@ -38,12 +38,14 @@ class Message;
class Connection : public QObject {
Q_OBJECT
private:
static int iReceiveLevel;
static QSet<Connection *> 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<QSslError> &);
void recheckBuffer();
public:
Connection(QObject *parent, QSslSocket *qtsSocket);
~Connection();