diff --git a/include/Swiften/Server/Server.cpp b/include/Swiften/Server/Server.cpp index 89f478e4..65a1a193 100644 --- a/include/Swiften/Server/Server.cpp +++ b/include/Swiften/Server/Server.cpp @@ -109,9 +109,6 @@ void Server::handleNewClientConnection(boost::shared_ptr connection) serverFromClientSession->onSessionFinished.connect( boost::bind(&Server::handleSessionFinished, this, serverFromClientSession)); - serverFromClientSession->onPasswordInvalid.connect( - boost::bind(&Server::handleSessionFinished, this, - serverFromClientSession)); serverFromClientSession->onDataRead.connect(boost::bind(&Server::handleDataRead, this, _1)); serverFromClientSession->onDataWritten.connect(boost::bind(&Server::handleDataWritten, this, _1)); @@ -137,7 +134,17 @@ void Server::handleSessionStarted(boost::shared_ptr ses } void Server::handleSessionFinished(boost::shared_ptr session) { + if (!session->getRemoteJID().isValid()) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(session->getBareJID()); + presence->setType(Swift::Presence::Unavailable); + dynamic_cast(stanzaChannel_)->onPresenceReceived(presence); + } serverFromClientSessions.erase(std::remove(serverFromClientSessions.begin(), serverFromClientSessions.end(), session), serverFromClientSessions.end()); + session->onSessionStarted.disconnect( + boost::bind(&Server::handleSessionStarted, this, session)); + session->onSessionFinished.disconnect( + boost::bind(&Server::handleSessionFinished, this, session)); } void Server::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, const PKCS12Certificate& cert) { diff --git a/include/Swiften/Server/ServerFromClientSession.cpp b/include/Swiften/Server/ServerFromClientSession.cpp index a5817807..f69b63cf 100644 --- a/include/Swiften/Server/ServerFromClientSession.cpp +++ b/include/Swiften/Server/ServerFromClientSession.cpp @@ -47,6 +47,7 @@ ServerFromClientSession::ServerFromClientSession( } ServerFromClientSession::~ServerFromClientSession() { + std::cout << "DESTRUCTOR;\n"; if (tlsLayer) { delete tlsLayer; } @@ -56,6 +57,8 @@ void ServerFromClientSession::handlePasswordValid(const std::string &user) { if (user != JID(user_, getLocalJID().getDomain()).toString()) return; if (!isInitialized()) { + userRegistry_->onPasswordValid.disconnect(boost::bind(&ServerFromClientSession::handlePasswordValid, this, _1)); + userRegistry_->onPasswordInvalid.disconnect(boost::bind(&ServerFromClientSession::handlePasswordInvalid, this, _1)); getXMPPLayer()->writeElement(boost::shared_ptr(new AuthSuccess())); authenticated_ = true; getXMPPLayer()->resetParser(); @@ -66,7 +69,8 @@ void ServerFromClientSession::handlePasswordInvalid(const std::string &user) { if (user != JID(user_, getLocalJID().getDomain()).toString() || authenticated_) return; if (!isInitialized()) { - user_ = "/././"; + userRegistry_->onPasswordValid.disconnect(boost::bind(&ServerFromClientSession::handlePasswordValid, this, _1)); + userRegistry_->onPasswordInvalid.disconnect(boost::bind(&ServerFromClientSession::handlePasswordInvalid, this, _1)); getXMPPLayer()->writeElement(boost::shared_ptr(new AuthFailure)); finishSession(AuthenticationFailedError); onPasswordInvalid(); diff --git a/include/Swiften/Server/ServerFromClientSession.h b/include/Swiften/Server/ServerFromClientSession.h index 7de233d3..f0a62e65 100644 --- a/include/Swiften/Server/ServerFromClientSession.h +++ b/include/Swiften/Server/ServerFromClientSession.h @@ -50,6 +50,10 @@ namespace Swift { void addTLSEncryption(TLSServerContextFactory* tlsContextFactory, const PKCS12Certificate& cert); + Swift::JID getBareJID() { + return Swift::JID(user_, getLocalJID().getDomain()); + } + private: void handleElement(boost::shared_ptr); void handleStreamStart(const ProtocolHeader& header); diff --git a/include/Swiften/Server/UserRegistry.h b/include/Swiften/Server/UserRegistry.h index 56456f0f..5781802b 100644 --- a/include/Swiften/Server/UserRegistry.h +++ b/include/Swiften/Server/UserRegistry.h @@ -19,6 +19,8 @@ namespace Swift { virtual bool isValidUserPassword(const JID& user, const SafeByteArray& password) = 0; + virtual void stopLogin(const JID &/*user*/) {}; + boost::signal onPasswordValid; boost::signal onPasswordInvalid; diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index f5cbd9b0..36b40469 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -107,6 +107,7 @@ class NetworkPluginServer { std::list m_clients; Swift::Timer::ref m_pingTimer; Component *m_component; + std::list m_waitingUsers; }; } diff --git a/include/transport/user.h b/include/transport/user.h index 1b271dba..135f82f2 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -81,6 +81,18 @@ class User { void handleDisconnected(const std::string &error); + bool isReadyToConnect() { + return m_readyForConnect; + } + + void setConnected(bool connected) { + m_connected = connected; + } + + bool isConnected() { + return m_connected; + } + boost::signal onReadyToConnect; boost::signal onPresenceChanged; boost::signal onRoomJoined; diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 9d5c8700..ba0d900a 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -10,7 +10,7 @@ admin_username=admin admin_password=test #cert= #patch to PKCS#12 certificate #cert_password= #password to that certificate if any -users_per_backend=2 +users_per_backend=1 backend=../../backends/libpurple/spectrum_libpurple_backend #backend=../../backends/libircclient-qt/spectrum_libircclient-qt_backend #protocol=prpl-jabber diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 9b9365b0..0dedd646 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -8,7 +8,7 @@ backend_host=localhost # < this option doesn't work yet backend_port=10001 #cert= #patch to PKCS#12 certificate #cert_password= #password to that certificate if any -users_per_backend=2 +users_per_backend=1 backend=spectrum_libpurple_backend #backend=spectrum_libircclient-qt_backend protocol=prpl-jabber diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 647a7d6d..42baf81f 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -189,6 +189,28 @@ void NetworkPluginServer::handleNewClientConnection(boost::shared_ptronDisconnected.connect(boost::bind(&NetworkPluginServer::handleSessionFinished, this, client)); c->onDataRead.connect(boost::bind(&NetworkPluginServer::handleDataRead, this, client, _1)); sendPing(client); + + // some users are in queue waiting for this backend + while(!m_waitingUsers.empty()) { + // There's no new backend, so stop associating users and wait for new backend, + // which has been already spawned in getFreeClient() call. + if (getFreeClient() == NULL) + break; + + User *u = m_waitingUsers.front(); + m_waitingUsers.pop_front(); + + LOG4CXX_INFO(logger, "Associating " << u->getJID().toString() << " with this backend"); + + // associate backend with user + handleUserCreated(u); + + // connect user if it's ready + if (u->isReadyToConnect()) { + handleUserReadyToConnect(u); + } + + } } void NetworkPluginServer::handleSessionFinished(Backend *c) { @@ -217,6 +239,13 @@ void NetworkPluginServer::handleConnectedPayload(const std::string &data) { // TODO: ERROR return; } + + User *user = m_userManager->getUser(payload.user()); + if (!user) { + return; + } + + user->setConnected(true); m_component->m_userRegistry->onPasswordValid(payload.user()); } @@ -524,8 +553,8 @@ void NetworkPluginServer::handleUserCreated(User *user) { Backend *c = getFreeClient(); if (!c) { - LOG4CXX_ERROR(logger, "There is no backend to handle user " << user->getJID().toString()); - user->handleDisconnected("Internal Server Error (no free backend to handle your session), please reconnect."); + LOG4CXX_INFO(logger, "There is no backend to handle user " << user->getJID().toString() << ". Adding him to queue."); + m_waitingUsers.push_back(user); return; } user->setData(c); @@ -552,6 +581,9 @@ void NetworkPluginServer::handleUserReadyToConnect(User *user) { WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_LOGIN); Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } send(c->connection, message); } @@ -572,6 +604,9 @@ void NetworkPluginServer::handleUserPresenceChanged(User *user, Swift::Presence: WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_STATUS_CHANGED); Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } send(c->connection, message); } @@ -590,6 +625,9 @@ void NetworkPluginServer::handleRoomJoined(User *user, const std::string &r, con WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_JOIN_ROOM); Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } send(c->connection, message); NetworkConversation *conv = new NetworkConversation(user->getConversationManager(), r, true); @@ -612,6 +650,9 @@ void NetworkPluginServer::handleRoomLeft(User *user, const std::string &r) { WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_LEAVE_ROOM); Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } send(c->connection, message); NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(r); @@ -626,6 +667,7 @@ void NetworkPluginServer::handleRoomLeft(User *user, const std::string &r) { void NetworkPluginServer::handleUserDestroyed(User *user) { std::cout << "HANDLE_DESTROYED\n"; + m_waitingUsers.remove(user); UserInfo userInfo = user->getUserInfo(); pbnetwork::Logout logout; @@ -680,6 +722,9 @@ void NetworkPluginServer::handleMessageReceived(NetworkConversation *conv, boost WRAP(message, type); Backend *c = (Backend *) conv->getConversationManager()->getUser()->getData(); + if (!c) { + return; + } send(c->connection, message); } } @@ -722,6 +767,9 @@ void NetworkPluginServer::handleMessageReceived(NetworkConversation *conv, boost WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_CONV_MESSAGE); Backend *c = (Backend *) conv->getConversationManager()->getUser()->getData(); + if (!c) { + return; + } send(c->connection, message); } } @@ -742,6 +790,9 @@ void NetworkPluginServer::handleBuddyRemoved(Buddy *b) { WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_BUDDY_REMOVED); Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } send(c->connection, message); } @@ -765,6 +816,9 @@ void NetworkPluginServer::handleBuddyUpdated(Buddy *b, const Swift::RosterItemPa WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_BUDDY_CHANGED); Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } send(c->connection, message); } @@ -785,6 +839,9 @@ void NetworkPluginServer::handleVCardUpdated(User *user, boost::shared_ptrgetData(); + if (!c) { + return; + } send(c->connection, message); } @@ -800,6 +857,9 @@ void NetworkPluginServer::handleVCardRequired(User *user, const std::string &nam WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_VCARD); Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } send(c->connection, message); } @@ -838,7 +898,7 @@ NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient() { } } - if (spawnNew) { + if (spawnNew || c == NULL) { exec_(CONFIG_STRING(m_config, "service.backend").c_str(), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getConfigFile().c_str()); } diff --git a/src/user.cpp b/src/user.cpp index a4a2214b..5a18c790 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -172,6 +172,7 @@ void User::onConnectingTimeout() { } void User::handleDisconnected(const std::string &error) { + if (error.empty()) { LOG4CXX_INFO(logger, m_jid.toString() << ": Disconnected from legacy network"); } @@ -186,12 +187,12 @@ void User::handleDisconnected(const std::string &error) { msg->setFrom(m_component->getJID()); m_component->getStanzaChannel()->sendMessage(msg); - // In server mode, server finishes the session and pass unavailable session to userManager, + // In server mode, server finishes the session and pass unavailable session to userManager if we're connected to legacy network, // so we can't removeUser() in server mode, because it would be removed twice. // Once in finishSession and once in m_userManager->removeUser. if (m_component->inServerMode()) { dynamic_cast(m_component->getStanzaChannel())->finishSession(m_jid, boost::shared_ptr(new Swift::StreamError())); - if (!m_readyForConnect) { + if (!m_connected) { m_userManager->removeUser(this); } }