/** * 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/admininterface.h" #include "transport/user.h" #include "transport/transport.h" #include "transport/storagebackend.h" #include "transport/conversationmanager.h" #include "transport/rostermanager.h" #include "transport/usermanager.h" #include "transport/networkpluginserver.h" #include "storageresponder.h" #include "log4cxx/logger.h" #include "transport/memoryusage.h" #include using namespace log4cxx; namespace Transport { static LoggerPtr logger = Logger::getLogger("AdminInterface"); static std::string getArg(const std::string &body) { std::string ret; if (body.find(" ") == std::string::npos) return ret; return body.substr(body.find(" ") + 1); } AdminInterface::AdminInterface(Component *component, UserManager *userManager, NetworkPluginServer *server, StorageBackend *storageBackend) { m_component = component; m_storageBackend = storageBackend; m_userManager = userManager; m_server = server; m_component->getStanzaChannel()->onMessageReceived.connect(bind(&AdminInterface::handleMessageReceived, this, _1)); } AdminInterface::~AdminInterface() { } void AdminInterface::handleMessageReceived(Swift::Message::ref message) { if (!message->getTo().getNode().empty()) return; if (message->getFrom().getNode() != CONFIG_STRING(m_component->getConfig(), "service.admin_username")) { LOG4CXX_WARN(logger, "Message not from admin user, but from " << message->getFrom().getNode()); return; } LOG4CXX_INFO(logger, "Message from admin received"); message->setTo(message->getFrom()); message->setFrom(m_component->getJID()); if (message->getBody() == "status") { int users = m_userManager->getUserCount(); int backends = m_server->getBackendCount(); message->setBody("Running (" + boost::lexical_cast(users) + " users connected using " + boost::lexical_cast(backends) + " backends)"); } else if (message->getBody() == "online_users") { std::string lst; const std::map &users = m_userManager->getUsers(); if (users.size() == 0) lst = "0"; for (std::map::const_iterator it = users.begin(); it != users.end(); it ++) { lst += (*it).first + "\n"; } message->setBody(lst); } else if (message->getBody() == "online_users_count") { int users = m_userManager->getUserCount(); message->setBody(boost::lexical_cast(users)); } else if (message->getBody() == "reload") { bool done = m_component->getConfig()->reload(); if (done) { message->setBody("Config reloaded"); } else { message->setBody("Error during config reload"); } } else if (message->getBody() == "online_users_per_backend") { std::string lst; int id = 1; const std::list &backends = m_server->getBackends(); for (std::list ::const_iterator b = backends.begin(); b != backends.end(); b++) { NetworkPluginServer::Backend *backend = *b; lst += "Backend " + boost::lexical_cast(id); lst += backend->acceptUsers ? "" : " - not-accepting"; lst += backend->longRun ? " - long-running" : ""; lst += ":\n"; if (backend->users.size() == 0) { lst += " waiting for users\n"; } else { time_t now = time(NULL); for (std::list::const_iterator u = backend->users.begin(); u != backend->users.end(); u++) { User *user = *u; lst += " " + user->getJID().toBare().toString(); lst += " - non-active for " + boost::lexical_cast(now - user->getLastActivity()) + " seconds"; lst += "\n"; } } id++; } message->setBody(lst); } else if (message->getBody().find("has_online_user") == 0) { User *user = m_userManager->getUser(getArg(message->getBody())); std::cout << getArg(message->getBody()) << "\n"; message->setBody(boost::lexical_cast(user != NULL)); } else if (message->getBody() == "backends_count") { int backends = m_server->getBackendCount(); message->setBody(boost::lexical_cast(backends)); } else if (message->getBody() == "res_memory") { double shared = 0; double rss = 0; #ifndef WIN32 process_mem_usage(shared, rss); #endif const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { rss += backend->res; } message->setBody(boost::lexical_cast(rss)); } else if (message->getBody() == "shr_memory") { double shared = 0; double rss = 0; #ifndef WIN32 process_mem_usage(shared, rss); #endif const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { shared += backend->shared; } message->setBody(boost::lexical_cast(shared)); } else if (message->getBody() == "used_memory") { double shared = 0; double rss = 0; #ifndef WIN32 process_mem_usage(shared, rss); #endif rss -= shared; const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { rss += backend->res - backend->shared; } message->setBody(boost::lexical_cast(rss)); } else if (message->getBody() == "average_memory_per_user") { if (m_userManager->getUserCount() == 0) { message->setBody(boost::lexical_cast(0)); } else { unsigned long per_user = 0; const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { per_user += (backend->res - backend->init_res); } message->setBody(boost::lexical_cast(per_user / m_userManager->getUserCount())); } } else if (message->getBody() == "res_memory_per_backend") { std::string lst; int id = 1; const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { lst += "Backend " + boost::lexical_cast(id) + ": " + boost::lexical_cast(backend->res) + "\n"; id++; } message->setBody(lst); } else if (message->getBody() == "shr_memory_per_backend") { std::string lst; int id = 1; const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { lst += "Backend " + boost::lexical_cast(id) + ": " + boost::lexical_cast(backend->shared) + "\n"; id++; } message->setBody(lst); } else if (message->getBody() == "used_memory_per_backend") { std::string lst; int id = 1; const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { lst += "Backend " + boost::lexical_cast(id) + ": " + boost::lexical_cast(backend->res - backend->shared) + "\n"; id++; } message->setBody(lst); } else if (message->getBody() == "average_memory_per_user_per_backend") { std::string lst; int id = 1; const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { if (backend->users.size() == 0) { lst += "Backend " + boost::lexical_cast(id) + ": 0\n"; } else { lst += "Backend " + boost::lexical_cast(id) + ": " + boost::lexical_cast((backend->res - backend->init_res) / backend->users.size()) + "\n"; } id++; } message->setBody(lst); } else if (message->getBody() == "collect_backend") { m_server->collectBackend(); } else if (message->getBody().find("help") == 0) { std::string help; help += "General:\n"; help += " status - shows instance status\n"; help += " reload - Reloads config file\n"; help += "Users:\n"; help += " online_users - returns list of all online users\n"; help += " online_users_count - number of online users\n"; help += " online_users_per_backend - shows online users per backends\n"; help += " has_online_user - returns 1 if user is online\n"; help += "Backends:\n"; help += " backends_count - number of active backends\n"; help += "Memory:\n"; help += " res_memory - Total RESident memory spectrum2 and its backends use in KB\n"; help += " shr_memory - Total SHaRed memory spectrum2 backends share together in KB\n"; help += " used_memory - (res_memory - shr_memory)\n"; help += " average_memory_per_user - (memory_used_without_any_user - res_memory)\n"; help += " res_memory_per_backend - RESident memory used by backends in KB\n"; help += " shr_memory_per_backend - SHaRed memory used by backends in KB\n"; help += " used_memory_per_backend - (res_memory - shr_memory) per backend\n"; help += " average_memory_per_user_per_backend - (memory_used_without_any_user - res_memory) per backend\n"; message->setBody(help); } else { message->setBody("Unknown command. Try \"help\""); } m_component->getStanzaChannel()->sendMessage(message); } }