From 00fcb4ab7fd1a2af1c81d9cab13ee23fb7d7b73c Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Sun, 12 Jul 2009 15:16:49 +0200 Subject: [PATCH] Fixes #682 - Core crashes on client connection Big thanks to seezer for debuging and researching! --- src/core/core.cpp | 61 ++++++++++++++++++++++++++++++++++++++++------- src/core/core.h | 11 +++++++-- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 0b0a999d..9d6e1722 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -34,6 +34,22 @@ // migration related #include +// ============================== +// 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() { @@ -611,19 +627,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(); 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 2c1fa07d..f31b3776 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -48,8 +48,8 @@ struct NetworkInfo; class Core : public QObject { Q_OBJECT - public: - static Core * instance(); +public: + static Core *instance(); static void destroy(); static void saveState(); @@ -380,12 +380,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); @@ -393,6 +396,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()); @@ -415,6 +421,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(); -- 2.20.1