diff options
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | CMake/AddDependencies.cmake | 1 | ||||
m--------- | lib/asio | 0 | ||||
-rw-r--r-- | src/Bindings/ManualBindings_Network.cpp | 4 | ||||
-rw-r--r-- | src/Globals.h | 2 | ||||
-rw-r--r-- | src/OSSupport/HostnameLookup.cpp | 121 | ||||
-rw-r--r-- | src/OSSupport/HostnameLookup.h | 21 | ||||
-rw-r--r-- | src/OSSupport/IPLookup.cpp | 4 | ||||
-rw-r--r-- | src/OSSupport/Network.h | 2 | ||||
-rw-r--r-- | src/OSSupport/NetworkSingleton.cpp | 10 | ||||
-rw-r--r-- | src/OSSupport/NetworkSingleton.h | 10 | ||||
-rw-r--r-- | src/OSSupport/TCPLinkImpl.cpp | 2 | ||||
-rw-r--r-- | src/OSSupport/UDPEndpointImpl.cpp | 3 | ||||
-rw-r--r-- | tests/Network/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/Network/NameLookup.cpp | 4 |
15 files changed, 85 insertions, 104 deletions
diff --git a/.gitmodules b/.gitmodules index e167fe6d5..57f3c9779 100644 --- a/.gitmodules +++ b/.gitmodules @@ -66,3 +66,6 @@ [submodule "Tools/BlockTypePaletteGenerator/lib/lunajson"] path = Tools/BlockTypePaletteGenerator/lib/lunajson url = https://github.com/grafi-tt/lunajson.git +[submodule "lib/asio"] + path = lib/asio + url = https://github.com/chriskohlhoff/asio diff --git a/CMake/AddDependencies.cmake b/CMake/AddDependencies.cmake index 971a338cc..795940009 100644 --- a/CMake/AddDependencies.cmake +++ b/CMake/AddDependencies.cmake @@ -49,6 +49,7 @@ function(link_dependencies TARGET) # Add required includes: target_include_directories( ${TARGET} SYSTEM PRIVATE + lib/asio/asio/include lib/mbedtls/include lib/TCLAP/include lib # TODO fix files including zlib/x instead of x diff --git a/lib/asio b/lib/asio new file mode 160000 +Subproject efff0de89920eb66afead00dfd8bb8cf588ccee diff --git a/src/Bindings/ManualBindings_Network.cpp b/src/Bindings/ManualBindings_Network.cpp index 4a7dd2367..fb60e4e0a 100644 --- a/src/Bindings/ManualBindings_Network.cpp +++ b/src/Bindings/ManualBindings_Network.cpp @@ -169,7 +169,7 @@ static int tolua_cNetwork_HostnameToIP(lua_State * L) ASSERT(callbacks != nullptr); // Invalid callbacks would have resulted in GetStackValues() returning false // Try to look up: - bool res = cNetwork::HostnameToIP(host, std::make_shared<cLuaNameLookup>(host, std::move(callbacks))); + bool res = cNetwork::HostnameToIP(host, std::make_unique<cLuaNameLookup>(host, std::move(callbacks))); S.Push(res); return 1; } @@ -205,7 +205,7 @@ static int tolua_cNetwork_IPToHostname(lua_State * L) ASSERT(callbacks != nullptr); // Invalid callbacks would have resulted in GetStackValues() returning false // Try to look up: - bool res = cNetwork::IPToHostName(ip, std::make_shared<cLuaNameLookup>(ip, std::move(callbacks))); + bool res = cNetwork::IPToHostName(ip, std::make_unique<cLuaNameLookup>(ip, std::move(callbacks))); S.Push(res); return 1; } diff --git a/src/Globals.h b/src/Globals.h index 114991129..2523a4304 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -57,7 +57,7 @@ #include <stdlib.h> #include <crtdbg.h> #define DEBUG_CLIENTBLOCK new(_CLIENT_BLOCK, __FILE__, __LINE__) - #define new DEBUG_CLIENTBLOCK + // #define new DEBUG_CLIENTBLOCK // For some reason this works magically - each "new X" gets replaced as "new(_CLIENT_BLOCK, "file", line) X" // The CRT has a definition for this operator new that stores the debugging info for leak-finding later. #endif diff --git a/src/OSSupport/HostnameLookup.cpp b/src/OSSupport/HostnameLookup.cpp index d86430d83..ee9610f63 100644 --- a/src/OSSupport/HostnameLookup.cpp +++ b/src/OSSupport/HostnameLookup.cpp @@ -15,104 +15,85 @@ //////////////////////////////////////////////////////////////////////////////// // cHostnameLookup: -cHostnameLookup::cHostnameLookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks): - m_Callbacks(std::move(a_Callbacks)), - m_Hostname(a_Hostname) +void cHostnameLookup::Lookup( + const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks) { -} - - - - - -void cHostnameLookup::Lookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks) -{ - // 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().async_resolve( + a_Hostname, "", + [Callbacks = std::move(a_Callbacks)](const auto & a_Error, const auto & a_Results) + { + // If an error has occurred, notify the error callback: + if (a_Error) + { + Callbacks->OnError(a_Error.value(), a_Error.message()); + return; + } - // 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); - }); + Callback(*Callbacks.get(), a_Results); + } + ); } -void cHostnameLookup::Callback(int a_ErrCode, addrinfo * a_Addr) +void cHostnameLookup::Callback(cNetwork::cResolveNameCallbacks & a_Callbacks, const asio::ip::tcp::resolver::results_type & a_Addr) { - // If an error has occurred, notify the error callback: - if (a_ErrCode != 0) - { - m_Callbacks->OnError(a_ErrCode, ErrorString(a_ErrCode)); - return; - } - // Call the success handler for each entry received: bool HasResolved = false; - addrinfo * OrigAddr = a_Addr; - for (;a_Addr != nullptr; a_Addr = a_Addr->ai_next) + + for (const auto & Addr : a_Addr) { - char IP[128]; - switch (a_Addr->ai_family) + const auto & Endpoint = Addr.endpoint(); + const auto & Address = Endpoint.address(); + const auto & Hostname = Addr.host_name(); + + if (Address.is_v4()) { - case AF_INET: // IPv4 + const auto sin = + reinterpret_cast<const sockaddr_in *>(Endpoint.data()); + if (!a_Callbacks.OnNameResolvedV4(Hostname, sin)) { - sockaddr_in * sin = reinterpret_cast<sockaddr_in *>(a_Addr->ai_addr); - 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; - continue; - } - evutil_inet_ntop(AF_INET, &(sin->sin_addr), IP, sizeof(IP)); - break; + // Callback indicated that the IP shouldn't be serialized to + // a string, just continue with the next address: + HasResolved = true; + continue; } - case AF_INET6: // IPv6 - { - sockaddr_in6 * sin = reinterpret_cast<sockaddr_in6 *>(a_Addr->ai_addr); - 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; - continue; - } - evutil_inet_ntop(AF_INET6, &(sin->sin6_addr), IP, sizeof(IP)); - break; - } - default: + } + else if (Address.is_v6()) + { + const auto sin = + reinterpret_cast<const sockaddr_in6 *>(Endpoint.data()); + if (!a_Callbacks.OnNameResolvedV6(Hostname, sin)) { - // Unknown address family, handle as if this entry wasn't received - continue; // for (a_Addr) + // Callback indicated that the IP shouldn't be serialized to + // a string, just continue with the next address: + HasResolved = true; + continue; } } - m_Callbacks->OnNameResolved(m_Hostname, IP); + else + { + // Unknown address family, handle as if this entry wasn't + // received + continue; // for (a_Addr) + } + a_Callbacks.OnNameResolved(Hostname, Address.to_string()); HasResolved = true; } // for (a_Addr) // If only unsupported families were reported, call the Error handler: if (!HasResolved) { - m_Callbacks->OnError(EAI_NONAME, ErrorString(EAI_NONAME)); + a_Callbacks.OnError(EAI_NONAME, ErrorString(EAI_NONAME)); } else { - m_Callbacks->OnFinished(); + a_Callbacks.OnFinished(); } - freeaddrinfo(OrigAddr); } diff --git a/src/OSSupport/HostnameLookup.h b/src/OSSupport/HostnameLookup.h index 9189ef021..337100063 100644 --- a/src/OSSupport/HostnameLookup.h +++ b/src/OSSupport/HostnameLookup.h @@ -12,6 +12,7 @@ #pragma once #include "Network.h" +#include <asio/ip/tcp.hpp> @@ -24,23 +25,7 @@ public: /** Creates a lookup object and schedules the lookup. */ static void Lookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks); -protected: +private: - /** 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; - - void Callback(int a_ErrCode, struct addrinfo * a_Addr); + static void Callback(cNetwork::cResolveNameCallbacks & a_Callbacks, const asio::ip::tcp::resolver::results_type & a_Addr); }; -typedef std::shared_ptr<cHostnameLookup> cHostnameLookupPtr; -typedef std::vector<cHostnameLookupPtr> cHostnameLookupPtrs; - - - - - diff --git a/src/OSSupport/IPLookup.cpp b/src/OSSupport/IPLookup.cpp index f730110b9..066573a72 100644 --- a/src/OSSupport/IPLookup.cpp +++ b/src/OSSupport/IPLookup.cpp @@ -32,7 +32,7 @@ void cIPLookup::Lookup(const AString & a_IP, cNetwork::cResolveNameCallbacksPtr cIPLookupPtr Lookup{ new cIPLookup(a_IP, std::move(a_Callbacks)) }; // Cannot use std::make_shared here, constructor is not accessible // Note the Lookup object is owned solely by this lambda which is destroyed after it runs - cNetworkSingleton::Get().GetLookupThread().ScheduleLookup([=]() + /* cNetworkSingleton::Get().GetLookupThread().ScheduleLookup( */[=]() { sockaddr_storage sa; int salen = sizeof(sa); @@ -58,7 +58,7 @@ void cIPLookup::Lookup(const AString & a_IP, cNetwork::cResolveNameCallbacksPtr 0 ); Lookup->Callback(ErrCode, Hostname); - }); + }(); } diff --git a/src/OSSupport/Network.h b/src/OSSupport/Network.h index 8e3f20025..e6432cd15 100644 --- a/src/OSSupport/Network.h +++ b/src/OSSupport/Network.h @@ -297,7 +297,7 @@ public: Only called if there was no error reported. */ virtual void OnFinished(void) = 0; }; - typedef std::shared_ptr<cResolveNameCallbacks> cResolveNameCallbacksPtr; + typedef std::unique_ptr<cResolveNameCallbacks> cResolveNameCallbacksPtr; /** Queues a TCP connection to be made to the specified host. diff --git a/src/OSSupport/NetworkSingleton.cpp b/src/OSSupport/NetworkSingleton.cpp index e022f4fec..54842f358 100644 --- a/src/OSSupport/NetworkSingleton.cpp +++ b/src/OSSupport/NetworkSingleton.cpp @@ -16,7 +16,8 @@ cNetworkSingleton::cNetworkSingleton() : - m_HasTerminated(true) + m_HasTerminated(true), + m_Resolver(m_Context) { } @@ -47,7 +48,9 @@ cNetworkSingleton & cNetworkSingleton::Get(void) void cNetworkSingleton::Initialise(void) { // Start the lookup thread - m_LookupThread.Start(); + m_Context.restart(); + m_Context.get_executor().on_work_started(); + m_LookupThread = std::thread([this] { m_Context.run(); }); // Windows: initialize networking: #ifdef _WIN32 @@ -100,7 +103,8 @@ void cNetworkSingleton::Terminate(void) ASSERT(!m_HasTerminated); // Wait for the lookup thread to stop - m_LookupThread.Stop(); + m_Context.get_executor().on_work_finished(); + m_LookupThread.join(); // Wait for the LibEvent event loop to terminate: event_base_loopbreak(m_EventBase); diff --git a/src/OSSupport/NetworkSingleton.h b/src/OSSupport/NetworkSingleton.h index 2a2d0cef3..31347f4c1 100644 --- a/src/OSSupport/NetworkSingleton.h +++ b/src/OSSupport/NetworkSingleton.h @@ -14,6 +14,8 @@ #pragma once #include <event2/event.h> +#include <asio/ip/tcp.hpp> +#include <asio/io_context.hpp> #include "NetworkLookup.h" #include "CriticalSection.h" #include "Event.h" @@ -57,7 +59,7 @@ public: event_base * GetEventBase(void) { return m_EventBase; } /** Returns the thread used to perform hostname and IP lookups */ - cNetworkLookup & GetLookupThread() { return m_LookupThread; } + asio::ip::tcp::resolver & GetLookupThread() { return m_Resolver; } /** Adds the specified link to m_Connections. Used by the underlying link implementation when a new link is created. */ @@ -100,7 +102,11 @@ protected: cEvent m_StartupEvent; /** The thread on which hostname and ip address lookup is performed. */ - cNetworkLookup m_LookupThread; + std::thread m_LookupThread; + + asio::io_context m_Context; + + asio::ip::tcp::resolver m_Resolver; /** Converts LibEvent-generated log events into log messages in MCS log. */ diff --git a/src/OSSupport/TCPLinkImpl.cpp b/src/OSSupport/TCPLinkImpl.cpp index c93a1879d..6b8c7f677 100644 --- a/src/OSSupport/TCPLinkImpl.cpp +++ b/src/OSSupport/TCPLinkImpl.cpp @@ -138,7 +138,7 @@ cTCPLinkImplPtr cTCPLinkImpl::Connect(const AString & a_Host, UInt16 a_Port, cTC }; // Schedule the host query - cNetwork::HostnameToIP(a_Host, std::make_shared<cHostnameCallback>(res, a_Port)); + cNetwork::HostnameToIP(a_Host, std::make_unique<cHostnameCallback>(res, a_Port)); return res; } diff --git a/src/OSSupport/UDPEndpointImpl.cpp b/src/OSSupport/UDPEndpointImpl.cpp index 3f04dd4f5..14066a058 100644 --- a/src/OSSupport/UDPEndpointImpl.cpp +++ b/src/OSSupport/UDPEndpointImpl.cpp @@ -270,8 +270,7 @@ bool cUDPEndpointImpl::Send(const AString & a_Payload, const AString & a_Host, U if (evutil_parse_sockaddr_port(a_Host.c_str(), reinterpret_cast<sockaddr *>(&sa), &salen) != 0) { // a_Host is a hostname, we need to do a lookup first: - auto queue = std::make_shared<cUDPSendAfterLookup>(a_Payload, a_Port, m_MainSock, m_SecondarySock, m_IsMainSockIPv6); - return cNetwork::HostnameToIP(a_Host, queue); + return cNetwork::HostnameToIP(a_Host, std::make_unique<cUDPSendAfterLookup>(a_Payload, a_Port, m_MainSock, m_SecondarySock, m_IsMainSockIPv6)); } // a_Host is an IP address and has been parsed into "sa" diff --git a/tests/Network/CMakeLists.txt b/tests/Network/CMakeLists.txt index 8bbe6294d..00d5e2f21 100644 --- a/tests/Network/CMakeLists.txt +++ b/tests/Network/CMakeLists.txt @@ -55,6 +55,8 @@ add_library(Network ${Network_HDRS} ) +target_include_directories(Network SYSTEM PUBLIC ${CMAKE_SOURCE_DIR}/lib/asio/asio/include) + target_link_libraries(Network event_core event_extra fmt::fmt mbedtls) if(NOT WIN32) target_link_libraries(Network event_pthreads Threads::Threads) diff --git a/tests/Network/NameLookup.cpp b/tests/Network/NameLookup.cpp index 2904a0199..1ae6c3bbc 100644 --- a/tests/Network/NameLookup.cpp +++ b/tests/Network/NameLookup.cpp @@ -52,7 +52,7 @@ static void DoTest(void) // Look up google.com (has multiple IP addresses): LOGD("Network test: Looking up google.com"); - if (!cNetwork::HostnameToIP("google.com", std::make_shared<cFinishLookupCallbacks>(evtFinish))) + if (!cNetwork::HostnameToIP("google.com", std::make_unique<cFinishLookupCallbacks>(evtFinish))) { LOGWARNING("Cannot resolve google.com to IP"); abort(); @@ -63,7 +63,7 @@ static void DoTest(void) // Look up 8.8.8.8 (Google free DNS): LOGD("Network test: Looking up IP 8.8.8.8"); - if (!cNetwork::IPToHostName("8.8.8.8", std::make_shared<cFinishLookupCallbacks>(evtFinish))) + if (!cNetwork::IPToHostName("8.8.8.8", std::make_unique<cFinishLookupCallbacks>(evtFinish))) { LOGWARNING("Cannot resolve 8.8.8.8 to name"); abort(); |