Merge "Add the support to device connection via TCP/IP" into marshmallow-cts-dev
[platform/upstream/VK-GL-CTS.git] / execserver / xsTcpServer.cpp
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