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 
TcpServer(deSocketFamily family,int port)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 
runServer(void)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 
connectionDone(ConnectionHandler * handler)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 
addLiveConnection(ConnectionHandler * handler)98 void TcpServer::addLiveConnection (ConnectionHandler* handler)
99 {
100 	de::ScopedLock lock(m_connectionListLock);
101 	m_liveConnections.push_back(handler);
102 }
103 
deleteDoneConnections(void)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 
stopServer(void)114 void TcpServer::stopServer (void)
115 {
116 	// Close socket. This should get accept() to return null.
117 	m_socket.close();
118 }
119 
~TcpServer(void)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 
~ConnectionHandler(void)152 ConnectionHandler::~ConnectionHandler (void)
153 {
154 	delete m_socket;
155 }
156 
run(void)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