From c7f2b6298073e84d58fe12d6546a91e4f6871074 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 18 Aug 2011 13:37:43 +0200 Subject: [PATCH] Hopefully working disconnecting/connecting when more resources are connected --- include/Swiften/Server/Server.cpp | 12 ++-- .../Server/ServerFromClientSession.cpp | 32 ++------- .../Swiften/Server/ServerFromClientSession.h | 6 +- .../Swiften/Server/ServerStanzaChannel.cpp | 33 ++++++--- include/Swiften/Server/ServerStanzaChannel.h | 2 +- include/Swiften/Server/SimpleUserRegistry.cpp | 11 ++- include/Swiften/Server/SimpleUserRegistry.h | 2 +- include/Swiften/Server/UserRegistry.h | 9 +-- include/transport/transport.h | 2 +- include/transport/usermanager.h | 3 +- include/transport/userregistry.h | 69 ++++++++++++++++--- src/user.cpp | 23 +++++++ src/usermanager.cpp | 49 ++++++++++--- 13 files changed, 179 insertions(+), 74 deletions(-) diff --git a/include/Swiften/Server/Server.cpp b/include/Swiften/Server/Server.cpp index 61e0a494..ff623b62 100644 --- a/include/Swiften/Server/Server.cpp +++ b/include/Swiften/Server/Server.cpp @@ -134,12 +134,12 @@ 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); - } +// 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()); std::cout << "FINISH SESSION2 " << serverFromClientSessions.size() << "\n"; session->onSessionStarted.disconnect( diff --git a/include/Swiften/Server/ServerFromClientSession.cpp b/include/Swiften/Server/ServerFromClientSession.cpp index e6ef09b4..3950ddd3 100644 --- a/include/Swiften/Server/ServerFromClientSession.cpp +++ b/include/Swiften/Server/ServerFromClientSession.cpp @@ -45,32 +45,21 @@ ServerFromClientSession::ServerFromClientSession( } ServerFromClientSession::~ServerFromClientSession() { - std::cout << "DESTRUCTOR;\n"; - userRegistry_->onPasswordValid.disconnect(boost::bind(&ServerFromClientSession::handlePasswordValid, this, _1)); - userRegistry_->onPasswordInvalid.disconnect(boost::bind(&ServerFromClientSession::handlePasswordInvalid, this, _1)); if (tlsLayer) { delete tlsLayer; } } -void ServerFromClientSession::handlePasswordValid(const std::string &user) { - if (user != JID(user_, getLocalJID().getDomain()).toString()) - return; +void ServerFromClientSession::handlePasswordValid() { 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(); } } -void ServerFromClientSession::handlePasswordInvalid(const std::string &user) { - if (user != JID(user_, getLocalJID().getDomain()).toString() || authenticated_) - return; +void ServerFromClientSession::handlePasswordInvalid() { 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 AuthFailure)); finishSession(AuthenticationFailedError); } @@ -91,18 +80,7 @@ void ServerFromClientSession::handleElement(boost::shared_ptr element) else { PLAINMessage plainMessage(authRequest->getMessage() ? *authRequest->getMessage() : createSafeByteArray("")); user_ = plainMessage.getAuthenticationID(); - userRegistry_->onPasswordInvalid(JID(plainMessage.getAuthenticationID(), getLocalJID().getDomain()).toBare().toString()); - userRegistry_->onPasswordValid.connect(boost::bind(&ServerFromClientSession::handlePasswordValid, this, _1)); - userRegistry_->onPasswordInvalid.connect(boost::bind(&ServerFromClientSession::handlePasswordInvalid, this, _1)); - if (userRegistry_->isValidUserPassword(JID(plainMessage.getAuthenticationID(), getLocalJID().getDomain()), plainMessage.getPassword())) { - // we're waiting for usermanager signal now -// authenticated_ = true; -// getXMPPLayer()->resetParser(); - } - else { - getXMPPLayer()->writeElement(boost::shared_ptr(new AuthFailure)); - finishSession(AuthenticationFailedError); - } + userRegistry_->isValidUserPassword(JID(plainMessage.getAuthenticationID(), getLocalJID().getDomain()), this, plainMessage.getPassword()); } } else { @@ -170,6 +148,10 @@ void ServerFromClientSession::setAllowSASLEXTERNAL() { allowSASLEXTERNAL = true; } +void ServerFromClientSession::handleSessionFinished(const boost::optional&) { + userRegistry_->stopLogin(JID(user_, getLocalJID().getDomain()), this); +} + void ServerFromClientSession::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, const PKCS12Certificate& cert) { tlsLayer = new TLSServerLayer(tlsContextFactory); if (!tlsLayer->setServerCertificate(cert)) { diff --git a/include/Swiften/Server/ServerFromClientSession.h b/include/Swiften/Server/ServerFromClientSession.h index 6fbe44ff..b22da265 100644 --- a/include/Swiften/Server/ServerFromClientSession.h +++ b/include/Swiften/Server/ServerFromClientSession.h @@ -53,11 +53,13 @@ namespace Swift { return Swift::JID(user_, getLocalJID().getDomain()); } + void handlePasswordValid(); + void handlePasswordInvalid(); + private: void handleElement(boost::shared_ptr); void handleStreamStart(const ProtocolHeader& header); - void handlePasswordValid(const std::string &user); - void handlePasswordInvalid(const std::string &user); + void handleSessionFinished(const boost::optional&); void setInitialized(); bool isInitialized() const { diff --git a/include/Swiften/Server/ServerStanzaChannel.cpp b/include/Swiften/Server/ServerStanzaChannel.cpp index bfa33db4..4ac5acc8 100644 --- a/include/Swiften/Server/ServerStanzaChannel.cpp +++ b/include/Swiften/Server/ServerStanzaChannel.cpp @@ -29,6 +29,7 @@ namespace { } void ServerStanzaChannel::addSession(boost::shared_ptr session) { + std::cout << "ADDING SESSION\n"; sessions[session->getRemoteJID().toBare().toString()].push_back(session); session->onSessionFinished.connect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); session->onElementReceived.connect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); @@ -53,20 +54,30 @@ void ServerStanzaChannel::sendPresence(boost::shared_ptr presence) { send(presence); } -void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr element) { +void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr element, bool last) { std::vector > candidateSessions; for (std::list >::const_iterator i = sessions[to.toBare().toString()].begin(); i != sessions[to.toBare().toString()].end(); ++i) { - if (element) { - (*i)->sendElement(element); - } candidateSessions.push_back(*i); } for (std::vector >::const_iterator i = candidateSessions.begin(); i != candidateSessions.end(); ++i) { - + removeSession(*i); + if (element) { + (*i)->sendElement(element); + } + + if (last && (*i)->getRemoteJID().isValid()) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom((*i)->getRemoteJID()); + presence->setType(Swift::Presence::Unavailable); + onPresenceReceived(presence); + } + (*i)->finishSession(); - sessions[to.toBare().toString()].remove(*i); std::cout << "FINISH SESSION " << sessions[to.toBare().toString()].size() << "\n"; + if (last) { + break; + } } } @@ -109,10 +120,12 @@ void ServerStanzaChannel::send(boost::shared_ptr stanza) { void ServerStanzaChannel::handleSessionFinished(const boost::optional&, const boost::shared_ptr& session) { removeSession(session); - Swift::Presence::ref presence = Swift::Presence::create(); - presence->setFrom(session->getRemoteJID()); - presence->setType(Swift::Presence::Unavailable); - onPresenceReceived(presence); +// if (!session->initiatedFinish()) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(session->getRemoteJID()); + presence->setType(Swift::Presence::Unavailable); + onPresenceReceived(presence); +// } } void ServerStanzaChannel::handleElement(boost::shared_ptr element, const boost::shared_ptr& session) { diff --git a/include/Swiften/Server/ServerStanzaChannel.h b/include/Swiften/Server/ServerStanzaChannel.h index fc05294d..69158eea 100644 --- a/include/Swiften/Server/ServerStanzaChannel.h +++ b/include/Swiften/Server/ServerStanzaChannel.h @@ -26,7 +26,7 @@ namespace Swift { void sendMessage(boost::shared_ptr message); void sendPresence(boost::shared_ptr presence); - void finishSession(const JID& to, boost::shared_ptr element); + void finishSession(const JID& to, boost::shared_ptr element, bool last = false); bool getStreamManagementEnabled() const { return false; diff --git a/include/Swiften/Server/SimpleUserRegistry.cpp b/include/Swiften/Server/SimpleUserRegistry.cpp index a9f24c62..36b421fc 100644 --- a/include/Swiften/Server/SimpleUserRegistry.cpp +++ b/include/Swiften/Server/SimpleUserRegistry.cpp @@ -11,9 +11,16 @@ namespace Swift { SimpleUserRegistry::SimpleUserRegistry() { } -bool SimpleUserRegistry::isValidUserPassword(const JID& user, const SafeByteArray& password) { +void SimpleUserRegistry::isValidUserPassword(const JID& user, ServerFromClientSession *session, const SafeByteArray& password) { std::map::const_iterator i = users.find(user); - return i != users.end() ? i->second == password : false; + + + if (i != users.end() && i->second == password) { + session->handlePasswordValid(); + } + else { + session->handlePasswordInvalid(); + } } void SimpleUserRegistry::addUser(const JID& user, const std::string& password) { diff --git a/include/Swiften/Server/SimpleUserRegistry.h b/include/Swiften/Server/SimpleUserRegistry.h index 7e177979..f44ae2cb 100644 --- a/include/Swiften/Server/SimpleUserRegistry.h +++ b/include/Swiften/Server/SimpleUserRegistry.h @@ -19,7 +19,7 @@ namespace Swift { public: SimpleUserRegistry(); - virtual bool isValidUserPassword(const JID& user, const SafeByteArray& password); + virtual void isValidUserPassword(const JID& user, ServerFromClientSession *session, const SafeByteArray& password); void addUser(const JID& user, const std::string& password); private: diff --git a/include/Swiften/Server/UserRegistry.h b/include/Swiften/Server/UserRegistry.h index 5781802b..2ded68e3 100644 --- a/include/Swiften/Server/UserRegistry.h +++ b/include/Swiften/Server/UserRegistry.h @@ -9,6 +9,7 @@ #include #include #include +#include "Swiften/Server/ServerFromClientSession.h" namespace Swift { class JID; @@ -17,12 +18,8 @@ namespace Swift { public: virtual ~UserRegistry(); - virtual bool isValidUserPassword(const JID& user, const SafeByteArray& password) = 0; - - virtual void stopLogin(const JID &/*user*/) {}; - - boost::signal onPasswordValid; - boost::signal onPasswordInvalid; + virtual void isValidUserPassword(const JID& user, ServerFromClientSession *session, const SafeByteArray& password) = 0; + virtual void stopLogin(const JID &/*user*/, ServerFromClientSession *) {}; }; } diff --git a/include/transport/transport.h b/include/transport/transport.h index 527326b7..39773731 100644 --- a/include/transport/transport.h +++ b/include/transport/transport.h @@ -180,7 +180,7 @@ namespace Transport { Swift::PresenceOracle *m_presenceOracle; Swift::StanzaChannel *m_stanzaChannel; Swift::IQRouter *m_iqRouter; - Swift::UserRegistry *m_userRegistry; + Transport::UserRegistry *m_userRegistry; StorageBackend *m_storageBackend; DiscoInfoResponder *m_discoInfoResponder; DiscoItemsResponder *m_discoItemsResponder; diff --git a/include/transport/usermanager.h b/include/transport/usermanager.h index 2067552d..578d9f2a 100644 --- a/include/transport/usermanager.h +++ b/include/transport/usermanager.h @@ -82,6 +82,7 @@ class UserManager { } void connectUser(const Swift::JID &user); + void disconnectUser(const Swift::JID &user); private: void handlePresence(Swift::Presence::ref presence); @@ -89,7 +90,7 @@ class UserManager { void handleGeneralPresenceReceived(Swift::Presence::ref presence); void handleProbePresence(Swift::Presence::ref presence); void handleSubscription(Swift::Presence::ref presence); - void handleRemoveTimeout(const std::string jid, bool reconnect); + void handleRemoveTimeout(const std::string jid, User *user, bool reconnect); // void handleDiscoInfoResponse(boost::shared_ptr info, Swift::ErrorPayload::ref error, const Swift::JID& jid); void addUser(User *user); diff --git a/include/transport/userregistry.h b/include/transport/userregistry.h index ce8667d1..04dfe3a6 100644 --- a/include/transport/userregistry.h +++ b/include/transport/userregistry.h @@ -32,31 +32,84 @@ class UserRegistry : public Swift::UserRegistry { public: UserRegistry(Config *cfg) {config = cfg;} ~UserRegistry() {} - bool isValidUserPassword(const Swift::JID& user, const Swift::SafeByteArray& password) { + void isValidUserPassword(const Swift::JID& user, Swift::ServerFromClientSession *session, const Swift::SafeByteArray& password) { if (!CONFIG_STRING(config, "service.admin_username").empty() && user.getNode() == CONFIG_STRING(config, "service.admin_username")) { if (Swift::safeByteArrayToString(password) == CONFIG_STRING(config, "service.admin_password")) { - onPasswordValid(user); + session->handlePasswordValid(); } else { - onPasswordInvalid(user); + session->handlePasswordInvalid(); } - return true; + return; } - users[user.toBare().toString()] = Swift::safeByteArrayToString(password); + std::string key = user.toBare().toString(); + + // Users try to connect twice + if (users.find(key) != users.end()) { + // Kill the first session if the second password is same + if (Swift::safeByteArrayToString(password) == users[key].password) { + Swift::ServerFromClientSession *tmp = users[key].session; + users[key].session = session; + tmp->handlePasswordInvalid(); + } + else { + session->handlePasswordInvalid(); + std::cout << "invalid " << session << "\n"; + return; + } + } + std::cout << "adding " << session << "\n"; + users[key].password = Swift::safeByteArrayToString(password); + users[key].session = session; onConnectUser(user); - return true; + return; + } + + void stopLogin(const Swift::JID& user, Swift::ServerFromClientSession *session) { + std::cout << "stopping " << session << "\n"; + std::string key = user.toBare().toString(); + if (users.find(key) != users.end()) { + if (users[key].session == session) { + std::cout << "DISCONNECT USER\n"; + onDisconnectUser(user); + users.erase(key); + } + } + } + + void onPasswordValid(const Swift::JID &user) { + std::string key = user.toBare().toString(); + if (users.find(key) != users.end()) { + users[key].session->handlePasswordValid(); + users.erase(key); + } + } + + void onPasswordInvalid(const Swift::JID &user) { + std::string key = user.toBare().toString(); + if (users.find(key) != users.end()) { + users[key].session->handlePasswordInvalid(); + users.erase(key); + } } const std::string &getUserPassword(const std::string &barejid) { - return users[barejid]; + return users[barejid].password; } boost::signal onConnectUser; + boost::signal onDisconnectUser; - mutable std::map users; + private: + typedef struct { + std::string password; + Swift::ServerFromClientSession *session; + } Sess; + + mutable std::map users; mutable Config *config; }; diff --git a/src/user.cpp b/src/user.cpp index d16d6bd0..110bbfe7 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -30,6 +30,9 @@ #include "Swiften/Elements/MUCPayload.h" #include "log4cxx/logger.h" #include +#include +#include +#include using namespace log4cxx; using namespace boost; @@ -99,8 +102,28 @@ Swift::JID User::getJIDWithFeature(const std::string &feature) { return jid; } +static void +print_trace (void) +{ +void *array[80]; +size_t size; +char **strings; +size_t i; + +size = backtrace (array, 80); +strings = backtrace_symbols (array, size); + +printf ("Obtained %zd stack frames.\n", size); + +for (i = 0; i < size; i++) + printf ("%s\n", strings[i]); + +free (strings); +} + void User::handlePresence(Swift::Presence::ref presence) { std::cout << "PRESENCE " << presence->getFrom().toString() << "\n"; +// print_trace(); if (!m_connected) { // we are not connected to legacy network, so we should do it when disco#info arrive :) if (m_readyForConnect == false) { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 48c6f33c..d44fb573 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -55,6 +55,7 @@ UserManager::UserManager(Component *component, UserRegistry *userRegistry, Stora m_component->getStanzaChannel()->onPresenceReceived.connect(bind(&UserManager::handleGeneralPresenceReceived, this, _1)); m_userRegistry->onConnectUser.connect(bind(&UserManager::connectUser, this, _1)); + m_userRegistry->onDisconnectUser.connect(bind(&UserManager::disconnectUser, this, _1)); // component->onDiscoInfoResponse.connect(bind(&UserManager::handleDiscoInfoResponse, this, _1, _2, _3)); m_removeTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(1); @@ -187,16 +188,20 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { Swift::Presence::ref highest = m_component->getPresenceOracle()->getHighestPriorityPresence(presence->getFrom().toBare()); // There's no presence for this user, so disconnect if (!highest || (highest && highest->getType() == Swift::Presence::Unavailable)) { - m_removeTimer->onTick.connect(boost::bind(&UserManager::handleRemoveTimeout, this, user->getJID().toBare().toString(), false)); + m_removeTimer->onTick.connect(boost::bind(&UserManager::handleRemoveTimeout, this, user->getJID().toBare().toString(), user, false)); m_removeTimer->start(); } } } } -void UserManager::handleRemoveTimeout(const std::string jid, bool reconnect) { - m_removeTimer->onTick.disconnect(boost::bind(&UserManager::handleRemoveTimeout, this, jid, reconnect)); +void UserManager::handleRemoveTimeout(const std::string jid, User *u, bool reconnect) { + m_removeTimer->onTick.disconnect(boost::bind(&UserManager::handleRemoveTimeout, this, jid, u, reconnect)); User *user = getUser(jid); + if (user != u) { + return; + } + if (user) { // Reconnect means that we're disconnecting this User instance from legacy network backend, // but we're going to connect it again in this call. Currently it's used only when @@ -310,14 +315,28 @@ void UserManager::connectUser(const Swift::JID &user) { // Called by UserRegistry in server mode when user connects the server and wants // to connect legacy network if (m_users.find(user.toBare().toString()) != m_users.end()) { - if (CONFIG_BOOL(m_component->getConfig(), "service.more_resources")) { - m_userRegistry->onPasswordValid(user); - } - else { - // Reconnect the user if more resources per one legacy network account are not allowed - m_removeTimer->onTick.connect(boost::bind(&UserManager::handleRemoveTimeout, this, user.toBare().toString(), true)); - m_removeTimer->start(); + if (m_users[user.toBare().toString()]->isConnected()) { + if (CONFIG_BOOL(m_component->getConfig(), "service.more_resources")) { + m_userRegistry->onPasswordValid(user); + } + else { + boost::shared_ptr msg(new Swift::Message()); + msg->setBody("You have signed on from another location."); + msg->setTo(user); + msg->setFrom(m_component->getJID()); + m_component->getStanzaChannel()->sendMessage(msg); + m_userRegistry->onPasswordValid(user); + m_component->onUserPresenceReceived.disconnect(bind(&UserManager::handlePresence, this, _1)); + dynamic_cast(m_component->getStanzaChannel())->finishSession(user, boost::shared_ptr(new Swift::StreamError()), true); + m_component->onUserPresenceReceived.connect(bind(&UserManager::handlePresence, this, _1)); + } } +// } +// else { +// // Reconnect the user if more resources per one legacy network account are not allowed +// m_removeTimer->onTick.connect(boost::bind(&UserManager::handleRemoveTimeout, this, user.toBare().toString(), true)); +// m_removeTimer->start(); +// } } else { // simulate initial available presence to start connecting this user. @@ -325,9 +344,17 @@ void UserManager::connectUser(const Swift::JID &user) { response->setTo(m_component->getJID()); response->setFrom(user); response->setType(Swift::Presence::Available); - m_component->onUserPresenceReceived(response); + dynamic_cast(m_component->getStanzaChannel())->onPresenceReceived(response); } } +void UserManager::disconnectUser(const Swift::JID &user) { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo(m_component->getJID()); + response->setFrom(user); + response->setType(Swift::Presence::Unavailable); + dynamic_cast(m_component->getStanzaChannel())->onPresenceReceived(response); +} + }