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) : m_socket()
34 {
35 de::SocketAddress address;
36 address.setFamily(family);
37 address.setPort(port);
38 address.setType(DE_SOCKETTYPE_STREAM);
39 address.setProtocol(DE_SOCKETPROTOCOL_TCP);
40
41 m_socket.listen(address);
42 m_socket.setFlags(DE_SOCKET_CLOSE_ON_EXEC);
43 }
44
runServer(void)45 void TcpServer::runServer(void)
46 {
47 de::Socket *clientSocket = DE_NULL;
48 de::SocketAddress clientAddr;
49
50 while ((clientSocket = m_socket.accept(clientAddr)) != DE_NULL)
51 {
52 ConnectionHandler *handler = DE_NULL;
53
54 try
55 {
56 handler = createHandler(clientSocket, clientAddr);
57 }
58 catch (...)
59 {
60 delete clientSocket;
61 throw;
62 }
63
64 try
65 {
66 addLiveConnection(handler);
67 }
68 catch (...)
69 {
70 delete handler;
71 throw;
72 }
73
74 // Start handler.
75 handler->start();
76
77 // Perform connection list cleanup.
78 deleteDoneConnections();
79 }
80
81 // One more cleanup pass.
82 deleteDoneConnections();
83 }
84
connectionDone(ConnectionHandler * handler)85 void TcpServer::connectionDone(ConnectionHandler *handler)
86 {
87 de::ScopedLock lock(m_connectionListLock);
88
89 std::vector<ConnectionHandler *>::iterator liveListPos =
90 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(),
132 std::inserter(allConnections, allConnections.end()));
133 std::copy(m_doneConnections.begin(), m_doneConnections.end(),
134 std::inserter(allConnections, allConnections.end()));
135 }
136 catch (...)
137 {
138 }
139 m_connectionListLock.unlock();
140 }
141
142 for (std::vector<ConnectionHandler *>::const_iterator i = allConnections.begin(); i != allConnections.end();
143 i++)
144 delete *i;
145
146 if (m_socket.getState() != DE_SOCKETSTATE_CLOSED)
147 m_socket.close();
148 }
149 catch (...)
150 {
151 // Nada, we're at destructor.
152 }
153 }
154
~ConnectionHandler(void)155 ConnectionHandler::~ConnectionHandler(void)
156 {
157 delete m_socket;
158 }
159
run(void)160 void ConnectionHandler::run(void)
161 {
162 try
163 {
164 handle();
165 }
166 catch (const std::exception &e)
167 {
168 printf("ConnectionHandler::run(): %s\n", e.what());
169 }
170
171 // Notify server that this connection is done.
172 m_server->connectionDone(this);
173 }
174
175 } // namespace xs
176