cNetwork: Split cNetworkSingleton to a separate file.
This commit is contained in:
parent
ae29a82eba
commit
d3076a3e16
@ -13,6 +13,7 @@ SET (SRCS
|
||||
IsThread.cpp
|
||||
ListenThread.cpp
|
||||
Network.cpp
|
||||
NetworkSingleton.cpp
|
||||
Semaphore.cpp
|
||||
Socket.cpp
|
||||
SocketThreads.cpp
|
||||
@ -28,6 +29,7 @@ SET (HDRS
|
||||
IsThread.h
|
||||
ListenThread.h
|
||||
Network.h
|
||||
NetworkSingleton.h
|
||||
Queue.h
|
||||
Semaphore.h
|
||||
Socket.h
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <thread>
|
||||
#include "Event.h"
|
||||
#include "CriticalSection.h"
|
||||
#include "NetworkSingleton.h"
|
||||
|
||||
|
||||
|
||||
@ -232,102 +233,6 @@ protected:
|
||||
|
||||
|
||||
|
||||
class cNetworkSingleton
|
||||
{
|
||||
friend class cHostnameLookup; // Needs access to m_DNSBase
|
||||
friend class cIPLookup; // Needs access to m_DNSBase
|
||||
friend class cTCPLinkImpl; // Needs access to m_EventBase and m_DNSBase
|
||||
friend class cServerHandleImpl; // Needs access to m_EventBase
|
||||
|
||||
public:
|
||||
/** Returns the singleton instance of this class */
|
||||
static cNetworkSingleton & Get(void);
|
||||
|
||||
|
||||
// The following functions are implementations for the cNetwork class
|
||||
|
||||
/** Queues a DNS query to resolve the specified hostname to IP address.
|
||||
Calls one of the callbacks when the resolving succeeds, or when it fails.
|
||||
Returns true if queueing was successful, false if not.
|
||||
Note that the return value doesn't report the success of the actual lookup; the lookup happens asynchronously on the background. */
|
||||
bool HostnameToIP(
|
||||
const AString & a_Hostname,
|
||||
cNetwork::cResolveNameCallbacksPtr a_Callbacks
|
||||
);
|
||||
|
||||
|
||||
/** Queues a DNS query to resolve the specified IP address to a hostname.
|
||||
Calls one of the callbacks when the resolving succeeds, or when it fails.
|
||||
Returns true if queueing was successful, false if not.
|
||||
Note that the return value doesn't report the success of the actual lookup; the lookup happens asynchronously on the background. */
|
||||
bool IPToHostName(
|
||||
const AString & a_IP,
|
||||
cNetwork::cResolveNameCallbacksPtr a_Callbacks
|
||||
);
|
||||
|
||||
protected:
|
||||
|
||||
/** The main LibEvent container for driving the event loop. */
|
||||
event_base * m_EventBase;
|
||||
|
||||
/** The LibEvent handle for doing DNS lookups. */
|
||||
evdns_base * m_DNSBase;
|
||||
|
||||
/** Container for all client connections, including ones with pending-connect. */
|
||||
cTCPLinkImplPtrs m_Connections;
|
||||
|
||||
/** Container for all servers that are currently active. */
|
||||
cServerHandleImplPtrs m_Servers;
|
||||
|
||||
/** Container for all pending hostname lookups. */
|
||||
cHostnameLookupPtrs m_HostnameLookups;
|
||||
|
||||
/** Container for all pending IP lookups. */
|
||||
cIPLookupPtrs m_IPLookups;
|
||||
|
||||
/** Mutex protecting all containers against multithreaded access. */
|
||||
cCriticalSection m_CS;
|
||||
|
||||
|
||||
/** Initializes the LibEvent internals. */
|
||||
cNetworkSingleton(void);
|
||||
|
||||
/** Converts LibEvent-generated log events into log messages in MCS log. */
|
||||
static void LogCallback(int a_Severity, const char * a_Msg);
|
||||
|
||||
/** Implements the thread that runs LibEvent's event dispatcher loop. */
|
||||
static void RunEventLoop(cNetworkSingleton * a_Self);
|
||||
|
||||
/** Removes the specified hostname lookup from m_HostnameLookups.
|
||||
Used by the underlying lookup implementation when the lookup is finished. */
|
||||
void RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup);
|
||||
|
||||
/** Removes the specified IP lookup from m_IPLookups.
|
||||
Used by the underlying lookup implementation when the lookup is finished. */
|
||||
void RemoveIPLookup(const cIPLookup * a_IPLookup);
|
||||
|
||||
/** Adds the specified link to m_Connections.
|
||||
Used by the underlying link implementation when a new link is created. */
|
||||
void AddLink(cTCPLinkImplPtr a_Link);
|
||||
|
||||
/** Removes the specified link from m_Connections.
|
||||
Used by the underlying link implementation when the link is closed / errored. */
|
||||
void RemoveLink(const cTCPLinkImpl * a_Link);
|
||||
|
||||
/** Adds the specified link to m_Servers.
|
||||
Used by the underlying server handle implementation when a new listening server is created.
|
||||
Only servers that succeed in listening are added. */
|
||||
void AddServer(cServerHandleImplPtr a_Server);
|
||||
|
||||
/** Removes the specified server from m_Servers.
|
||||
Used by the underlying server handle implementation when the server is closed. */
|
||||
void RemoveServer(const cServerHandleImpl * a_Server);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Globals:
|
||||
|
||||
@ -357,7 +262,7 @@ cHostnameLookup::cHostnameLookup(const AString & a_Hostname, cNetwork::cResolveN
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_flags = EVUTIL_AI_CANONNAME;
|
||||
evdns_getaddrinfo(cNetworkSingleton::Get().m_DNSBase, a_Hostname.c_str(), nullptr, &hints, Callback, this);
|
||||
evdns_getaddrinfo(cNetworkSingleton::Get().GetDNSBase(), a_Hostname.c_str(), nullptr, &hints, Callback, this);
|
||||
}
|
||||
|
||||
|
||||
@ -440,13 +345,13 @@ cIPLookup::cIPLookup(const AString & a_IP, cNetwork::cResolveNameCallbacksPtr a_
|
||||
case AF_INET:
|
||||
{
|
||||
sockaddr_in * sa4 = reinterpret_cast<sockaddr_in *>(&sa);
|
||||
evdns_base_resolve_reverse(cNetworkSingleton::Get().m_DNSBase, &(sa4->sin_addr), 0, Callback, this);
|
||||
evdns_base_resolve_reverse(cNetworkSingleton::Get().GetDNSBase(), &(sa4->sin_addr), 0, Callback, this);
|
||||
break;
|
||||
}
|
||||
case AF_INET6:
|
||||
{
|
||||
sockaddr_in6 * sa6 = reinterpret_cast<sockaddr_in6 *>(&sa);
|
||||
evdns_base_resolve_reverse_ipv6(cNetworkSingleton::Get().m_DNSBase, &(sa6->sin6_addr), 0, Callback, this);
|
||||
evdns_base_resolve_reverse_ipv6(cNetworkSingleton::Get().GetDNSBase(), &(sa6->sin6_addr), 0, Callback, this);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -492,7 +397,7 @@ void cIPLookup::Callback(int a_Result, char a_Type, int a_Count, int a_Ttl, void
|
||||
|
||||
cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks):
|
||||
super(a_LinkCallbacks),
|
||||
m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().m_EventBase, -1, BEV_OPT_CLOSE_ON_FREE)),
|
||||
m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), -1, BEV_OPT_CLOSE_ON_FREE)),
|
||||
m_Server(nullptr)
|
||||
{
|
||||
// Create the LibEvent handle, but don't assign a socket to it yet (will be assigned within Connect() method):
|
||||
@ -506,7 +411,7 @@ cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks):
|
||||
|
||||
cTCPLinkImpl::cTCPLinkImpl(evutil_socket_t a_Socket, cTCPLink::cCallbacksPtr a_LinkCallbacks, cServerHandleImpl * a_Server, const sockaddr * a_Address, int a_AddrLen):
|
||||
super(a_LinkCallbacks),
|
||||
m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().m_EventBase, a_Socket, BEV_OPT_CLOSE_ON_FREE)),
|
||||
m_BufferEvent(bufferevent_socket_new(cNetworkSingleton::Get().GetEventBase(), a_Socket, BEV_OPT_CLOSE_ON_FREE)),
|
||||
m_Server(a_Server)
|
||||
{
|
||||
// Update the endpoint addresses:
|
||||
@ -568,7 +473,7 @@ cTCPLinkImplPtr cTCPLinkImpl::Connect(const AString & a_Host, UInt16 a_Port, cTC
|
||||
}
|
||||
|
||||
// a_Host is a hostname, connect after a lookup:
|
||||
if (bufferevent_socket_connect_hostname(res->m_BufferEvent, cNetworkSingleton::Get().m_DNSBase, AF_UNSPEC, a_Host.c_str(), a_Port) == 0)
|
||||
if (bufferevent_socket_connect_hostname(res->m_BufferEvent, cNetworkSingleton::Get().GetDNSBase(), AF_UNSPEC, a_Host.c_str(), a_Port) == 0)
|
||||
{
|
||||
// Success
|
||||
return res;
|
||||
@ -932,7 +837,7 @@ bool cServerHandleImpl::Listen(UInt16 a_Port)
|
||||
evutil_closesocket(MainSock);
|
||||
return false;
|
||||
}
|
||||
m_ConnListener = evconnlistener_new(cNetworkSingleton::Get().m_EventBase, Callback, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 0, MainSock);
|
||||
m_ConnListener = evconnlistener_new(cNetworkSingleton::Get().GetEventBase(), Callback, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 0, MainSock);
|
||||
|
||||
// If a secondary socket is required (WinXP dual-stack), create it here:
|
||||
if (NeedsTwoSockets)
|
||||
@ -943,7 +848,7 @@ bool cServerHandleImpl::Listen(UInt16 a_Port)
|
||||
{
|
||||
if (evutil_make_socket_nonblocking(SecondSock) == 0)
|
||||
{
|
||||
m_SecondaryConnListener = evconnlistener_new(cNetworkSingleton::Get().m_EventBase, Callback, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 0, SecondSock);
|
||||
m_SecondaryConnListener = evconnlistener_new(cNetworkSingleton::Get().GetEventBase(), Callback, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 0, SecondSock);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1070,224 +975,3 @@ cTCPLink::cTCPLink(cCallbacksPtr a_Callbacks):
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cNetworkSingleton:
|
||||
|
||||
cNetworkSingleton::cNetworkSingleton(void)
|
||||
{
|
||||
// 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:
|
||||
std::thread EventLoopThread(RunEventLoop, this);
|
||||
EventLoopThread.detach();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cNetworkSingleton & cNetworkSingleton::Get(void)
|
||||
{
|
||||
static cNetworkSingleton Instance;
|
||||
return Instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cNetworkSingleton::HostnameToIP(
|
||||
const AString & a_Hostname,
|
||||
cNetwork::cResolveNameCallbacksPtr a_Callbacks
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_HostnameLookups.push_back(std::make_shared<cHostnameLookup>(a_Hostname, a_Callbacks));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool cNetworkSingleton::IPToHostName(
|
||||
const AString & a_IP,
|
||||
cNetwork::cResolveNameCallbacksPtr a_Callbacks
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_IPLookups.push_back(std::make_shared<cIPLookup>(a_IP, a_Callbacks));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetworkSingleton::RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup)
|
||||
{
|
||||
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[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetworkSingleton::RemoveIPLookup(const cIPLookup * a_IPLookup)
|
||||
{
|
||||
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)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_Connections.push_back(a_Link);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetworkSingleton::RemoveLink(const cTCPLinkImpl * a_Link)
|
||||
{
|
||||
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)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_Servers.push_back(a_Server);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetworkSingleton::RemoveServer(const cServerHandleImpl * a_Server)
|
||||
{
|
||||
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[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
281
src/OSSupport/NetworkSingleton.cpp
Normal file
281
src/OSSupport/NetworkSingleton.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
|
||||
// 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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Class definitions:
|
||||
|
||||
/** Holds information about an in-progress Hostname-to-IP lookup. */
|
||||
class cHostnameLookup
|
||||
{
|
||||
/** The callbacks to call for resolved names / errors. */
|
||||
cNetwork::cResolveNameCallbacksPtr m_Callbacks;
|
||||
|
||||
/** The hostname that was queried (needed for the callbacks). */
|
||||
AString m_Hostname;
|
||||
|
||||
static void Callback(int a_ErrCode, struct evutil_addrinfo * a_Addr, void * a_Self);
|
||||
|
||||
public:
|
||||
cHostnameLookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks);
|
||||
};
|
||||
typedef SharedPtr<cHostnameLookup> cHostnameLookupPtr;
|
||||
typedef std::vector<cHostnameLookupPtr> cHostnameLookupPtrs;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Holds information about an in-progress IP-to-Hostname lookup. */
|
||||
class cIPLookup
|
||||
{
|
||||
/** The callbacks to call for resolved names / errors. */
|
||||
cNetwork::cResolveNameCallbacksPtr m_Callbacks;
|
||||
|
||||
/** The IP that was queried (needed for the callbacks). */
|
||||
AString m_IP;
|
||||
|
||||
static void Callback(int a_Result, char a_Type, int a_Count, int a_Ttl, void * a_Addresses, void * a_Self);
|
||||
|
||||
public:
|
||||
cIPLookup(const AString & a_IP, cNetwork::cResolveNameCallbacksPtr a_Callbacks);
|
||||
};
|
||||
typedef SharedPtr<cIPLookup> cIPLookupPtr;
|
||||
typedef std::vector<cIPLookupPtr> cIPLookupPtrs;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cNetworkSingleton::cNetworkSingleton(void)
|
||||
{
|
||||
// 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:
|
||||
std::thread EventLoopThread(RunEventLoop, this);
|
||||
EventLoopThread.detach();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cNetworkSingleton & cNetworkSingleton::Get(void)
|
||||
{
|
||||
static cNetworkSingleton Instance;
|
||||
return Instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cNetworkSingleton::HostnameToIP(
|
||||
const AString & a_Hostname,
|
||||
cNetwork::cResolveNameCallbacksPtr a_Callbacks
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_HostnameLookups.push_back(std::make_shared<cHostnameLookup>(a_Hostname, a_Callbacks));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool cNetworkSingleton::IPToHostName(
|
||||
const AString & a_IP,
|
||||
cNetwork::cResolveNameCallbacksPtr a_Callbacks
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_IPLookups.push_back(std::make_shared<cIPLookup>(a_IP, a_Callbacks));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetworkSingleton::RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup)
|
||||
{
|
||||
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[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetworkSingleton::RemoveIPLookup(const cIPLookup * a_IPLookup)
|
||||
{
|
||||
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)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_Connections.push_back(a_Link);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetworkSingleton::RemoveLink(const cTCPLinkImpl * a_Link)
|
||||
{
|
||||
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)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_Servers.push_back(a_Server);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetworkSingleton::RemoveServer(const cServerHandleImpl * a_Server)
|
||||
{
|
||||
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[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
138
src/OSSupport/NetworkSingleton.h
Normal file
138
src/OSSupport/NetworkSingleton.h
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
// NetworkSingleton.h
|
||||
|
||||
// Declares 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Network.h"
|
||||
#include "CriticalSection.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
struct event_base;
|
||||
struct evdns_base;
|
||||
class cServerHandleImpl;
|
||||
class cTCPLinkImpl;
|
||||
class cHostnameLookup;
|
||||
class cIPLookup;
|
||||
typedef SharedPtr<cTCPLinkImpl> cTCPLinkImplPtr;
|
||||
typedef std::vector<cTCPLinkImplPtr> cTCPLinkImplPtrs;
|
||||
typedef SharedPtr<cServerHandleImpl> cServerHandleImplPtr;
|
||||
typedef std::vector<cServerHandleImplPtr> cServerHandleImplPtrs;
|
||||
typedef SharedPtr<cHostnameLookup> cHostnameLookupPtr;
|
||||
typedef std::vector<cHostnameLookupPtr> cHostnameLookupPtrs;
|
||||
typedef SharedPtr<cIPLookup> cIPLookupPtr;
|
||||
typedef std::vector<cIPLookupPtr> cIPLookupPtrs;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cNetworkSingleton
|
||||
{
|
||||
public:
|
||||
/** Returns the singleton instance of this class */
|
||||
static cNetworkSingleton & Get(void);
|
||||
|
||||
|
||||
// The following functions are implementations for the cNetwork class
|
||||
|
||||
/** Queues a DNS query to resolve the specified hostname to IP address.
|
||||
Calls one of the callbacks when the resolving succeeds, or when it fails.
|
||||
Returns true if queueing was successful, false if not.
|
||||
Note that the return value doesn't report the success of the actual lookup; the lookup happens asynchronously on the background.
|
||||
TODO: Move this out into a separate file with cHostnameLookup. */
|
||||
bool HostnameToIP(
|
||||
const AString & a_Hostname,
|
||||
cNetwork::cResolveNameCallbacksPtr a_Callbacks
|
||||
);
|
||||
|
||||
|
||||
/** Queues a DNS query to resolve the specified IP address to a hostname.
|
||||
Calls one of the callbacks when the resolving succeeds, or when it fails.
|
||||
Returns true if queueing was successful, false if not.
|
||||
Note that the return value doesn't report the success of the actual lookup; the lookup happens asynchronously on the background.
|
||||
TODO: Move this out into a separate file with cIPLookup. */
|
||||
bool IPToHostName(
|
||||
const AString & a_IP,
|
||||
cNetwork::cResolveNameCallbacksPtr a_Callbacks
|
||||
);
|
||||
|
||||
/** Returns the main LibEvent handle for event registering. */
|
||||
event_base * GetEventBase(void) { return m_EventBase; }
|
||||
|
||||
/** Returns the LibEvent handle for DNS lookups. */
|
||||
evdns_base * GetDNSBase(void) { return m_DNSBase; }
|
||||
|
||||
/** Removes the specified hostname lookup from m_HostnameLookups.
|
||||
Used by the underlying lookup implementation when the lookup is finished. */
|
||||
void RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup);
|
||||
|
||||
/** Removes the specified IP lookup from m_IPLookups.
|
||||
Used by the underlying lookup implementation when the lookup is finished. */
|
||||
void RemoveIPLookup(const cIPLookup * a_IPLookup);
|
||||
|
||||
/** Adds the specified link to m_Connections.
|
||||
Used by the underlying link implementation when a new link is created. */
|
||||
void AddLink(cTCPLinkImplPtr a_Link);
|
||||
|
||||
/** Removes the specified link from m_Connections.
|
||||
Used by the underlying link implementation when the link is closed / errored. */
|
||||
void RemoveLink(const cTCPLinkImpl * a_Link);
|
||||
|
||||
/** Adds the specified link to m_Servers.
|
||||
Used by the underlying server handle implementation when a new listening server is created.
|
||||
Only servers that succeed in listening are added. */
|
||||
void AddServer(cServerHandleImplPtr a_Server);
|
||||
|
||||
/** Removes the specified server from m_Servers.
|
||||
Used by the underlying server handle implementation when the server is closed. */
|
||||
void RemoveServer(const cServerHandleImpl * a_Server);
|
||||
|
||||
protected:
|
||||
|
||||
/** The main LibEvent container for driving the event loop. */
|
||||
event_base * m_EventBase;
|
||||
|
||||
/** The LibEvent handle for doing DNS lookups. */
|
||||
evdns_base * m_DNSBase;
|
||||
|
||||
/** Container for all client connections, including ones with pending-connect. */
|
||||
cTCPLinkImplPtrs m_Connections;
|
||||
|
||||
/** Container for all servers that are currently active. */
|
||||
cServerHandleImplPtrs m_Servers;
|
||||
|
||||
/** Container for all pending hostname lookups. */
|
||||
cHostnameLookupPtrs m_HostnameLookups;
|
||||
|
||||
/** Container for all pending IP lookups. */
|
||||
cIPLookupPtrs m_IPLookups;
|
||||
|
||||
/** Mutex protecting all containers against multithreaded access. */
|
||||
cCriticalSection m_CS;
|
||||
|
||||
|
||||
/** Initializes the LibEvent internals. */
|
||||
cNetworkSingleton(void);
|
||||
|
||||
/** Converts LibEvent-generated log events into log messages in MCS log. */
|
||||
static void LogCallback(int a_Severity, const char * a_Msg);
|
||||
|
||||
/** Implements the thread that runs LibEvent's event dispatcher loop. */
|
||||
static void RunEventLoop(cNetworkSingleton * a_Self);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,10 +6,13 @@ include_directories(${CMAKE_SOURCE_DIR}/src/)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/lib/libevent/include)
|
||||
|
||||
add_definitions(-DTEST_GLOBALS=1)
|
||||
|
||||
# Create a single Network library that contains all the networking code:
|
||||
add_library(Network
|
||||
${CMAKE_SOURCE_DIR}/src/OSSupport/Network.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/OSSupport/CriticalSection.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/OSSupport/Event.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/OSSupport/Network.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/OSSupport/NetworkSingleton.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/StringUtils.cpp
|
||||
)
|
||||
|
||||
@ -18,12 +21,20 @@ if (MSVC)
|
||||
target_link_libraries(Network ws2_32.lib)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
|
||||
# Define individual tests:
|
||||
|
||||
# Google: download the google.com frontpage using http client socket:
|
||||
add_executable(Google-exe Google.cpp)
|
||||
target_link_libraries(Google-exe Network)
|
||||
add_test(NAME Google-test COMMAND Google-exe)
|
||||
|
||||
# EchoServer: Listen on port 9876, echo everything back:
|
||||
add_executable(EchoServer EchoServer.cpp)
|
||||
target_link_libraries(EchoServer Network)
|
||||
|
||||
# NameLookup: Lookup hostname-to-IP and IP-to-hostname:
|
||||
add_executable(NameLookup NameLookup.cpp)
|
||||
target_link_libraries(NameLookup Network)
|
||||
|
Loading…
Reference in New Issue
Block a user