diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a08cdcd647604c682fe0949d65eb5a4b90ba5681 --- /dev/null +++ b/src/networkpluginserver.cpp @@ -0,0 +1,240 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "transport/networkpluginserver.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/storagebackend.h" +#include "transport/rostermanager.h" +#include "transport/usermanager.h" +#include "transport/conversationmanager.h" +#include "transport/localbuddy.h" +#include "transport/config.h" +#include "Swiften/Swiften.h" +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Elements/StreamError.h" +#include "pbnetwork.pb.h" +#include "sys/wait.h" +#include "sys/signal.h" + +namespace Transport { + +#define WRAP(MESSAGE, TYPE) pbnetwork::WrapperMessage wrap; \ + wrap.set_type(TYPE); \ + wrap.set_payload(MESSAGE); \ + wrap.SerializeToString(&MESSAGE); + +static int exec_(const char *path, const char *host, const char *port, const char *config) { +// char *argv[] = {(char*)script_name, '\0'}; + int status = 0; + pid_t pid = fork(); + if ( pid == 0 ) { + // child process + execlp(path, path, "--host", host, "--port", port, config, NULL); + exit(1); + } else if ( pid < 0 ) { + // fork failed + status = -1; + } + return status; +} + +static void SigCatcher(int n) { + wait3(NULL,WNOHANG,NULL); +} + +static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payload) { + buddy->setName(payload.buddyname()); + buddy->setAlias(payload.alias()); + std::vector groups; + groups.push_back(payload.groups()); + buddy->setGroups(groups); + buddy->setStatus(Swift::StatusShow((Swift::StatusShow::Type) payload.status()), payload.statusmessage()); + buddy->setIconHash(payload.iconhash()); +} + +NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, UserManager *userManager) { + m_userManager = userManager; + m_config = config; + m_userManager->onUserCreated.connect(boost::bind(&NetworkPluginServer::handleUserCreated, this, _1)); + m_userManager->onUserDestroyed.connect(boost::bind(&NetworkPluginServer::handleUserDestroyed, this, _1)); + + m_server = component->getFactories()->getConnectionFactory()->createConnectionServer(10000); + m_server->onNewConnection.connect(boost::bind(&NetworkPluginServer::handleNewClientConnection, this, _1)); + m_server->start(); + + signal(SIGCHLD, SigCatcher); + + exec_(CONFIG_STRING(m_config, "service.backend").c_str(), "localhost", "10000", m_config->getConfigFile().c_str()); +} + +NetworkPluginServer::~NetworkPluginServer() { + +} + +void NetworkPluginServer::handleNewClientConnection(boost::shared_ptr c) { + if (m_client) { + c->disconnect(); + } + m_client = c; + + c->onDisconnected.connect(boost::bind(&NetworkPluginServer::handleSessionFinished, this, c)); + c->onDataRead.connect(boost::bind(&NetworkPluginServer::handleDataRead, this, c, _1)); +} + +void NetworkPluginServer::handleSessionFinished(boost::shared_ptr c) { + if (c == m_client) { + m_client.reset(); + } +} + +void NetworkPluginServer::handleConnectedPayload(const std::string &data) { + pbnetwork::Connected payload; + if (payload.ParseFromString(data) == false) { + // TODO: ERROR + return; + } + std::cout << payload.name() << "\n"; +} + +void NetworkPluginServer::handleDisconnectedPayload(const std::string &data) { + pbnetwork::Disconnected payload; + if (payload.ParseFromString(data) == false) { + // TODO: ERROR + return; + } + + User *user = m_userManager->getUser(payload.user()); + if (!user) + return; + + user->handleDisconnected(payload.message()); +} + +void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) { + pbnetwork::Buddy payload; + if (payload.ParseFromString(data) == false) { + // TODO: ERROR + return; + } + + User *user = m_userManager->getUser(payload.username()); + if (!user) + return; + + LocalBuddy *buddy = (LocalBuddy *) user->getRosterManager()->getBuddy(payload.buddyname()); + if (buddy) { + handleBuddyPayload(buddy, payload); + buddy->buddyChanged(); + } + else { + buddy = new LocalBuddy(user->getRosterManager(), -1); + handleBuddyPayload(buddy, payload); + user->getRosterManager()->setBuddy(buddy); + } +} + +void NetworkPluginServer::handleDataRead(boost::shared_ptr c, const Swift::ByteArray &data) { + long expected_size = 0; + m_data += data.toString(); + std::cout << "received data; size = " << m_data.size() << "\n"; + while (m_data.size() != 0) { + if (m_data.size() >= 4) { + unsigned char * head = (unsigned char*) m_data.c_str(); + expected_size = (((((*head << 8) | *(head + 1)) << 8) | *(head + 2)) << 8) | *(head + 3); + //expected_size = m_data[0]; + std::cout << "expected_size=" << expected_size << "\n"; + if (m_data.size() - 4 < expected_size) + return; + } + else { + return; + } + + std::string msg = m_data.substr(4, expected_size); + m_data.erase(0, 4 + expected_size); + + pbnetwork::WrapperMessage wrapper; + if (wrapper.ParseFromString(msg) == false) { + // TODO: ERROR + return; + } + + switch(wrapper.type()) { + case pbnetwork::WrapperMessage_Type_TYPE_CONNECTED: + handleConnectedPayload(wrapper.payload()); + break; + case pbnetwork::WrapperMessage_Type_TYPE_DISCONNECTED: + handleDisconnectedPayload(wrapper.payload()); + break; + case pbnetwork::WrapperMessage_Type_TYPE_BUDDY_CHANGED: + handleBuddyChangedPayload(wrapper.payload()); + break; + default: + return; + } + } +} + +void NetworkPluginServer::send(boost::shared_ptr &c, const std::string &data) { + std::string header(" "); + for (int i = 0; i != 4; ++i) + header.at(i) = static_cast(data.size() >> (8 * (3 - i))); + + c->write(Swift::ByteArray(header + data)); +} + +void NetworkPluginServer::handleUserCreated(User *user) { +// UserInfo userInfo = user->getUserInfo(); + user->onReadyToConnect.connect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user)); +} + +void NetworkPluginServer::handleUserReadyToConnect(User *user) { + UserInfo userInfo = user->getUserInfo(); + + pbnetwork::Login login; + login.set_user(user->getJID().toBare()); + login.set_legacyname(userInfo.uin); + login.set_password(userInfo.password); + + std::string message; + login.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_LOGIN); + + send(m_client, message); +} + +void NetworkPluginServer::handleUserDestroyed(User *user) { + UserInfo userInfo = user->getUserInfo(); + + pbnetwork::Logout logout; + logout.set_user(user->getJID().toBare()); + logout.set_legacyname(userInfo.uin); + + std::string message; + logout.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_LOGOUT); + + send(m_client, message); +} + +}