diff options
author | Mattes D <github@xoft.cz> | 2015-01-17 23:33:59 +0100 |
---|---|---|
committer | Mattes D <github@xoft.cz> | 2015-01-22 20:13:00 +0100 |
commit | d3076a3e1664c6a6e7c0d4cf24ac4335bb0a3899 (patch) | |
tree | 646bd5529f803e448b6eec6c9bac3be8d8f68a94 | |
parent | cNetwork: Fixed WSAStartup()-not-called error in Listen(). (diff) | |
download | cuberite-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.txt | 2 | ||||
-rw-r--r-- | src/OSSupport/Network.cpp | 334 | ||||
-rw-r--r-- | src/OSSupport/NetworkSingleton.cpp | 281 | ||||
-rw-r--r-- | src/OSSupport/NetworkSingleton.h | 138 | ||||
-rw-r--r-- | tests/Network/CMakeLists.txt | 13 |
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) |