You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
3.9 KiB
173 lines
3.9 KiB
4 months ago
|
/*-------------------------------------------------------------------------
|
||
|
* drawElements Quality Program Execution Server
|
||
|
* ---------------------------------------------
|
||
|
*
|
||
|
* Copyright 2014 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
*//*!
|
||
|
* \file
|
||
|
* \brief TCP Server.
|
||
|
*//*--------------------------------------------------------------------*/
|
||
|
|
||
|
#include "xsTcpServer.hpp"
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <iterator>
|
||
|
#include <cstdio>
|
||
|
|
||
|
namespace xs
|
||
|
{
|
||
|
|
||
|
TcpServer::TcpServer (deSocketFamily family, int port)
|
||
|
: m_socket()
|
||
|
{
|
||
|
de::SocketAddress address;
|
||
|
address.setFamily(family);
|
||
|
address.setPort(port);
|
||
|
address.setType(DE_SOCKETTYPE_STREAM);
|
||
|
address.setProtocol(DE_SOCKETPROTOCOL_TCP);
|
||
|
|
||
|
m_socket.listen(address);
|
||
|
m_socket.setFlags(DE_SOCKET_CLOSE_ON_EXEC);
|
||
|
}
|
||
|
|
||
|
void TcpServer::runServer (void)
|
||
|
{
|
||
|
de::Socket* clientSocket = DE_NULL;
|
||
|
de::SocketAddress clientAddr;
|
||
|
|
||
|
while ((clientSocket = m_socket.accept(clientAddr)) != DE_NULL)
|
||
|
{
|
||
|
ConnectionHandler* handler = DE_NULL;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
handler = createHandler(clientSocket, clientAddr);
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
delete clientSocket;
|
||
|
throw;
|
||
|
}
|
||
|
|
||
|
try
|
||
|
{
|
||
|
addLiveConnection(handler);
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
delete handler;
|
||
|
throw;
|
||
|
}
|
||
|
|
||
|
// Start handler.
|
||
|
handler->start();
|
||
|
|
||
|
// Perform connection list cleanup.
|
||
|
deleteDoneConnections();
|
||
|
}
|
||
|
|
||
|
// One more cleanup pass.
|
||
|
deleteDoneConnections();
|
||
|
}
|
||
|
|
||
|
void TcpServer::connectionDone (ConnectionHandler* handler)
|
||
|
{
|
||
|
de::ScopedLock lock(m_connectionListLock);
|
||
|
|
||
|
std::vector<ConnectionHandler*>::iterator liveListPos = std::find(m_liveConnections.begin(), m_liveConnections.end(), handler);
|
||
|
DE_ASSERT(liveListPos != m_liveConnections.end());
|
||
|
|
||
|
m_doneConnections.reserve(m_doneConnections.size()+1);
|
||
|
m_liveConnections.erase(liveListPos);
|
||
|
m_doneConnections.push_back(handler);
|
||
|
}
|
||
|
|
||
|
void TcpServer::addLiveConnection (ConnectionHandler* handler)
|
||
|
{
|
||
|
de::ScopedLock lock(m_connectionListLock);
|
||
|
m_liveConnections.push_back(handler);
|
||
|
}
|
||
|
|
||
|
void TcpServer::deleteDoneConnections (void)
|
||
|
{
|
||
|
de::ScopedLock lock(m_connectionListLock);
|
||
|
|
||
|
for (std::vector<ConnectionHandler*>::iterator i = m_doneConnections.begin(); i != m_doneConnections.end(); i++)
|
||
|
delete *i;
|
||
|
|
||
|
m_doneConnections.clear();
|
||
|
}
|
||
|
|
||
|
void TcpServer::stopServer (void)
|
||
|
{
|
||
|
// Close socket. This should get accept() to return null.
|
||
|
m_socket.close();
|
||
|
}
|
||
|
|
||
|
TcpServer::~TcpServer (void)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
std::vector<ConnectionHandler*> allConnections;
|
||
|
|
||
|
if (m_connectionListLock.tryLock())
|
||
|
{
|
||
|
// \note [pyry] It is possible that cleanup actually fails.
|
||
|
try
|
||
|
{
|
||
|
std::copy(m_liveConnections.begin(), m_liveConnections.end(), std::inserter(allConnections, allConnections.end()));
|
||
|
std::copy(m_doneConnections.begin(), m_doneConnections.end(), std::inserter(allConnections, allConnections.end()));
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
}
|
||
|
m_connectionListLock.unlock();
|
||
|
}
|
||
|
|
||
|
for (std::vector<ConnectionHandler*>::const_iterator i = allConnections.begin(); i != allConnections.end(); i++)
|
||
|
delete *i;
|
||
|
|
||
|
if (m_socket.getState() != DE_SOCKETSTATE_CLOSED)
|
||
|
m_socket.close();
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
// Nada, we're at destructor.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ConnectionHandler::~ConnectionHandler (void)
|
||
|
{
|
||
|
delete m_socket;
|
||
|
}
|
||
|
|
||
|
void ConnectionHandler::run (void)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
handle();
|
||
|
}
|
||
|
catch (const std::exception& e)
|
||
|
{
|
||
|
printf("ConnectionHandler::run(): %s\n", e.what());
|
||
|
}
|
||
|
|
||
|
// Notify server that this connection is done.
|
||
|
m_server->connectionDone(this);
|
||
|
}
|
||
|
|
||
|
} // xs
|