/* * RequestManager.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 "RequestManager.h" #include "RequestHandlers/DisconnectRequestHandler.h" #include "Logger.h" #include namespace Mad { namespace Common { RequestManager RequestManager::requestManager; bool RequestManager::RequestMap::addRequest(boost::uint16_t id, boost::shared_ptr info) { if(!insert(std::make_pair(id, info)).second) return false; info->signalFinished().connect(boost::bind(&RequestManager::RequestMap::deleteRequest, this, id)); return true; } boost::shared_ptr RequestManager::RequestMap::findRequest(boost::uint16_t id) { iterator it = find(id); if(it == end()) return boost::shared_ptr(); return it->second; } bool RequestManager::RequestMap::deleteRequest(boost::uint16_t id) { return erase(id); } void RequestManager::receiveHandler(Connection *connection, const XmlPacket &packet, boost::uint16_t requestId) { boost::upgrade_lock lock(mutex); std::map >::iterator it = requestMaps.find(connection); if(it == requestMaps.end()) { // TODO: Error Logger::log(Logger::ERROR, "Received a packet from an unregistered connection."); return; } boost::shared_ptr requestMap = it->second; boost::shared_ptr request = requestMap->findRequest(requestId); if(request) { lock.unlock(); request->handlePacket(packet); return; } std::map >::iterator factoryIt = requestHandlerFactories.find(packet.getType()); if(factoryIt != requestHandlerFactories.end()) { { boost::upgrade_to_unique_lock upgradeLock(lock); request = factoryIt->second->createRequestHandler(connection, requestId); requestMap->addRequest(requestId, request); } lock.unlock(); request->handlePacket(packet); return; } lock.unlock(); Logger::logf(Logger::ERROR, "Received an unexpected packet with type '%s'.", packet.getType().c_str()); XmlPacket ret; ret.setType("Error"); ret.add("ErrorCode", Net::Exception::UNEXPECTED_PACKET); connection->sendPacket(ret, requestId); } boost::shared_ptr RequestManager::_getUnusedRequestId(Connection *connection, boost::uint16_t *requestId) { std::map >::iterator it = requestMaps.find(connection); if(it == requestMaps.end()) { Logger::log(Logger::CRITICAL, "Trying to send a request over an unregistered connecion."); return boost::shared_ptr(); } boost::shared_ptr requestMap = it->second; do { *requestId = _getRequestId(); } while(requestMap->findRequest(*requestId)); return requestMap; } void RequestManager::registerConnection(Connection *connection) { boost::lock_guard lock(mutex); requestMaps.insert(std::make_pair(connection, new RequestMap())); connection->signalReceive().connect(boost::bind(&RequestManager::receiveHandler, this, connection, _1, _2)); } RequestManager::RequestManager() : server(false), lastRequestId(-1) { registerPacketType("Disconnect"); } } }