/* * 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 Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this program. If not, see . */ #include "RequestManager.h" #include "RequestHandlers/DisconnectRequestHandler.h" #include namespace Mad { namespace Common { void RequestManager::RequestMap::unregisterConnection(Connection *connection) { std::map::iterator idMap = connectionMap.find(connection); if(idMap == connectionMap.end()) return; for(IdMap::iterator request = idMap->second.begin(); request != idMap->second.end(); ++request) handlerMap.erase(request->second.get()); connectionMap.erase(idMap); } bool RequestManager::RequestMap::addRequest(Connection *con, boost::uint16_t id, boost::shared_ptr request) { std::map::iterator idMap = connectionMap.find(con); if(idMap == connectionMap.end()) return false; if(!idMap->second.insert(std::make_pair(id, request)).second) return false; if(!handlerMap.insert(std::make_pair(request.get(), std::make_pair(con, id))).second) { idMap->second.erase(id); return false; } return true; } boost::shared_ptr RequestManager::RequestMap::findRequest(Connection *con, boost::uint16_t id) { std::map::iterator idMap = connectionMap.find(con); if(idMap == connectionMap.end()) return boost::shared_ptr(); IdMap::iterator it = idMap->second.find(id); if(it == idMap->second.end()) return boost::shared_ptr(); return it->second; } void RequestManager::RequestMap::deleteRequest(Connection *con, boost::uint16_t id) { std::map::iterator idMap = connectionMap.find(con); if(idMap == connectionMap.end()) return; IdMap::iterator it = idMap->second.find(id); if(it == idMap->second.end()) return; handlerMap.erase(it->second.get()); idMap->second.erase(it); } std::pair RequestManager::RequestMap::getRequestInfo(const RequestHandler *requestHandler) { HandlerMap::iterator it = handlerMap.find(requestHandler); if(it == handlerMap.end()) return std::pair(0, 0); else return it->second; } void RequestManager::receiveHandler(Connection *connection, boost::shared_ptr packet, boost::uint16_t requestId) { boost::upgrade_lock lock(mutex); boost::shared_ptr request = requestMap.findRequest(connection, requestId); if(request) { lock.unlock(); application->getThreadManager()->pushWork(boost::bind(&RequestHandler::handlePacket, request, packet)); return; } if(!requestMap.isConnectionRegistered(connection)) { // TODO: Error application->log(Core::Logger::LOG_ERROR, "Received a packet from an unregistered connection."); return; } std::map >::iterator rgh = requestHandlerGroups.find(packet->getType()); if(rgh != requestHandlerGroups.end()) { request = rgh->second->createRequestHandler(application, packet->getType()); if(request) { { boost::upgrade_to_unique_lock upgradeLock(lock); requestMap.addRequest(connection, requestId, request); request->connectSignalFinished(boost::bind(&RequestManager::handleRequestFinished, this, connection, requestId)); } lock.unlock(); application->getThreadManager()->pushWork(boost::bind(&RequestHandler::handlePacket, request, packet)); return; } } lock.unlock(); XmlData ret; ret.setType("Error"); ret.set("ErrorCode", Core::Exception::NOT_IMPLEMENTED); connection->sendPacket(ret, requestId); } bool RequestManager::sendRequest(Connection *connection, boost::shared_ptr request) { boost::unique_lock lock(mutex); if(!requestMap.isConnectionRegistered(connection)) { application->log(Core::Logger::LOG_CRITICAL, "Trying to send a request over an unregistered connecion."); return false; } boost::uint16_t requestId = _getUnusedRequestId(connection); if(request->isFinished || !requestMap.addRequest(connection, requestId, request)) { application->log(Core::Logger::LOG_CRITICAL, "Trying resend a request."); return false; } request->connectSignalFinished(boost::bind(&RequestManager::handleRequestFinished, this, connection, requestId)); lock.unlock(); application->getThreadManager()->pushWork(boost::bind(&Request::sendRequest, request)); return true; } boost::uint16_t RequestManager::_getUnusedRequestId(Connection *connection) { while(true) { boost::uint16_t requestId = _getRequestId(); if(!requestMap.findRequest(connection, requestId)) return requestId; } } void RequestManager::registerConnection(Connection *connection) { boost::lock_guard lock(mutex); requestMap.registerConnection(connection); connection->connectSignalReceive(boost::bind(&RequestManager::receiveHandler, this, connection, _1, _2)); } RequestManager::RequestManager(Application *application0, bool server) : application(application0), lastRequestId(server ? 0 : -1) { registerPacketType("Disconnect"); } } }