Home | History | Annotate | Download | only in execserver
      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