/* * ConnectionManager.cpp * * Copyright (C) 2008 Matthias Schiffer * * 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 3 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, see . */ #include "ConnectionManager.h" #include #include #include #include #include #include "Requests/DaemonStateUpdateRequest.h" #include "RequestHandlers/DaemonCommandRequestHandler.h" #include "RequestHandlers/DaemonFSInfoRequestHandler.h" #include "RequestHandlers/DaemonListRequestHandler.h" #include "RequestHandlers/DaemonStatusRequestHandler.h" #include "RequestHandlers/GSSAPIAuthRequestHandler.h" #include "RequestHandlers/IdentifyRequestHandler.h" #include "RequestHandlers/LogRequestHandler.h" #include "RequestHandlers/UserInfoRequestHandler.h" #include "RequestHandlers/UserListRequestHandler.h" #include #include #include #include #include #include namespace Mad { namespace Server { ConnectionManager ConnectionManager::connectionManager; bool ConnectionManager::Connection::send(const Net::Packet &packet) { return connection->send(packet); } ConnectionManager::Connection::Connection(Net::ServerConnection *connection0) : connection(connection0), type(connection0->isDaemonConnection() ? DAEMON : CLIENT), hostInfo(0) { connection->signalReceive().connect(boost::bind(&Connection::receive, this, _1)); } ConnectionManager::Connection::~Connection() { delete connection; } bool ConnectionManager::Connection::isConnected() const { return connection->isConnected(); } bool ConnectionManager::Connection::disconnect() { connection->disconnect(); return true; } void* ConnectionManager::Connection::getCertificate(size_t *size) const { const gnutls_datum_t *cert = connection->getCertificate(); *size = cert->size; return cert->data; } void* ConnectionManager::Connection::getPeerCertificate(size_t *size) const { const gnutls_datum_t *cert = connection->getPeerCertificate(); *size = cert->size; return cert->data; } void ConnectionManager::updateState(Common::HostInfo *hostInfo, Common::HostInfo::State state) { hostInfo->setState(state); for(std::set::iterator con = connections.begin(); con != connections.end(); ++con) { if((*con)->getConnectionType() == Connection::CLIENT) Common::RequestManager::get()->sendRequest(*con, boost::bind(&ConnectionManager::updateStateFinished, this, _1), hostInfo->getName(), state); } } bool ConnectionManager::handleConfigEntry(const Common::ConfigEntry &entry, bool handled) { if(handled) return false; if(entry[0].getKey().matches("Listen") && entry[1].empty()) { try { listenerAddresses.push_back(Net::IPAddress(entry[0][0])); } catch(Net::Exception &e) { // TODO Log error } return true; } else if(entry[0].getKey().matches("X509TrustFile") && entry[1].empty()) { x509TrustFile = entry[0][0]; return true; } else if(entry[0].getKey().matches("X509CrlFile") && entry[1].empty()) { x509CrlFile = entry[0][0]; return true; } else if(entry[0].getKey().matches("X509CertFile") && entry[1].empty()) { x509CertFile = entry[0][0]; return true; } else if(entry[0].getKey().matches("X509KeyFile") && entry[1].empty()) { x509KeyFile = entry[0][0]; return true; } else if(entry[0].getKey().matches("Daemon")) { if(entry[0].getSize() == 1) { if(entry[1].empty()) { daemonInfo.insert(std::make_pair(entry[0][0], Common::HostInfo(entry[0][0]))); return true; } else if(entry[1].getKey().matches("IpAddress") && entry[2].empty()) { daemonInfo[entry[0][0]].setIP(entry[1][0]); return true; } } } return false; } void ConnectionManager::configFinished() { if(listenerAddresses.empty()) { try { Net::Listener *listener = new Net::Listener(x509CertFile, x509KeyFile); listener->signalNewConnection().connect(boost::bind(&ConnectionManager::newConnectionHandler, this, _1)); listeners.push_back(listener); } catch(Net::Exception &e) { // TODO Log error } } else { for(std::vector::const_iterator address = listenerAddresses.begin(); address != listenerAddresses.end(); ++address) { try { Net::Listener *listener = new Net::Listener(x509CertFile, x509KeyFile, *address); listener->signalNewConnection().connect(boost::bind(&ConnectionManager::newConnectionHandler, this, _1)); listeners.push_back(listener); } catch(Net::Exception &e) { // TODO Log error } } } } void ConnectionManager::newConnectionHandler(Net::ServerConnection *con) { Connection *connection = new Connection(con); con->signalDisconnected().connect(boost::bind(&ConnectionManager::disconnectHandler, this, connection)); connections.insert(connection); Common::RequestManager::get()->registerConnection(connection); } void ConnectionManager::disconnectHandler(Connection *con) { if(con->isIdentified()) updateState(con->getHostInfo(), Common::HostInfo::INACTIVE); connections.erase(con); Common::RequestManager::get()->unregisterConnection(con); delete con; } void ConnectionManager::doInit() { Common::RequestManager::get()->setServer(true); Common::RequestManager::get()->registerPacketType("AuthGSSAPI"); Common::RequestManager::get()->registerPacketType("DaemonCommand"); Common::RequestManager::get()->registerPacketType("DaemonFSInfo"); Common::RequestManager::get()->registerPacketType("FSInfo"); Common::RequestManager::get()->registerPacketType("GetStatus"); Common::RequestManager::get()->registerPacketType("GetDaemonStatus"); Common::RequestManager::get()->registerPacketType("Identify"); Common::RequestManager::get()->registerPacketType("ListHosts"); Common::RequestManager::get()->registerPacketType("GetUserInfo"); Common::RequestManager::get()->registerPacketType("ListUsers"); Common::RequestManager::get()->registerPacketType("Log"); } void ConnectionManager::doDeinit() { for(std::set::iterator con = connections.begin(); con != connections.end(); ++con) delete *con; Common::RequestManager::get()->unregisterPacketType("AuthGSSAPI"); Common::RequestManager::get()->unregisterPacketType("DaemonCommand"); Common::RequestManager::get()->unregisterPacketType("DaemonFSInfo"); Common::RequestManager::get()->unregisterPacketType("FSInfo"); Common::RequestManager::get()->unregisterPacketType("GetStatus"); Common::RequestManager::get()->unregisterPacketType("GetDaemonStatus"); Common::RequestManager::get()->unregisterPacketType("Identify"); Common::RequestManager::get()->unregisterPacketType("ListHosts"); Common::RequestManager::get()->unregisterPacketType("GetUserInfo"); Common::RequestManager::get()->unregisterPacketType("ListUsers"); Common::RequestManager::get()->unregisterPacketType("Log"); } Common::Connection* ConnectionManager::getDaemonConnection(const std::string &name) const throw (Net::Exception&) { const Common::HostInfo *hostInfo; try { hostInfo = &daemonInfo.at(name); } catch(std::out_of_range&) { throw Net::Exception(Net::Exception::UNKNOWN_DAEMON); } if(hostInfo->getState() != Common::HostInfo::INACTIVE) { for(std::set::const_iterator it = connections.begin(); it != connections.end(); ++it) { if((*it)->getHostInfo() == hostInfo) { return *it; } } } throw(Net::Exception::NOT_AVAILABLE); } std::string ConnectionManager::getDaemonName(const Common::Connection *con) const throw (Net::Exception&) { const Connection *connection = dynamic_cast(con); if(connection) { if(connection->isIdentified()) { return connection->getHostInfo()->getName(); } } throw Net::Exception(Net::Exception::UNKNOWN_DAEMON); } void ConnectionManager::identifyDaemonConnection(Common::Connection *con, const std::string &name) throw (Net::Exception&) { // TODO Logging Connection *connection = dynamic_cast(con); if(!connection || (connection->getConnectionType() != Connection::DAEMON)) throw Net::Exception(Net::Exception::INVALID_ACTION); if(connection->isIdentified()) throw Net::Exception(Net::Exception::ALREADY_IDENTIFIED); if(daemonInfo.count(name) == 0) throw Net::Exception(Net::Exception::UNKNOWN_DAEMON); Common::HostInfo *hostInfo = &daemonInfo[name]; if(hostInfo->getState() != Common::HostInfo::INACTIVE) { try { getDaemonConnection(name)->disconnect(); Common::Logger::log(Common::Logger::WARNING, "Disconnecting old connection."); } catch(Net::Exception&) {} } connection->identify(hostInfo); updateState(hostInfo, Common::HostInfo::RUNNING); Common::Logger::logf("Identified as '%s'.", name.c_str()); } std::vector ConnectionManager::getDaemonList() const { std::vector ret; for(std::map::const_iterator daemon = daemonInfo.begin(); daemon != daemonInfo.end(); ++daemon) { ret.push_back(daemon->second); } return ret; } } }