Hopefully working disconnecting/connecting when more resources are connected

This commit is contained in:
Jan Kaluza 2011-08-18 13:37:43 +02:00
parent 93ddc62068
commit c7f2b62980
13 changed files with 179 additions and 74 deletions

View file

@ -134,12 +134,12 @@ void Server::handleSessionStarted(boost::shared_ptr<ServerFromClientSession> ses
}
void Server::handleSessionFinished(boost::shared_ptr<ServerFromClientSession> session) {
if (!session->getRemoteJID().isValid()) {
Swift::Presence::ref presence = Swift::Presence::create();
presence->setFrom(session->getBareJID());
presence->setType(Swift::Presence::Unavailable);
dynamic_cast<ServerStanzaChannel *>(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<ServerStanzaChannel *>(stanzaChannel_)->onPresenceReceived(presence);
// }
serverFromClientSessions.erase(std::remove(serverFromClientSessions.begin(), serverFromClientSessions.end(), session), serverFromClientSessions.end());
std::cout << "FINISH SESSION2 " << serverFromClientSessions.size() << "\n";
session->onSessionStarted.disconnect(

View file

@ -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<AuthSuccess>(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<AuthFailure>(new AuthFailure));
finishSession(AuthenticationFailedError);
}
@ -91,18 +80,7 @@ void ServerFromClientSession::handleElement(boost::shared_ptr<Element> 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<AuthFailure>(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<SessionError>&) {
userRegistry_->stopLogin(JID(user_, getLocalJID().getDomain()), this);
}
void ServerFromClientSession::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, const PKCS12Certificate& cert) {
tlsLayer = new TLSServerLayer(tlsContextFactory);
if (!tlsLayer->setServerCertificate(cert)) {

View file

@ -53,11 +53,13 @@ namespace Swift {
return Swift::JID(user_, getLocalJID().getDomain());
}
void handlePasswordValid();
void handlePasswordInvalid();
private:
void handleElement(boost::shared_ptr<Element>);
void handleStreamStart(const ProtocolHeader& header);
void handlePasswordValid(const std::string &user);
void handlePasswordInvalid(const std::string &user);
void handleSessionFinished(const boost::optional<SessionError>&);
void setInitialized();
bool isInitialized() const {

View file

@ -29,6 +29,7 @@ namespace {
}
void ServerStanzaChannel::addSession(boost::shared_ptr<ServerFromClientSession> 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> presence) {
send(presence);
}
void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr<Element> element) {
void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr<Element> element, bool last) {
std::vector<boost::shared_ptr<ServerFromClientSession> > candidateSessions;
for (std::list<boost::shared_ptr<ServerFromClientSession> >::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<boost::shared_ptr<ServerFromClientSession> >::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> stanza) {
void ServerStanzaChannel::handleSessionFinished(const boost::optional<Session::SessionError>&, const boost::shared_ptr<ServerFromClientSession>& 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> element, const boost::shared_ptr<ServerFromClientSession>& session) {

View file

@ -26,7 +26,7 @@ namespace Swift {
void sendMessage(boost::shared_ptr<Message> message);
void sendPresence(boost::shared_ptr<Presence> presence);
void finishSession(const JID& to, boost::shared_ptr<Element> element);
void finishSession(const JID& to, boost::shared_ptr<Element> element, bool last = false);
bool getStreamManagementEnabled() const {
return false;

View file

@ -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<JID,SafeByteArray>::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) {

View file

@ -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:

View file

@ -9,6 +9,7 @@
#include <string>
#include <Swiften/Base/SafeByteArray.h>
#include <boost/signal.hpp>
#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<void (const std::string &user)> onPasswordValid;
boost::signal<void (const std::string &user)> onPasswordInvalid;
virtual void isValidUserPassword(const JID& user, ServerFromClientSession *session, const SafeByteArray& password) = 0;
virtual void stopLogin(const JID &/*user*/, ServerFromClientSession *) {};
};
}

View file

@ -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;

View file

@ -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<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid);
void addUser(User *user);

View file

@ -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<void (const Swift::JID &user)> onConnectUser;
boost::signal<void (const Swift::JID &user)> onDisconnectUser;
mutable std::map<std::string, std::string> users;
private:
typedef struct {
std::string password;
Swift::ServerFromClientSession *session;
} Sess;
mutable std::map<std::string, Sess> users;
mutable Config *config;
};

View file

@ -30,6 +30,9 @@
#include "Swiften/Elements/MUCPayload.h"
#include "log4cxx/logger.h"
#include <boost/foreach.hpp>
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
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) {

View file

@ -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<Swift::Message> 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<Swift::ServerStanzaChannel *>(m_component->getStanzaChannel())->finishSession(user, boost::shared_ptr<Swift::Element>(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<Swift::ServerStanzaChannel *>(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<Swift::ServerStanzaChannel *>(m_component->getStanzaChannel())->onPresenceReceived(response);
}
}