From 28d8d8419a5b900e9d20ce91dc63e28349b6470a Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Mon, 4 Mar 2013 21:13:08 +0000 Subject: Moved client socket accepting into a separate thread object, cListenThread MCServer can now listen on multiple ports FS #312 git-svn-id: http://mc-server.googlecode.com/svn/trunk@1252 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/ListenThread.cpp | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 source/ListenThread.cpp (limited to 'source/ListenThread.cpp') diff --git a/source/ListenThread.cpp b/source/ListenThread.cpp new file mode 100644 index 000000000..52a4df9e4 --- /dev/null +++ b/source/ListenThread.cpp @@ -0,0 +1,172 @@ + +// ListenThread.cpp + +// Implements the cListenThread class representing the thread that listens for client connections + +#include "Globals.h" +#include "ListenThread.h" + + + + + +cListenThread::cListenThread(cCallback & a_Callback) : + super("ListenThread"), + m_Callback(a_Callback) +{ +} + + + + + +cListenThread::~cListenThread() +{ + // TODO +} + + + + + +bool cListenThread::Initialize(const AString & a_PortsString) +{ + ASSERT(m_Sockets.empty()); // Not yet started + + if (!CreateSockets(a_PortsString)) + { + return false; + } + + return true; +} + + + + + +bool cListenThread::Start(void) +{ + ASSERT(!m_Sockets.empty()); // Has Initialize() been called? + + return super::Start(); +} + + + + + +void cListenThread::Stop(void) +{ + m_ShouldTerminate = true; + + // Close one socket to wake the thread up from the select() call + m_Sockets[0].CloseSocket(); + + // Wait for the thread to finish + super::Wait(); + + // Clean up all sockets + m_Sockets.clear(); +} + + + + + +void cListenThread::SetReuseAddr(bool a_Reuse) +{ + ASSERT(m_Sockets.empty()); // Must not be started + + m_ShouldReuseAddr = a_Reuse; +} + + + + + +bool cListenThread::CreateSockets(const AString & a_PortsString) +{ + AStringVector Ports = StringSplit(a_PortsString, ","); + + if (Ports.empty()) + { + return false; + } + + for (AStringVector::const_iterator itr = Ports.begin(), end = Ports.end(); itr != end; ++itr) + { + int Port = atoi(Trim(*itr).c_str()); + if ((Port <= 0) || (Port > 65535)) + { + LOGWARNING("Invalid port specified: \"%s\".", Trim(*itr).c_str()); + continue; + } + m_Sockets.push_back(cSocket::CreateSocket()); + if (!m_Sockets.back().IsValid()) + { + LOGERROR("Cannot create listening socket for port %d: \"%s\"", Port, cSocket::GetLastErrorString().c_str()); + m_Sockets.pop_back(); + continue; + } + + if (m_ShouldReuseAddr) + { + if (m_Sockets.back().SetReuseAddress() == -1) + { + LOG("Port %d cannot reuse addr, syscall failed: \"%s\".", Port, cSocket::GetLastErrorString().c_str()); + } + } + m_Sockets.back().BindToAny(Port); + m_Sockets.back().Listen(); + LOGD("Port %d is open for connections", Port); + } // for itr - Ports[] + + return !(m_Sockets.empty()); +} + + + + + +void cListenThread::Execute(void) +{ + // Find the highest socket number: + cSocket::xSocket Highest = m_Sockets[0].GetSocket(); + for (cSockets::iterator itr = m_Sockets.begin(), end = m_Sockets.end(); itr != end; ++itr) + { + if (itr->GetSocket() > Highest) + { + Highest = itr->GetSocket(); + } + } // for itr - m_Sockets[] + + while (!m_ShouldTerminate) + { + // Put all sockets into a FD set: + fd_set fdRead; + FD_ZERO(&fdRead); + for (cSockets::iterator itr = m_Sockets.begin(), end = m_Sockets.end(); itr != end; ++itr) + { + FD_SET(itr->GetSocket(), &fdRead); + } // for itr - m_Sockets[] + + if (select(Highest + 1, &fdRead, NULL, NULL, NULL) == -1) + { + LOG("select(R) call failed in cListenThread: \"%s\"", cSocket::GetLastErrorString().c_str()); + continue; + } + for (cSockets::iterator itr = m_Sockets.begin(), end = m_Sockets.end(); itr != end; ++itr) + { + if (FD_ISSET(itr->GetSocket(), &fdRead)) + { + cSocket Client = itr->Accept(); + m_Callback.OnConnectionAccepted(Client); + } + } // for itr - m_Sockets[] + } // while (!m_ShouldTerminate) +} + + + + -- cgit v1.2.3