summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattes D <github@xoft.cz>2015-01-17 23:33:59 +0100
committerMattes D <github@xoft.cz>2015-01-22 20:13:00 +0100
commitd3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899 (patch)
tree646bd5529f803e448b6eec6c9bac3be8d8f68a94
parentcNetwork: Fixed WSAStartup()-not-called error in Listen(). (diff)
downloadcuberite-d3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899.tar
cuberite-d3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899.tar.gz
cuberite-d3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899.tar.bz2
cuberite-d3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899.tar.lz
cuberite-d3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899.tar.xz
cuberite-d3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899.tar.zst
cuberite-d3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899.zip
-rw-r--r--src/OSSupport/CMakeLists.txt2
-rw-r--r--src/OSSupport/Network.cpp334
-rw-r--r--src/OSSupport/NetworkSingleton.cpp281
-rw-r--r--src/OSSupport/NetworkSingleton.h138
-rw-r--r--tests/Network/CMakeLists.txt13
5 files changed, 442 insertions, 326 deletions
diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index 8454279fe..167afb784 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -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
diff --git a/src/OSSupport/Network.cpp b/src/OSSupport/Network.cpp
index decd111ea..359206632 100644
--- a/src/OSSupport/Network.cpp
+++ b/src/OSSupport/Network.cpp
@@ -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[]
-}
-
-
-
-
diff --git a/src/OSSupport/NetworkSingleton.cpp b/src/OSSupport/NetworkSingleton.cpp
new file mode 100644
index 000000000..552abad64
--- /dev/null
+++ b/src/OSSupport/NetworkSingleton.cpp
@@ -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[]
+}
+
+
+
+
diff --git a/src/OSSupport/NetworkSingleton.h b/src/OSSupport/NetworkSingleton.h
new file mode 100644
index 000000000..d5a4ec279
--- /dev/null
+++ b/src/OSSupport/NetworkSingleton.h
@@ -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);
+};
+
+
+
+
+
+
+
+
+
diff --git a/tests/Network/CMakeLists.txt b/tests/Network/CMakeLists.txt
index 9d0dcdc24..6bf291544 100644
--- a/tests/Network/CMakeLists.txt
+++ b/tests/Network/CMakeLists.txt
@@ -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)