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