summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/OSSupport/CMakeLists.txt3
-rw-r--r--src/OSSupport/GetAddressInfoError.h29
-rw-r--r--src/OSSupport/HostnameLookup.cpp68
-rw-r--r--src/OSSupport/HostnameLookup.h13
-rw-r--r--src/OSSupport/IPLookup.cpp91
-rw-r--r--src/OSSupport/IPLookup.h11
-rw-r--r--src/OSSupport/NetworkLookup.cpp63
-rw-r--r--src/OSSupport/NetworkLookup.h42
-rw-r--r--src/OSSupport/NetworkSingleton.cpp93
-rw-r--r--src/OSSupport/NetworkSingleton.h43
-rw-r--r--src/OSSupport/TCPLinkImpl.cpp86
11 files changed, 294 insertions, 248 deletions
diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index 22699f7cd..8e018425b 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -12,6 +12,7 @@ SET (SRCS
IPLookup.cpp
IsThread.cpp
NetworkInterfaceEnum.cpp
+ NetworkLookup.cpp
NetworkSingleton.cpp
ServerHandleImpl.cpp
StackTrace.cpp
@@ -24,11 +25,13 @@ SET (HDRS
Errors.h
Event.h
File.h
+ GetAddressInfoError.h
GZipFile.h
HostnameLookup.h
IPLookup.h
IsThread.h
Network.h
+ NetworkLookup.h
NetworkSingleton.h
Queue.h
ServerHandleImpl.h
diff --git a/src/OSSupport/GetAddressInfoError.h b/src/OSSupport/GetAddressInfoError.h
new file mode 100644
index 000000000..43869fb63
--- /dev/null
+++ b/src/OSSupport/GetAddressInfoError.h
@@ -0,0 +1,29 @@
+#pragma once
+
+
+
+/** Returns the readable form of a getaddressinfo type error code */
+inline AString ErrorString(int a_ErrorCode)
+{
+ // Note gai_strerror is not threadsafe on windows
+ #ifdef _WIN32
+ char ErrorStr[GAI_STRERROR_BUFFER_SIZE + 1];
+
+ int MsgLen = FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ nullptr,
+ a_ErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ ErrorStr,
+ sizeof(ErrorStr) - 1,
+ nullptr
+ );
+
+ return AString(ErrorStr, MsgLen);
+ #else
+ return gai_strerror(a_ErrorCode);
+ #endif
+}
+
diff --git a/src/OSSupport/HostnameLookup.cpp b/src/OSSupport/HostnameLookup.cpp
index 0944153be..867472e8c 100644
--- a/src/OSSupport/HostnameLookup.cpp
+++ b/src/OSSupport/HostnameLookup.cpp
@@ -5,8 +5,8 @@
#include "Globals.h"
#include "HostnameLookup.h"
-#include <event2/dns.h>
#include "NetworkSingleton.h"
+#include "GetAddressInfoError.h"
@@ -15,8 +15,9 @@
////////////////////////////////////////////////////////////////////////////////
// cHostnameLookup:
-cHostnameLookup::cHostnameLookup(cNetwork::cResolveNameCallbacksPtr a_Callbacks):
- m_Callbacks(a_Callbacks)
+cHostnameLookup::cHostnameLookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks):
+ m_Callbacks(a_Callbacks),
+ m_Hostname(a_Hostname)
{
}
@@ -24,43 +25,45 @@ cHostnameLookup::cHostnameLookup(cNetwork::cResolveNameCallbacksPtr a_Callbacks)
-void cHostnameLookup::Lookup(const AString & a_Hostname)
+void cHostnameLookup::Lookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks)
{
- // Store the hostname for the callback:
- m_Hostname = a_Hostname;
-
- // Start the lookup:
- // Note that we don't have to store the LibEvent lookup handle, LibEvent will free it on its own.
- evutil_addrinfo hints;
- memset(&hints, 0, sizeof(hints));
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_family = AF_UNSPEC;
- hints.ai_flags = EVUTIL_AI_CANONNAME;
- evdns_getaddrinfo(cNetworkSingleton::Get().GetDNSBase(), a_Hostname.c_str(), nullptr, &hints, Callback, this);
+ // Cannot use std::make_shared here, constructor is not accessible
+ cHostnameLookupPtr Lookup{ new cHostnameLookup(a_Hostname, std::move(a_Callbacks)) };
+
+ // Note the Lookup object is owned solely by this lambda which is destroyed after it runs
+ cNetworkSingleton::Get().GetLookupThread().ScheduleLookup([=]()
+ {
+ // Start the lookup:
+ addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_CANONNAME;
+
+ addrinfo * Result;
+ int ErrCode = getaddrinfo(Lookup->m_Hostname.c_str(), nullptr, &hints, &Result);
+
+ Lookup->Callback(ErrCode, Result);
+ });
}
-void cHostnameLookup::Callback(int a_ErrCode, evutil_addrinfo * a_Addr, void * a_Self)
+void cHostnameLookup::Callback(int a_ErrCode, addrinfo * a_Addr)
{
- // Get the Self class:
- cHostnameLookup * Self = reinterpret_cast<cHostnameLookup *>(a_Self);
- ASSERT(Self != nullptr);
-
// If an error has occurred, notify the error callback:
if (a_ErrCode != 0)
{
- Self->m_Callbacks->OnError(a_ErrCode, evutil_socket_error_to_string(a_ErrCode));
- cNetworkSingleton::Get().RemoveHostnameLookup(Self);
+ m_Callbacks->OnError(a_ErrCode, ErrorString(a_ErrCode));
return;
}
// Call the success handler for each entry received:
bool HasResolved = false;
- evutil_addrinfo * OrigAddr = a_Addr;
+ addrinfo * OrigAddr = a_Addr;
for (;a_Addr != nullptr; a_Addr = a_Addr->ai_next)
{
char IP[128];
@@ -69,7 +72,7 @@ void cHostnameLookup::Callback(int a_ErrCode, evutil_addrinfo * a_Addr, void * a
case AF_INET: // IPv4
{
sockaddr_in * sin = reinterpret_cast<sockaddr_in *>(a_Addr->ai_addr);
- if (!Self->m_Callbacks->OnNameResolvedV4(Self->m_Hostname, sin))
+ if (!m_Callbacks->OnNameResolvedV4(m_Hostname, sin))
{
// Callback indicated that the IP shouldn't be serialized to a string, just continue with the next address:
HasResolved = true;
@@ -81,7 +84,7 @@ void cHostnameLookup::Callback(int a_ErrCode, evutil_addrinfo * a_Addr, void * a
case AF_INET6: // IPv6
{
sockaddr_in6 * sin = reinterpret_cast<sockaddr_in6 *>(a_Addr->ai_addr);
- if (!Self->m_Callbacks->OnNameResolvedV6(Self->m_Hostname, sin))
+ if (!m_Callbacks->OnNameResolvedV6(m_Hostname, sin))
{
// Callback indicated that the IP shouldn't be serialized to a string, just continue with the next address:
HasResolved = true;
@@ -96,21 +99,20 @@ void cHostnameLookup::Callback(int a_ErrCode, evutil_addrinfo * a_Addr, void * a
continue; // for (a_Addr)
}
}
- Self->m_Callbacks->OnNameResolved(Self->m_Hostname, IP);
+ m_Callbacks->OnNameResolved(m_Hostname, IP);
HasResolved = true;
} // for (a_Addr)
// If only unsupported families were reported, call the Error handler:
if (!HasResolved)
{
- Self->m_Callbacks->OnError(DNS_ERR_NODATA, "The name does not resolve to any known address.");
+ m_Callbacks->OnError(EAI_NODATA, ErrorString(EAI_NODATA));
}
else
{
- Self->m_Callbacks->OnFinished();
+ m_Callbacks->OnFinished();
}
- evutil_freeaddrinfo(OrigAddr);
- cNetworkSingleton::Get().RemoveHostnameLookup(Self);
+ freeaddrinfo(OrigAddr);
}
@@ -125,9 +127,7 @@ bool cNetwork::HostnameToIP(
cNetwork::cResolveNameCallbacksPtr a_Callbacks
)
{
- auto Lookup = std::make_shared<cHostnameLookup>(a_Callbacks);
- cNetworkSingleton::Get().AddHostnameLookup(Lookup);
- Lookup->Lookup(a_Hostname);
+ cHostnameLookup::Lookup(a_Hostname, std::move(a_Callbacks));
return true;
}
diff --git a/src/OSSupport/HostnameLookup.h b/src/OSSupport/HostnameLookup.h
index d69f24707..559dfad5f 100644
--- a/src/OSSupport/HostnameLookup.h
+++ b/src/OSSupport/HostnameLookup.h
@@ -12,7 +12,6 @@
#pragma once
#include "Network.h"
-#include <event2/util.h>
@@ -22,21 +21,21 @@
class cHostnameLookup
{
public:
- /** Creates the lookup object. Doesn't start the lookup yet. */
- cHostnameLookup(cNetwork::cResolveNameCallbacksPtr a_Callbacks);
-
- /** Starts the lookup. */
- void Lookup(const AString & a_Hostname);
+ /** Creates a lookup object and schedules the lookup. */
+ static void Lookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks);
protected:
+ /** Creates the lookup object. Doesn't start the lookup yet. */
+ cHostnameLookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks);
+
/** 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);
+ void Callback(int a_ErrCode, struct addrinfo * a_Addr);
};
typedef SharedPtr<cHostnameLookup> cHostnameLookupPtr;
typedef std::vector<cHostnameLookupPtr> cHostnameLookupPtrs;
diff --git a/src/OSSupport/IPLookup.cpp b/src/OSSupport/IPLookup.cpp
index 2722d4722..7b543793d 100644
--- a/src/OSSupport/IPLookup.cpp
+++ b/src/OSSupport/IPLookup.cpp
@@ -5,8 +5,9 @@
#include "Globals.h"
#include "IPLookup.h"
-#include <event2/dns.h>
+#include <event2/util.h>
#include "NetworkSingleton.h"
+#include "GetAddressInfoError.h"
@@ -15,8 +16,9 @@
////////////////////////////////////////////////////////////////////////////////
// cIPLookup:
-cIPLookup::cIPLookup(cNetwork::cResolveNameCallbacksPtr a_Callbacks):
- m_Callbacks(a_Callbacks)
+cIPLookup::cIPLookup(const AString & a_IP, cNetwork::cResolveNameCallbacksPtr a_Callbacks):
+ m_Callbacks(a_Callbacks),
+ m_IP(a_IP)
{
ASSERT(a_Callbacks != nullptr);
}
@@ -25,68 +27,58 @@ cIPLookup::cIPLookup(cNetwork::cResolveNameCallbacksPtr a_Callbacks):
-bool cIPLookup::Lookup(const AString & a_IP)
+void cIPLookup::Lookup(const AString & a_IP, cNetwork::cResolveNameCallbacksPtr a_Callbacks)
{
- // Parse the IP address string into a sockaddr structure:
- m_IP = a_IP;
- sockaddr_storage sa;
- int salen = static_cast<int>(sizeof(sa));
- memset(&sa, 0, sizeof(sa));
- if (evutil_parse_sockaddr_port(a_IP.c_str(), reinterpret_cast<sockaddr *>(&sa), &salen) != 0)
- {
- LOGD("Failed to parse IP address \"%s\".", a_IP.c_str());
- return false;
- }
+ cIPLookupPtr Lookup{ new cIPLookup(a_IP, std::move(a_Callbacks)) }; // Cannot use std::make_shared here, constructor is not accessible
- // Call the proper resolver based on the address family:
- // Note that there's no need to store the evdns_request handle returned, LibEvent frees it on its own.
- switch (sa.ss_family)
+ // Note the Lookup object is owned solely by this lambda which is destroyed after it runs
+ cNetworkSingleton::Get().GetLookupThread().ScheduleLookup([=]()
{
- case AF_INET:
- {
- sockaddr_in * sa4 = reinterpret_cast<sockaddr_in *>(&sa);
- 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().GetDNSBase(), &(sa6->sin6_addr), 0, Callback, this);
- break;
- }
- default:
+ sockaddr_storage sa;
+ int salen = sizeof(sa);
+ memset(&sa, 0, sizeof(sa));
+
+ int ErrCode = evutil_parse_sockaddr_port(Lookup->m_IP.c_str(), reinterpret_cast<sockaddr *>(&sa), &salen);
+
+ if (ErrCode != 0)
{
- LOGWARNING("%s: Unknown address family: %d", __FUNCTION__, sa.ss_family);
- ASSERT(!"Unknown address family");
- return false;
+ LOGD("Failed to parse IP address \"%s\".", Lookup->m_IP.c_str());
+ Lookup->Callback(ErrCode, nullptr);
+ return;
}
- } // switch (address family)
- return true;
+
+ char Hostname[NI_MAXHOST];
+ char ServInfo[NI_MAXSERV];
+
+ ErrCode = getnameinfo(
+ reinterpret_cast<sockaddr *>(&sa),
+ static_cast<socklen_t>(salen),
+ Hostname, sizeof(Hostname),
+ ServInfo, sizeof(ServInfo),
+ 0
+ );
+ Lookup->Callback(ErrCode, Hostname);
+ });
}
-void cIPLookup::Callback(int a_Result, char a_Type, int a_Count, int a_Ttl, void * a_Addresses, void * a_Self)
+void cIPLookup::Callback(int a_Result, const char * a_Address)
{
- // Get the Self class:
- cIPLookup * Self = reinterpret_cast<cIPLookup *>(a_Self);
- ASSERT(Self != nullptr);
-
// Call the proper callback based on the event received:
- if ((a_Result != 0) || (a_Addresses == nullptr))
+ if ((a_Result != 0) || (a_Address == nullptr))
{
// An error has occurred, notify the error callback:
- Self->m_Callbacks->OnError(a_Result, evutil_socket_error_to_string(a_Result));
+ m_Callbacks->OnError(a_Result, ErrorString(a_Result));
}
else
{
// Call the success handler:
- Self->m_Callbacks->OnNameResolved(*(reinterpret_cast<char **>(a_Addresses)), Self->m_IP);
- Self->m_Callbacks->OnFinished();
+ m_Callbacks->OnNameResolved(a_Address, m_IP);
+ m_Callbacks->OnFinished();
}
- cNetworkSingleton::Get().RemoveIPLookup(Self);
}
@@ -101,14 +93,7 @@ bool cNetwork::IPToHostName(
cNetwork::cResolveNameCallbacksPtr a_Callbacks
)
{
- auto res = std::make_shared<cIPLookup>(a_Callbacks);
- cNetworkSingleton::Get().AddIPLookup(res);
- if (!res->Lookup(a_IP))
- {
- // Lookup failed early on, remove the object completely:
- cNetworkSingleton::Get().RemoveIPLookup(res.get());
- return false;
- }
+ cIPLookup::Lookup(a_IP, std::move(a_Callbacks));
return true;
}
diff --git a/src/OSSupport/IPLookup.h b/src/OSSupport/IPLookup.h
index af878cbf1..600ce0af2 100644
--- a/src/OSSupport/IPLookup.h
+++ b/src/OSSupport/IPLookup.h
@@ -21,12 +21,9 @@
class cIPLookup
{
public:
- /** Creates the lookup object. Doesn't start the lookup yet. */
- cIPLookup(cNetwork::cResolveNameCallbacksPtr a_Callbacks);
- /** Starts the lookup.
- Returns true if lookup started successfully, false on failure (invalid IP format etc.) */
- bool Lookup(const AString & a_IP);
+ /** Creates a lookup object and schedules the lookup. */
+ static void Lookup(const AString & a_IP, cNetwork::cResolveNameCallbacksPtr a_Callbacks);
protected:
@@ -36,9 +33,11 @@ protected:
/** The IP that was queried (needed for the callbacks). */
AString m_IP;
+ /** Creates the lookup object. Doesn't start the lookup yet. */
+ cIPLookup(const AString & a_IP, cNetwork::cResolveNameCallbacksPtr a_Callbacks);
/** Callback that is called by LibEvent when there's an event for the request. */
- static void Callback(int a_Result, char a_Type, int a_Count, int a_Ttl, void * a_Addresses, void * a_Self);
+ void Callback(int a_Result, const char * a_Address);
};
typedef SharedPtr<cIPLookup> cIPLookupPtr;
typedef std::vector<cIPLookupPtr> cIPLookupPtrs;
diff --git a/src/OSSupport/NetworkLookup.cpp b/src/OSSupport/NetworkLookup.cpp
new file mode 100644
index 000000000..5cd7ecfc4
--- /dev/null
+++ b/src/OSSupport/NetworkLookup.cpp
@@ -0,0 +1,63 @@
+
+// NetworkLookup.cpp
+
+// Implements the cNetworkLookup class representing an executor for asynchronous lookup tasks
+
+
+#include "Globals.h"
+#include "NetworkLookup.h"
+
+
+
+
+cNetworkLookup::cNetworkLookup() :
+ cIsThread("NetworkLookup")
+{
+}
+
+
+
+
+
+cNetworkLookup::~cNetworkLookup()
+{
+ Stop();
+}
+
+
+
+
+
+void cNetworkLookup::ScheduleLookup(std::function<void()> a_Lookup)
+{
+ m_WorkQueue.EnqueueItem(std::move(a_Lookup));
+}
+
+
+
+
+
+void cNetworkLookup::Stop()
+{
+ m_ShouldTerminate = true;
+ m_WorkQueue.Clear();
+ m_WorkQueue.EnqueueItem([](){}); // Dummy work to wake up the thread
+ cIsThread::Stop();
+}
+
+
+
+
+
+void cNetworkLookup::Execute()
+{
+ while (!m_ShouldTerminate)
+ {
+ // Execute the next task in the queue
+ auto Work = m_WorkQueue.DequeueItem();
+ Work();
+ }
+}
+
+
+
diff --git a/src/OSSupport/NetworkLookup.h b/src/OSSupport/NetworkLookup.h
new file mode 100644
index 000000000..e09062f4d
--- /dev/null
+++ b/src/OSSupport/NetworkLookup.h
@@ -0,0 +1,42 @@
+
+// NetworkLookup.h
+
+// Declares the cNetworkLookup class representing an executor for asynchronous lookup tasks
+
+#pragma once
+
+#include <functional>
+
+#include "IsThread.h"
+#include "Queue.h"
+
+
+
+
+
+class cNetworkLookup :
+ public cIsThread
+{
+public:
+
+ cNetworkLookup();
+ ~cNetworkLookup();
+
+ /** Schedule a lookup task for execution. */
+ void ScheduleLookup(std::function<void()> a_Lookup);
+
+ /** Cancels any scheduled lookups and joins the lookup thread. */
+ void Stop();
+
+protected:
+
+ /** Process the queue until the thread is stopped. */
+ virtual void Execute() override final;
+
+private:
+
+ /** The queue of lookup tasks waiting to be executed. */
+ cQueue<std::function<void()>> m_WorkQueue;
+};
+
+
diff --git a/src/OSSupport/NetworkSingleton.cpp b/src/OSSupport/NetworkSingleton.cpp
index 3a8dbbdc7..fde39807b 100644
--- a/src/OSSupport/NetworkSingleton.cpp
+++ b/src/OSSupport/NetworkSingleton.cpp
@@ -8,15 +8,7 @@
#include "NetworkSingleton.h"
#include <event2/thread.h>
#include <event2/bufferevent.h>
-#include <event2/dns.h>
#include <event2/listener.h>
-#include "IPLookup.h"
-#include "HostnameLookup.h"
-
-#ifdef ANDROID
- // For DNS server retrieval
- #include <sys/system_properties.h>
-#endif
@@ -53,6 +45,9 @@ cNetworkSingleton & cNetworkSingleton::Get(void)
void cNetworkSingleton::Initialise(void)
{
+ // Start the lookup thread
+ m_LookupThread.Start();
+
// Windows: initialize networking:
#ifdef _WIN32
WSADATA wsaData;
@@ -86,24 +81,6 @@ void cNetworkSingleton::Initialise(void)
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();
- }
-
- #ifdef ANDROID
- char PropertyBuffer[PROP_VALUE_MAX];
-
- __system_property_get("net.dns1", PropertyBuffer);
- evdns_base_nameserver_ip_add(m_DNSBase, PropertyBuffer);
-
- __system_property_get("net.dns2", PropertyBuffer);
- evdns_base_nameserver_ip_add(m_DNSBase, PropertyBuffer);
- #endif
-
// Create the event loop thread:
m_HasTerminated = false;
m_EventLoopThread = std::thread(RunEventLoop, this);
@@ -118,6 +95,9 @@ void cNetworkSingleton::Terminate(void)
{
ASSERT(!m_HasTerminated);
+ // Wait for the lookup thread to stop
+ m_LookupThread.Stop();
+
// Wait for the LibEvent event loop to terminate:
event_base_loopbreak(m_EventBase);
m_EventLoopThread.join();
@@ -127,12 +107,9 @@ void cNetworkSingleton::Terminate(void)
cCSLock Lock(m_CS);
m_Connections.clear();
m_Servers.clear();
- m_HostnameLookups.clear();
- m_IPLookups.clear();
}
// Free the underlying LibEvent objects:
- evdns_base_free(m_DNSBase, true);
event_base_free(m_EventBase);
libevent_global_shutdown();
@@ -189,64 +166,6 @@ void cNetworkSingleton::SignalizeStartup(evutil_socket_t a_Socket, short a_Event
-void cNetworkSingleton::AddHostnameLookup(cHostnameLookupPtr a_HostnameLookup)
-{
- ASSERT(!m_HasTerminated);
- cCSLock Lock(m_CS);
- m_HostnameLookups.push_back(a_HostnameLookup);
-}
-
-
-
-
-
-void cNetworkSingleton::RemoveHostnameLookup(const cHostnameLookup * a_HostnameLookup)
-{
- ASSERT(!m_HasTerminated);
- 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::AddIPLookup(cIPLookupPtr a_IPLookup)
-{
- ASSERT(!m_HasTerminated);
- cCSLock Lock(m_CS);
- m_IPLookups.push_back(a_IPLookup);
-}
-
-
-
-
-
-void cNetworkSingleton::RemoveIPLookup(const cIPLookup * a_IPLookup)
-{
- ASSERT(!m_HasTerminated);
- 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)
{
ASSERT(!m_HasTerminated);
diff --git a/src/OSSupport/NetworkSingleton.h b/src/OSSupport/NetworkSingleton.h
index 3c8f5f660..0b815af43 100644
--- a/src/OSSupport/NetworkSingleton.h
+++ b/src/OSSupport/NetworkSingleton.h
@@ -13,8 +13,10 @@
#pragma once
+#include <atomic>
#include <event2/event.h>
#include "Network.h"
+#include "NetworkLookup.h"
#include "CriticalSection.h"
#include "Event.h"
@@ -24,19 +26,12 @@
// fwd:
struct event_base;
-struct evdns_base;
class cTCPLinkImpl;
typedef SharedPtr<cTCPLinkImpl> cTCPLinkImplPtr;
typedef std::vector<cTCPLinkImplPtr> cTCPLinkImplPtrs;
class cServerHandleImpl;
typedef SharedPtr<cServerHandleImpl> cServerHandleImplPtr;
typedef std::vector<cServerHandleImplPtr> cServerHandleImplPtrs;
-class cHostnameLookup;
-typedef SharedPtr<cHostnameLookup> cHostnameLookupPtr;
-typedef std::vector<cHostnameLookupPtr> cHostnameLookupPtrs;
-class cIPLookup;
-typedef SharedPtr<cIPLookup> cIPLookupPtr;
-typedef std::vector<cIPLookupPtr> cIPLookupPtrs;
@@ -63,24 +58,8 @@ public:
/** 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; }
-
- /** Adds the specified hostname lookup to m_HostnameLookups.
- Used by the underlying lookup implementation when a new lookup is initiated. */
- void AddHostnameLookup(cHostnameLookupPtr a_HostnameLookup);
-
- /** 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);
-
- /** Adds the specified IP lookup to M_IPLookups.
- Used by the underlying lookup implementation when a new lookup is initiated. */
- void AddIPLookup(cIPLookupPtr a_IPLookup);
-
- /** 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);
+ /** Returns the thread used to perform hostname and IP lookups */
+ cNetworkLookup & GetLookupThread() { return m_LookupThread; }
/** Adds the specified link to m_Connections.
Used by the underlying link implementation when a new link is created. */
@@ -104,26 +83,17 @@ 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;
/** Set to true if Terminate has been called. */
- volatile bool m_HasTerminated;
+ std::atomic<bool> m_HasTerminated;
/** The thread in which the main LibEvent loop runs. */
std::thread m_EventLoopThread;
@@ -131,6 +101,9 @@ protected:
/** Event that is signalled once the startup is finished and the LibEvent loop is running. */
cEvent m_StartupEvent;
+ /** The thread on which hostname and ip address lookup is performed. */
+ cNetworkLookup m_LookupThread;
+
/** Converts LibEvent-generated log events into log messages in MCS log. */
static void LogCallback(int a_Severity, const char * a_Msg);
diff --git a/src/OSSupport/TCPLinkImpl.cpp b/src/OSSupport/TCPLinkImpl.cpp
index 47be99a48..06eff9b09 100644
--- a/src/OSSupport/TCPLinkImpl.cpp
+++ b/src/OSSupport/TCPLinkImpl.cpp
@@ -70,41 +70,75 @@ cTCPLinkImplPtr cTCPLinkImpl::Connect(const AString & a_Host, UInt16 a_Port, cTC
res->m_Callbacks->OnLinkCreated(res);
res->Enable(res);
- // If a_Host is an IP address, schedule a connection immediately:
- sockaddr_storage sa;
- int salen = static_cast<int>(sizeof(sa));
- if (evutil_parse_sockaddr_port(a_Host.c_str(), reinterpret_cast<sockaddr *>(&sa), &salen) == 0)
+ // Callback to connect after performing lookup:
+ class cHostnameCallback :
+ public cNetwork::cResolveNameCallbacks
{
- // Insert the correct port:
- if (sa.ss_family == AF_INET6)
+ cTCPLinkImplPtr m_Link;
+ UInt16 m_Port;
+ bool m_IsConnecting;
+
+ public:
+
+ cHostnameCallback(cTCPLinkImplPtr a_Link, UInt16 a_ConnectPort):
+ m_Link(std::move(a_Link)),
+ m_Port(a_ConnectPort),
+ m_IsConnecting(false)
{
- reinterpret_cast<sockaddr_in6 *>(&sa)->sin6_port = htons(a_Port);
}
- else
+
+ void DoConnect(const sockaddr * a_IP, int size)
{
- reinterpret_cast<sockaddr_in *>(&sa)->sin_port = htons(a_Port);
+ // Make sure connect is only completed once
+ if (!m_IsConnecting)
+ {
+ int ErrCode = bufferevent_socket_connect(m_Link->m_BufferEvent, a_IP, size);
+ if (ErrCode == 0)
+ {
+ m_IsConnecting = true;
+ }
+ else
+ {
+ m_Link->GetCallbacks()->OnError(ErrCode, evutil_socket_error_to_string(ErrCode));
+ }
+ }
}
- // Queue the connect request:
- if (bufferevent_socket_connect(res->m_BufferEvent, reinterpret_cast<sockaddr *>(&sa), salen) == 0)
+ virtual bool OnNameResolvedV4(const AString & a_Name, const sockaddr_in * a_IP) override
{
- // Success
- return res;
+ sockaddr_in Addr = *a_IP;
+ Addr.sin_port = htons(m_Port);
+ DoConnect(reinterpret_cast<const sockaddr *>(&Addr), sizeof(Addr));
+ return false; // Don't care about recieving ip as string
}
- // Failure
- cNetworkSingleton::Get().RemoveLink(res.get());
- return nullptr;
- }
- // a_Host is a hostname, connect after a lookup:
- if (bufferevent_socket_connect_hostname(res->m_BufferEvent, cNetworkSingleton::Get().GetDNSBase(), AF_UNSPEC, a_Host.c_str(), a_Port) == 0)
- {
- // Success
- return res;
- }
- // Failure
- cNetworkSingleton::Get().RemoveLink(res.get());
- return nullptr;
+ virtual bool OnNameResolvedV6(const AString & a_Name, const sockaddr_in6 * a_IP) override
+ {
+ sockaddr_in6 Addr = *a_IP;
+ Addr.sin6_port = htons(m_Port);
+ DoConnect(reinterpret_cast<const sockaddr *>(&Addr), sizeof(Addr));
+ return false; // Don't care about recieving ip as string
+ }
+
+ virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override
+ {
+ m_Link->GetCallbacks()->OnError(a_ErrorCode, a_ErrorMsg);
+ cNetworkSingleton::Get().RemoveLink(m_Link.get());
+ }
+
+ // Don't need to do anything for these
+ virtual void OnFinished() override
+ {
+ }
+
+ virtual void OnNameResolved(const AString & a_Name, const AString & a_IP) override
+ {
+ }
+ };
+
+ // Schedule the host query
+ cNetwork::HostnameToIP(a_Host, std::make_shared<cHostnameCallback>(res, a_Port));
+ return res;
}