From: Marcus Eggenberger Date: Sun, 12 Jul 2009 13:16:49 +0000 (+0200) Subject: Fixes #682 - Core crashes on client connection X-Git-Tag: 0.5-rc1~169 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=e049ffc61b5e260a49d73102a74c3821af827e77;hp=48f1843a91a923784b4a58b5bbe8a25aa7d395c8 Fixes #682 - Core crashes on client connection Big thanks to seezer for debuging and researching! --- diff --git a/src/core/core.cpp b/src/core/core.cpp index 18f022b1..b2e3ee43 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -40,6 +40,22 @@ # include #endif /* Q_OS_WIN32 */ +// ============================== +// Custom Events +// ============================== +const int Core::AddClientEventId = QEvent::registerEventType(); + +class AddClientEvent : public QEvent { +public: + AddClientEvent(QTcpSocket *socket, UserId uid) : QEvent(QEvent::Type(Core::AddClientEventId)), socket(socket), userId(uid) {} + QTcpSocket *socket; + UserId userId; +}; + + +// ============================== +// Core +// ============================== Core *Core::instanceptr = 0; Core *Core::instance() { @@ -648,20 +664,48 @@ void Core::clientDisconnected() { } void Core::setupClientSession(QTcpSocket *socket, UserId uid) { - // Find or create session for validated user - SessionThread *sess; - if(sessions.contains(uid)) sess = sessions[uid]; - else sess = createSession(uid); - // Hand over socket, session then sends state itself + // From now on everything is handled by the client session disconnect(socket, 0, this, 0); - socket->flush(); // ensure that the write cache is flushed before we hand over the connection to another thread. + socket->flush(); blocksizes.remove(socket); clientInfo.remove(socket); - if(!sess) { - qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(socket->peerAddress().toString()); + + // Find or create session for validated user + SessionThread *session; + if(sessions.contains(uid)) { + session = sessions[uid]; + } else { + session = createSession(uid); + if(!session) { + qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(socket->peerAddress().toString()); + socket->close(); + return; + } + } + + // as we are currently handling an event triggered by incoming data on this socket + // it is unsafe to directly move the socket to the client thread. + QCoreApplication::postEvent(this, new AddClientEvent(socket, uid)); +} + +void Core::customEvent(QEvent *event) { + if(event->type() == AddClientEventId) { + AddClientEvent *addClientEvent = static_cast(event); + addClientHelper(addClientEvent->socket, addClientEvent->userId); + return; + } +} + +void Core::addClientHelper(QTcpSocket *socket, UserId uid) { + // Find or create session for validated user + if(!sessions.contains(uid)) { + qWarning() << qPrintable(tr("Could not find a session for client:")) << qPrintable(socket->peerAddress().toString()); socket->close(); + return; } - sess->addClient(socket); + + SessionThread *session = sessions[uid]; + session->addClient(socket); } void Core::setupInternalClientSession(SignalProxy *proxy) { diff --git a/src/core/core.h b/src/core/core.h index fd67fa8a..c1f397ae 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -51,8 +51,8 @@ class AbstractSqlMigrationWriter; class Core : public QObject { Q_OBJECT - public: - static Core * instance(); +public: + static Core *instance(); static void destroy(); static void saveState(); @@ -382,12 +382,15 @@ class Core : public QObject { static inline QTimer &syncTimer() { return instance()->_storageSyncTimer; } + static const int AddClientEventId; + public slots: //! Make storage data persistent /** \note This method is threadsafe. */ void syncStorage(); void setupInternalClientSession(SignalProxy *proxy); + signals: //! Sent when a BufferInfo is updated in storage. void bufferInfoUpdated(UserId user, const BufferInfo &info); @@ -395,6 +398,9 @@ signals: //! Relay From CoreSession::sessionState(const QVariant &). Used for internal connection only void sessionState(const QVariant &); +protected: + virtual void customEvent(QEvent *event); + private slots: bool startListening(); void stopListening(const QString &msg = QString()); @@ -418,6 +424,7 @@ private: SessionThread *createSession(UserId userId, bool restoreState = false); void setupClientSession(QTcpSocket *socket, UserId uid); + void addClientHelper(QTcpSocket *socket, UserId uid); void processClientMessage(QTcpSocket *socket, const QVariantMap &msg); //void processCoreSetup(QTcpSocket *socket, QVariantMap &msg); QString setupCoreForInternalUsage();