1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program Execution Server 3 * --------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief TCP Server. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "xsTcpServer.hpp" 25 26 #include <algorithm> 27 #include <iterator> 28 #include <cstdio> 29 30 namespace xs 31 { 32 33 TcpServer::TcpServer (deSocketFamily family, int port) 34 : m_socket() 35 { 36 de::SocketAddress address; 37 address.setFamily(family); 38 address.setPort(port); 39 address.setType(DE_SOCKETTYPE_STREAM); 40 address.setProtocol(DE_SOCKETPROTOCOL_TCP); 41 42 m_socket.listen(address); 43 m_socket.setFlags(DE_SOCKET_CLOSE_ON_EXEC); 44 } 45 46 void TcpServer::runServer (void) 47 { 48 de::Socket* clientSocket = DE_NULL; 49 de::SocketAddress clientAddr; 50 51 while ((clientSocket = m_socket.accept(clientAddr)) != DE_NULL) 52 { 53 ConnectionHandler* handler = DE_NULL; 54 55 try 56 { 57 handler = createHandler(clientSocket, clientAddr); 58 } 59 catch (...) 60 { 61 delete clientSocket; 62 throw; 63 } 64 65 try 66 { 67 addLiveConnection(handler); 68 } 69 catch (...) 70 { 71 delete handler; 72 throw; 73 } 74 75 // Start handler. 76 handler->start(); 77 78 // Perform connection list cleanup. 79 deleteDoneConnections(); 80 } 81 82 // One more cleanup pass. 83 deleteDoneConnections(); 84 } 85 86 void TcpServer::connectionDone (ConnectionHandler* handler) 87 { 88 de::ScopedLock lock(m_connectionListLock); 89 90 std::vector<ConnectionHandler*>::iterator liveListPos = std::find(m_liveConnections.begin(), m_liveConnections.end(), handler); 91 DE_ASSERT(liveListPos != m_liveConnections.end()); 92 93 m_doneConnections.reserve(m_doneConnections.size()+1); 94 m_liveConnections.erase(liveListPos); 95 m_doneConnections.push_back(handler); 96 } 97 98 void TcpServer::addLiveConnection (ConnectionHandler* handler) 99 { 100 de::ScopedLock lock(m_connectionListLock); 101 m_liveConnections.push_back(handler); 102 } 103 104 void TcpServer::deleteDoneConnections (void) 105 { 106 de::ScopedLock lock(m_connectionListLock); 107 108 for (std::vector<ConnectionHandler*>::iterator i = m_doneConnections.begin(); i != m_doneConnections.end(); i++) 109 delete *i; 110 111 m_doneConnections.clear(); 112 } 113 114 void TcpServer::stopServer (void) 115 { 116 // Close socket. This should get accept() to return null. 117 m_socket.close(); 118 } 119 120 TcpServer::~TcpServer (void) 121 { 122 try 123 { 124 std::vector<ConnectionHandler*> allConnections; 125 126 if (m_connectionListLock.tryLock()) 127 { 128 // \note [pyry] It is possible that cleanup actually fails. 129 try 130 { 131 std::copy(m_liveConnections.begin(), m_liveConnections.end(), std::inserter(allConnections, allConnections.end())); 132 std::copy(m_doneConnections.begin(), m_doneConnections.end(), std::inserter(allConnections, allConnections.end())); 133 } 134 catch (...) 135 { 136 } 137 m_connectionListLock.unlock(); 138 } 139 140 for (std::vector<ConnectionHandler*>::const_iterator i = allConnections.begin(); i != allConnections.end(); i++) 141 delete *i; 142 143 if (m_socket.getState() != DE_SOCKETSTATE_CLOSED) 144 m_socket.close(); 145 } 146 catch (...) 147 { 148 // Nada, we're at destructor. 149 } 150 } 151 152 ConnectionHandler::~ConnectionHandler (void) 153 { 154 delete m_socket; 155 } 156 157 void ConnectionHandler::run (void) 158 { 159 try 160 { 161 handle(); 162 } 163 catch (const std::exception& e) 164 { 165 printf("ConnectionHandler::run(): %s\n", e.what()); 166 } 167 168 // Notify server that this connection is done. 169 m_server->connectionDone(this); 170 } 171 172 } // xs 173