xsTcpServer.cpp revision 3c827367444ee418f129b2c238299f49d3264554
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
30namespace xs
31{
32
33TcpServer::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
46void 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
86void 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
98void TcpServer::addLiveConnection (ConnectionHandler* handler)
99{
100	de::ScopedLock lock(m_connectionListLock);
101	m_liveConnections.push_back(handler);
102}
103
104void 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
114void TcpServer::stopServer (void)
115{
116	// Close socket. This should get accept() to return null.
117	m_socket.close();
118}
119
120TcpServer::~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
152ConnectionHandler::~ConnectionHandler (void)
153{
154	delete m_socket;
155}
156
157void 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