cNetwork: Split cNetworkSingleton to a separate file.
This commit is contained in:
parent
ae29a82eba
commit
d3076a3e16
@ -13,6 +13,7 @@ SET (SRCS
|
|||||||
IsThread.cpp
|
IsThread.cpp
|
||||||
ListenThread.cpp
|
ListenThread.cpp
|
||||||
Network.cpp
|
Network.cpp
|
||||||
|
NetworkSingleton.cpp
|
||||||
Semaphore.cpp
|
Semaphore.cpp
|
||||||
Socket.cpp
|
Socket.cpp
|
||||||
SocketThreads.cpp
|
SocketThreads.cpp
|
||||||
@ -28,6 +29,7 @@ SET (HDRS
|
|||||||
IsThread.h
|
IsThread.h
|
||||||
ListenThread.h
|
ListenThread.h
|
||||||
Network.h
|
Network.h
|
||||||
|
NetworkSingleton.h
|
||||||
Queue.h
|
Queue.h
|
||||||
Semaphore.h
|
Semaphore.h
|
||||||
Socket.h
|
Socket.h
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "CriticalSection.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:
|
// Globals:
|
||||||
|
|
||||||
@ -357,7 +262,7 @@ cHostnameLookup::cHostnameLookup(const AString & a_Hostname, cNetwork::cResolveN
|
|||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
hints.ai_family = AF_UNSPEC;
|
hints.ai_family = AF_UNSPEC;
|
||||||
hints.ai_flags = EVUTIL_AI_CANONNAME;
|
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:
|
case AF_INET:
|
||||||
{
|
{
|
||||||
sockaddr_in * sa4 = reinterpret_cast<sockaddr_in *>(&sa);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
{
|
{
|
||||||
sockaddr_in6 * sa6 = reinterpret_cast<sockaddr_in6 *>(&sa);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
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):
|
cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks):
|
||||||
super(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)
|
m_Server(nullptr)
|
||||||
{
|
{
|
||||||
// Create the LibEvent handle, but don't assign a socket to it yet (will be assigned within Connect() method):
|
// 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):
|
cTCPLinkImpl::cTCPLinkImpl(evutil_socket_t a_Socket, cTCPLink::cCallbacksPtr a_LinkCallbacks, cServerHandleImpl * a_Server, const sockaddr * a_Address, int a_AddrLen):
|
||||||
super(a_LinkCallbacks),
|
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)
|
m_Server(a_Server)
|
||||||
{
|
{
|
||||||
// Update the endpoint addresses:
|
// 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:
|
// 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
|
// Success
|
||||||
return res;
|
return res;
|
||||||
@ -932,7 +837,7 @@ bool cServerHandleImpl::Listen(UInt16 a_Port)
|
|||||||
evutil_closesocket(MainSock);
|
evutil_closesocket(MainSock);
|
||||||
return false;
|
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 a secondary socket is required (WinXP dual-stack), create it here:
|
||||||
if (NeedsTwoSockets)
|
if (NeedsTwoSockets)
|
||||||
@ -943,7 +848,7 @@ bool cServerHandleImpl::Listen(UInt16 a_Port)
|
|||||||
{
|
{
|
||||||
if (evutil_make_socket_nonblocking(SecondSock) == 0)
|
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
|
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)
|
include_directories(${CMAKE_SOURCE_DIR}/lib/libevent/include)
|
||||||
|
|
||||||
add_definitions(-DTEST_GLOBALS=1)
|
add_definitions(-DTEST_GLOBALS=1)
|
||||||
|
|
||||||
|
# Create a single Network library that contains all the networking code:
|
||||||
add_library(Network
|
add_library(Network
|
||||||
${CMAKE_SOURCE_DIR}/src/OSSupport/Network.cpp
|
|
||||||
${CMAKE_SOURCE_DIR}/src/OSSupport/CriticalSection.cpp
|
${CMAKE_SOURCE_DIR}/src/OSSupport/CriticalSection.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/OSSupport/Event.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
|
${CMAKE_SOURCE_DIR}/src/StringUtils.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,12 +21,20 @@ if (MSVC)
|
|||||||
target_link_libraries(Network ws2_32.lib)
|
target_link_libraries(Network ws2_32.lib)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Define individual tests:
|
||||||
|
|
||||||
|
# Google: download the google.com frontpage using http client socket:
|
||||||
add_executable(Google-exe Google.cpp)
|
add_executable(Google-exe Google.cpp)
|
||||||
target_link_libraries(Google-exe Network)
|
target_link_libraries(Google-exe Network)
|
||||||
add_test(NAME Google-test COMMAND Google-exe)
|
add_test(NAME Google-test COMMAND Google-exe)
|
||||||
|
|
||||||
|
# EchoServer: Listen on port 9876, echo everything back:
|
||||||
add_executable(EchoServer EchoServer.cpp)
|
add_executable(EchoServer EchoServer.cpp)
|
||||||
target_link_libraries(EchoServer Network)
|
target_link_libraries(EchoServer Network)
|
||||||
|
|
||||||
|
# NameLookup: Lookup hostname-to-IP and IP-to-hostname:
|
||||||
add_executable(NameLookup NameLookup.cpp)
|
add_executable(NameLookup NameLookup.cpp)
|
||||||
target_link_libraries(NameLookup Network)
|
target_link_libraries(NameLookup Network)
|
||||||
|
Loading…
Reference in New Issue
Block a user