Improved backends creation, fixed race-condition during connection process

This commit is contained in:
HanzZ 2011-07-17 23:05:54 +02:00
parent 25f5516757
commit 808a9067c5
10 changed files with 102 additions and 11 deletions

View file

@ -109,9 +109,6 @@ void Server::handleNewClientConnection(boost::shared_ptr<Connection> 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<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);
}
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) {

View file

@ -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<AuthSuccess>(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<AuthFailure>(new AuthFailure));
finishSession(AuthenticationFailedError);
onPasswordInvalid();

View file

@ -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<Element>);
void handleStreamStart(const ProtocolHeader& header);

View file

@ -19,6 +19,8 @@ namespace Swift {
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;

View file

@ -107,6 +107,7 @@ class NetworkPluginServer {
std::list<Backend *> m_clients;
Swift::Timer::ref m_pingTimer;
Component *m_component;
std::list<User *> m_waitingUsers;
};
}

View file

@ -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<void ()> onReadyToConnect;
boost::signal<void (Swift::Presence::ref presence)> onPresenceChanged;
boost::signal<void (const std::string &room, const std::string &nickname, const std::string &password)> onRoomJoined;

View file

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

View file

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

View file

@ -189,6 +189,28 @@ void NetworkPluginServer::handleNewClientConnection(boost::shared_ptr<Swift::Con
c->onDisconnected.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_ptr<Swift
WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_VCARD);
Backend *c = (Backend *) user->getData();
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());
}

View file

@ -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<Swift::ServerStanzaChannel *>(m_component->getStanzaChannel())->finishSession(m_jid, boost::shared_ptr<Swift::Element>(new Swift::StreamError()));
if (!m_readyForConnect) {
if (!m_connected) {
m_userManager->removeUser(this);
}
}