diff options
Diffstat (limited to 'src/Server/ConnectionManager.cpp')
-rw-r--r-- | src/Server/ConnectionManager.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/src/Server/ConnectionManager.cpp b/src/Server/ConnectionManager.cpp new file mode 100644 index 0000000..279304c --- /dev/null +++ b/src/Server/ConnectionManager.cpp @@ -0,0 +1,310 @@ +/* + * ConnectionManager.cpp + * + * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "ConnectionManager.h" +#include <Common/ConfigEntry.h> +#include <Common/ConfigManager.h> +#include <Common/Logger.h> +#include <Common/RequestHandlers/FSInfoRequestHandler.h> +#include <Common/RequestHandlers/StatusRequestHandler.h> +#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 <Net/FdManager.h> +#include <Net/ServerConnection.h> +#include <Net/Packet.h> +#include <Net/Listener.h> + +#include <unistd.h> +#include <algorithm> + +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, ConnectionType type0) +: connection(connection0), type(type0), hostInfo(0) { + connection->signalReceive().connect(sigc::mem_fun(this, &Connection::receive)); +} + +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::list<Connection*>::iterator con = connections.begin(); con != connections.end(); ++con) { + if((*con)->getConnectionType() == Connection::CLIENT) + Common::RequestManager::get()->sendRequest<Requests::DaemonStateUpdateRequest>(*con, Common::Request::slot_type(), 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(Common::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 { + listeners.push_back(new Net::Listener(x509CertFile, x509KeyFile)); + } + catch(Common::Exception &e) { + // TODO Log error + } + } + else { + for(std::vector<Net::IPAddress>::const_iterator address = listenerAddresses.begin(); address != listenerAddresses.end(); ++address) { + try { + listeners.push_back(new Net::Listener(x509CertFile, x509KeyFile, *address)); + } + catch(Common::Exception &e) { + // TODO Log error + } + } + } +} + +void ConnectionManager::doInit() { + Common::RequestManager::get()->setServer(true); + + Net::Connection::init(); + + Common::RequestManager::get()->registerPacketType<RequestHandlers::GSSAPIAuthRequestHandler>("AuthGSSAPI"); + Common::RequestManager::get()->registerPacketType<RequestHandlers::DaemonCommandRequestHandler>("DaemonCommand"); + Common::RequestManager::get()->registerPacketType<RequestHandlers::DaemonFSInfoRequestHandler>("DaemonFSInfo"); + Common::RequestManager::get()->registerPacketType<Common::RequestHandlers::FSInfoRequestHandler>("FSInfo"); + Common::RequestManager::get()->registerPacketType<Common::RequestHandlers::StatusRequestHandler>("GetStatus"); + Common::RequestManager::get()->registerPacketType<RequestHandlers::DaemonStatusRequestHandler>("GetDaemonStatus"); + Common::RequestManager::get()->registerPacketType<RequestHandlers::IdentifyRequestHandler>("Identify"); + Common::RequestManager::get()->registerPacketType<RequestHandlers::DaemonListRequestHandler>("ListHosts"); + Common::RequestManager::get()->registerPacketType<RequestHandlers::UserInfoRequestHandler>("GetUserInfo"); + Common::RequestManager::get()->registerPacketType<RequestHandlers::UserListRequestHandler>("ListUsers"); + Common::RequestManager::get()->registerPacketType<RequestHandlers::LogRequestHandler>("Log"); +} + +void ConnectionManager::doDeinit() { + for(std::list<Connection*>::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"); + + Net::Connection::deinit(); +} + +void ConnectionManager::run() { + // TODO Logging + + Net::FdManager::get()->run(); + + for(std::list<Connection*>::iterator con = connections.begin(); con != connections.end();) { + if(!(*con)->isConnected()) { + if((*con)->isIdentified()) + updateState((*con)->getHostInfo(), Common::HostInfo::INACTIVE); + + Common::RequestManager::get()->unregisterConnection(*con); + delete *con; + connections.erase(con++); + } + else + ++con; + } + + for(std::list<Net::Listener*>::iterator listener = listeners.begin(); listener != listeners.end(); ++listener) { + Net::ServerConnection *con; + + while((con = (*listener)->getConnection()) != 0) { + Connection *connection = new Connection(con, + con->isDaemonConnection() ? Connection::DAEMON : Connection::CLIENT); + connections.push_back(connection); + Common::RequestManager::get()->registerConnection(connection); + } + } +} + +Common::Connection* ConnectionManager::getDaemonConnection(const std::string &name) const throw (Common::Exception&) { + const Common::HostInfo *hostInfo; + + try { + hostInfo = &daemonInfo.at(name); + } + catch(std::out_of_range&) { + throw Common::Exception(Common::Exception::UNKNOWN_DAEMON); + } + + if(hostInfo->getState() != Common::HostInfo::INACTIVE) { + for(std::list<Connection*>::const_iterator it = connections.begin(); it != connections.end(); ++it) { + if((*it)->getHostInfo() == hostInfo) { + return *it; + } + } + } + + throw(Common::Exception::NOT_AVAILABLE); +} + +std::string ConnectionManager::getDaemonName(const Common::Connection *con) const throw (Common::Exception&) { + const Connection *connection = dynamic_cast<const Connection*>(con); + + if(connection) { + if(connection->isIdentified()) { + return connection->getHostInfo()->getName(); + } + } + + throw Common::Exception(Common::Exception::UNKNOWN_DAEMON); +} + +void ConnectionManager::identifyDaemonConnection(Common::Connection *con, const std::string &name) throw (Common::Exception&) { + // TODO Logging + + Connection *connection = dynamic_cast<Connection*>(con); + + if(!connection || (connection->getConnectionType() != Connection::DAEMON)) + throw Common::Exception(Common::Exception::INVALID_ACTION); + + if(connection->isIdentified()) + throw Common::Exception(Common::Exception::ALREADY_IDENTIFIED); + + if(daemonInfo.count(name) == 0) + throw Common::Exception(Common::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(Common::Exception&) {} + } + + connection->identify(hostInfo); + updateState(hostInfo, Common::HostInfo::RUNNING); + + Common::Logger::logf("Identified as '%s'.", name.c_str()); +} + +std::vector<Common::HostInfo> ConnectionManager::getDaemonList() const { + std::vector<Common::HostInfo> ret; + + for(std::map<std::string,Common::HostInfo>::const_iterator daemon = daemonInfo.begin(); daemon != daemonInfo.end(); ++daemon) { + ret.push_back(daemon->second); + } + + return ret; +} + +} +} |