2015-01-17 17:33:59 -05:00
|
|
|
|
|
|
|
// NetworkSingleton.cpp
|
|
|
|
|
|
|
|
// Implements the cNetworkSingleton class representing the storage for global data pertaining to network API
|
|
|
|
// such as a list of all connections, all listening sockets and the LibEvent dispatch thread.
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
#include "NetworkSingleton.h"
|
|
|
|
#include <event2/event.h>
|
|
|
|
#include <event2/thread.h>
|
|
|
|
#include <event2/bufferevent.h>
|
|
|
|
#include <event2/dns.h>
|
|
|
|
#include <event2/listener.h>
|
2015-01-18 05:57:16 -05:00
|
|
|
#include "IPLookup.h"
|
|
|
|
#include "HostnameLookup.h"
|
2015-01-17 17:33:59 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-01-26 08:46:20 -05:00
|
|
|
cNetworkSingleton::cNetworkSingleton(void):
|
|
|
|
m_HasTerminated(false)
|
2015-01-17 17:33:59 -05:00
|
|
|
{
|
|
|
|
// Windows: initialize networking:
|
|
|
|
#ifdef _WIN32
|
|
|
|
WSADATA wsaData;
|
|
|
|
memset(&wsaData, 0, sizeof(wsaData));
|
|
|
|
int res = WSAStartup (MAKEWORD(2, 2), &wsaData);
|
|
|
|
if (res != 0)
|
|
|
|
{
|
|
|
|
int err = WSAGetLastError();
|
|
|
|
LOGWARNING("WSAStartup failed: %d, WSAGLE = %d (%s)", res, err, evutil_socket_error_to_string(err));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
#endif // _WIN32
|
|
|
|
|
|
|
|
// Initialize LibEvent logging:
|
|
|
|
event_set_log_callback(LogCallback);
|
|
|
|
|
|
|
|
// Initialize threading:
|
|
|
|
#if defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
|
|
|
|
evthread_use_windows_threads();
|
|
|
|
#elif defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
|
|
|
|
evthread_use_pthreads();
|
|
|
|
#else
|
|
|
|
#error No threading implemented for EVTHREAD
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Create the main event_base:
|
|
|
|
m_EventBase = event_base_new();
|
|
|
|
if (m_EventBase == nullptr)
|
|
|
|
{
|
|
|
|
LOGERROR("Failed to initialize LibEvent. The server will now terminate.");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the DNS lookup helper:
|
|
|
|
m_DNSBase = evdns_base_new(m_EventBase, 1);
|
|
|
|
if (m_DNSBase == nullptr)
|
|
|
|
{
|
|
|
|
LOGERROR("Failed to initialize LibEvent's DNS subsystem. The server will now terminate.");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the event loop thread:
|
2015-02-18 16:41:22 -05:00
|
|
|
m_EventLoopThread = std::thread(RunEventLoop, this);
|
2015-01-17 17:33:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-01-18 06:35:02 -05:00
|
|
|
cNetworkSingleton::~cNetworkSingleton()
|
2015-01-17 17:33:59 -05:00
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
// Check that Terminate has been called already:
|
|
|
|
ASSERT(m_HasTerminated);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cNetworkSingleton & cNetworkSingleton::Get(void)
|
|
|
|
{
|
|
|
|
static cNetworkSingleton Instance;
|
|
|
|
return Instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cNetworkSingleton::Terminate(void)
|
|
|
|
{
|
|
|
|
ASSERT(!m_HasTerminated);
|
|
|
|
m_HasTerminated = true;
|
|
|
|
|
2015-01-18 06:35:02 -05:00
|
|
|
// Wait for the LibEvent event loop to terminate:
|
|
|
|
event_base_loopbreak(m_EventBase);
|
2015-02-18 16:41:22 -05:00
|
|
|
m_EventLoopThread.join();
|
2015-01-17 17:33:59 -05:00
|
|
|
|
2015-01-18 06:35:02 -05:00
|
|
|
// Remove all objects:
|
2015-01-17 17:33:59 -05:00
|
|
|
{
|
|
|
|
cCSLock Lock(m_CS);
|
2015-01-18 06:35:02 -05:00
|
|
|
m_Connections.clear();
|
|
|
|
m_Servers.clear();
|
|
|
|
m_HostnameLookups.clear();
|
|
|
|
m_IPLookups.clear();
|
2015-01-17 17:33:59 -05:00
|
|
|
}
|
2015-01-18 06:35:02 -05:00
|
|
|
|
|
|
|
// Free the underlying LibEvent objects:
|
|
|
|
evdns_base_free(m_DNSBase, true);
|
|
|
|
event_base_free(m_EventBase);
|
2015-01-23 17:01:18 -05:00
|
|
|
|
|
|
|
libevent_global_shutdown();
|
2015-01-17 17:33:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-01-18 06:35:02 -05:00
|
|
|
|
2015-01-17 17:33:59 -05:00
|
|
|
void cNetworkSingleton::LogCallback(int a_Severity, const char * a_Msg)
|
|
|
|
{
|
|
|
|
switch (a_Severity)
|
|
|
|
{
|
|
|
|
case _EVENT_LOG_DEBUG: LOGD ("LibEvent: %s", a_Msg); break;
|
|
|
|
case _EVENT_LOG_MSG: LOG ("LibEvent: %s", a_Msg); break;
|
|
|
|
case _EVENT_LOG_WARN: LOGWARNING("LibEvent: %s", a_Msg); break;
|
|
|
|
case _EVENT_LOG_ERR: LOGERROR ("LibEvent: %s", a_Msg); break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
LOGWARNING("LibEvent: Unknown log severity (%d): %s", a_Severity, a_Msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cNetworkSingleton::RunEventLoop(cNetworkSingleton * a_Self)
|
|
|
|
{
|
|
|
|
event_base_loop(a_Self->m_EventBase, EVLOOP_NO_EXIT_ON_EMPTY);
|
2015-01-18 06:35:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cNetworkSingleton::AddHostnameLookup(cHostnameLookupPtr a_HostnameLookup)
|
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
ASSERT(!m_HasTerminated);
|
2015-01-18 06:35:02 -05:00
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
m_HostnameLookups.push_back(a_HostnameLookup);
|
2015-01-17 17:33:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cNetworkSingleton::RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup)
|
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
ASSERT(!m_HasTerminated);
|
2015-01-17 17:33:59 -05:00
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
for (auto itr = m_HostnameLookups.begin(), end = m_HostnameLookups.end(); itr != end; ++itr)
|
|
|
|
{
|
|
|
|
if (itr->get() == a_HostnameLookup)
|
|
|
|
{
|
|
|
|
m_HostnameLookups.erase(itr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} // for itr - m_HostnameLookups[]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-01-18 06:35:02 -05:00
|
|
|
void cNetworkSingleton::AddIPLookup(cIPLookupPtr a_IPLookup)
|
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
ASSERT(!m_HasTerminated);
|
2015-01-18 06:35:02 -05:00
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
m_IPLookups.push_back(a_IPLookup);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-01-17 17:33:59 -05:00
|
|
|
void cNetworkSingleton::RemoveIPLookup(const cIPLookup * a_IPLookup)
|
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
ASSERT(!m_HasTerminated);
|
2015-01-17 17:33:59 -05:00
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
for (auto itr = m_IPLookups.begin(), end = m_IPLookups.end(); itr != end; ++itr)
|
|
|
|
{
|
|
|
|
if (itr->get() == a_IPLookup)
|
|
|
|
{
|
|
|
|
m_IPLookups.erase(itr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} // for itr - m_IPLookups[]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cNetworkSingleton::AddLink(cTCPLinkImplPtr a_Link)
|
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
ASSERT(!m_HasTerminated);
|
2015-01-17 17:33:59 -05:00
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
m_Connections.push_back(a_Link);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cNetworkSingleton::RemoveLink(const cTCPLinkImpl * a_Link)
|
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
ASSERT(!m_HasTerminated);
|
2015-01-17 17:33:59 -05:00
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
for (auto itr = m_Connections.begin(), end = m_Connections.end(); itr != end; ++itr)
|
|
|
|
{
|
|
|
|
if (itr->get() == a_Link)
|
|
|
|
{
|
|
|
|
m_Connections.erase(itr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} // for itr - m_Connections[]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cNetworkSingleton::AddServer(cServerHandleImplPtr a_Server)
|
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
ASSERT(!m_HasTerminated);
|
2015-01-17 17:33:59 -05:00
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
m_Servers.push_back(a_Server);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cNetworkSingleton::RemoveServer(const cServerHandleImpl * a_Server)
|
|
|
|
{
|
2015-01-26 08:46:20 -05:00
|
|
|
ASSERT(!m_HasTerminated);
|
2015-01-17 17:33:59 -05:00
|
|
|
cCSLock Lock(m_CS);
|
|
|
|
for (auto itr = m_Servers.begin(), end = m_Servers.end(); itr != end; ++itr)
|
|
|
|
{
|
|
|
|
if (itr->get() == a_Server)
|
|
|
|
{
|
|
|
|
m_Servers.erase(itr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} // for itr - m_Servers[]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|