// Copyright (c) 2013 by István Váradi // This file is part of XPLRA, a remote-access plugin for X-Plane // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // The views and conclusions contained in the software and documentation are those // of the authors and should not be interpreted as representing official policies, // either expressed or implied, of the FreeBSD Project. //------------------------------------------------------------------------------ #include "ServerThread.h" #include "ListenThread.h" #include "RequestQueue.h" #include "Protocol.h" #include "GetDataRefTask.h" #include "SetDataRefTask.h" #include "TaskRequest.h" #include "GetMultiDataRefRequest.h" #include "SetMultiDataRefRequest.h" #include #include //------------------------------------------------------------------------------ using xplra::ServerThread; using hu::varadiistvan::scpl::io::LocalAcceptor; using hu::varadiistvan::scpl::Mutex; using hu::varadiistvan::xplcommon::Util; using std::string; //------------------------------------------------------------------------------ Mutex ServerThread::instancesMutex; ServerThread::instances_t ServerThread::instances; //------------------------------------------------------------------------------ void ServerThread::quitAll() { instancesMutex.lock(); for(instances_t::iterator i = instances.begin(); i!=instances.end(); ++i) { (*i)->quit(); } instancesMutex.unlock(); } //------------------------------------------------------------------------------ ServerThread::ServerThread(ListenThread& listenThread, RequestQueue& requestQueue, LocalAcceptor& acceptor) : Thread(true), listenThread(listenThread), requestQueue(requestQueue), bufferedStream(acceptor.getSocket(&waiter)), stream(*bufferedStream), nextGetMultiRequestID(1), nextSetMultiRequestID(1) { instancesMutex.lock(); instances.insert(this); instancesMutex.unlock(); } //------------------------------------------------------------------------------ ServerThread::~ServerThread() { delete bufferedStream; for(getMultiRequests_t::iterator i = getMultiRequests.begin(); i!=getMultiRequests.end(); ++i) { delete i->second; } for(setMultiRequests_t::iterator i = setMultiRequests.begin(); i!=setMultiRequests.end(); ++i) { delete i->second; } instancesMutex.lock(); instances.erase(this); instancesMutex.unlock(); } //------------------------------------------------------------------------------ void ServerThread::quit() { stream.interrupt(); } //------------------------------------------------------------------------------ void ServerThread::run() { Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run\n", this); while(stream) { uint8_t command = stream.readU8(); if (!stream) continue; // Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run: command=0x%02x\n", // this, command); if (command==Protocol::COMMAND_GET_SINGLE) { if (!handleGetSingle()) break; } else if (command==Protocol::COMMAND_SET_SINGLE) { if (!handleSetSingle()) break; } else if (command==Protocol::COMMAND_GET_MULTI) { if (!handleGetMulti()) break; } else if (command==Protocol::COMMAND_SET_MULTI) { if (!handleSetMulti()) break; } else if (command==Protocol::COMMAND_REGISTER_GET_MULTI) { if (!handleRegisterGetMulti()) break; } else if (command==Protocol::COMMAND_UNREGISTER_GET_MULTI) { if (!handleUnregisterGetMulti()) break; } else if (command==Protocol::COMMAND_EXECUTE_GET_MULTI) { if (!handleExecuteGetMulti()) break; } else if (command==Protocol::COMMAND_REGISTER_SET_MULTI) { if (!handleRegisterSetMulti()) break; } else if (command==Protocol::COMMAND_UNREGISTER_SET_MULTI) { if (!handleUnregisterSetMulti()) break; } else if (command==Protocol::COMMAND_EXECUTE_SET_MULTI) { if (!handleExecuteSetMulti()) break; } else if (command==Protocol::COMMAND_GET_VERSIONS) { if (!handleGetVersions()) break; } else { stream.writeU8(Protocol::RESULT_INVALID_COMMAND); } stream.flush(); } Util::debug("hu.varadiistvan.xplra.ServerThread[%p]::run: quitting\n", this); } //------------------------------------------------------------------------------ bool ServerThread::handleGetSingle() { uint8_t result = Protocol::RESULT_OK; GetDataRefTask* task = GetDataRefTask::create(result, stream); if (!stream) { return false; } else if (task==0) { stream.writeU8(result); return true; } TaskRequest request(task); if (!requestQueue.execute(&request)) return false; if (task->isValid()) { stream.writeU8(Protocol::RESULT_OK); task->writeValue(stream); } else { stream.writeU8(Protocol::RESULT_UNKNOWN_DATAREF); } return true; } //------------------------------------------------------------------------------ bool ServerThread::handleSetSingle() { uint8_t result = Protocol::RESULT_OK; SetDataRefTask* task = SetDataRefTask::create(result, stream); if (!stream) { return false; } else if (task==0) { stream.writeU8(result); return true; } task->readValue(stream); if (!stream) { delete task; return false; } TaskRequest request(task); if (!requestQueue.execute(&request)) return false; stream.writeU8(task->isValid() ? Protocol::RESULT_OK : Protocol::RESULT_UNKNOWN_DATAREF); return true; } //------------------------------------------------------------------------------ bool ServerThread::handleGetMulti() { uint8_t result = Protocol::RESULT_OK; GetMultiDataRefRequest* request = new GetMultiDataRefRequest(result, stream); if (result!=Protocol::RESULT_OK || !stream) { delete request; stream.writeU8(result); return stream; } bool isOK = requestQueue.execute(request); if (isOK) { request->writeResult(stream); } delete request; return isOK; } //------------------------------------------------------------------------------ bool ServerThread::handleSetMulti() { uint8_t result = Protocol::RESULT_OK; SetMultiDataRefRequest* request = new SetMultiDataRefRequest(result, stream, true); if (result!=Protocol::RESULT_OK || !stream) { delete request; stream.writeU8(result); return stream; } bool isOK = requestQueue.execute(request); if (isOK) { request->writeResult(stream); } delete request; return isOK; } //------------------------------------------------------------------------------ bool ServerThread::handleRegisterGetMulti() { uint8_t result = Protocol::RESULT_OK; GetMultiDataRefRequest* request = new GetMultiDataRefRequest(result, stream); if (result!=Protocol::RESULT_OK || !stream) { delete request; stream.writeU8(result); return stream; } size_t id = nextGetMultiRequestID++; getMultiRequests[id] = request; stream.writeU8(Protocol::RESULT_OK); stream.writeU32(id); return true; } //------------------------------------------------------------------------------ bool ServerThread::handleUnregisterGetMulti() { uint32_t id = stream.readU32(); if (!stream) return false; getMultiRequests_t::iterator i = getMultiRequests.find(id); if (i==getMultiRequests.end()) { stream.writeU8(Protocol::RESULT_INVALID_ID); } else { GetMultiDataRefRequest* request = i->second; getMultiRequests.erase(i); delete request; stream.writeU8(Protocol::RESULT_OK); } return true; } //------------------------------------------------------------------------------ bool ServerThread::handleExecuteGetMulti() { uint32_t id = stream.readU32(); if (!stream) return false; getMultiRequests_t::iterator i = getMultiRequests.find(id); if (i==getMultiRequests.end()) { stream.writeU8(Protocol::RESULT_INVALID_ID); } else { GetMultiDataRefRequest* request = i->second; if (!requestQueue.execute(request)) return false; request->writeResult(stream); } return true; } //------------------------------------------------------------------------------ bool ServerThread::handleRegisterSetMulti() { uint8_t result = Protocol::RESULT_OK; SetMultiDataRefRequest* request = new SetMultiDataRefRequest(result, stream, false); if (result!=Protocol::RESULT_OK || !stream) { delete request; stream.writeU8(result); return stream; } size_t id = nextSetMultiRequestID++; setMultiRequests[id] = request; stream.writeU8(Protocol::RESULT_OK); stream.writeU32(id); return true; } //------------------------------------------------------------------------------ bool ServerThread::handleUnregisterSetMulti() { uint32_t id = stream.readU32(); if (!stream) return false; setMultiRequests_t::iterator i = setMultiRequests.find(id); if (i==setMultiRequests.end()) { stream.writeU8(Protocol::RESULT_INVALID_ID); } else { SetMultiDataRefRequest* request = i->second; setMultiRequests.erase(i); delete request; stream.writeU8(Protocol::RESULT_OK); } return true; } //------------------------------------------------------------------------------ bool ServerThread::handleExecuteSetMulti() { uint32_t id = stream.readU32(); if (!stream) return false; setMultiRequests_t::iterator i = setMultiRequests.find(id); if (i==setMultiRequests.end()) { stream.writeU8(Protocol::RESULT_INVALID_ID); } else { SetMultiDataRefRequest* request = i->second; request->readValues(stream); if (!stream || !requestQueue.execute(request)) return false; request->writeResult(stream); } return true; } //------------------------------------------------------------------------------ bool ServerThread::handleGetVersions() { int xplaneVersion = 0; int xplmVersion = 0; listenThread.getVersions(xplaneVersion, xplmVersion); stream.writeU8(Protocol::RESULT_OK); stream.writeS32(xplaneVersion); stream.writeS32(xplmVersion); stream.writeS32(Protocol::version); return true; } //------------------------------------------------------------------------------ // Local Variables: // mode: C++ // c-basic-offset: 4 // indent-tabs-mode: nil // End: