From 072fdf348826db6bc75207540c55e8e275227516 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 20 May 2020 19:59:46 +0100 Subject: PoC: C++ ASIO --- src/OSSupport/HostnameLookup.cpp | 121 ++++++++++++++++--------------------- src/OSSupport/HostnameLookup.h | 21 +------ src/OSSupport/IPLookup.cpp | 4 +- src/OSSupport/Network.h | 2 +- src/OSSupport/NetworkSingleton.cpp | 10 ++- src/OSSupport/NetworkSingleton.h | 10 ++- src/OSSupport/TCPLinkImpl.cpp | 2 +- src/OSSupport/UDPEndpointImpl.cpp | 3 +- 8 files changed, 74 insertions(+), 99 deletions(-) (limited to 'src/OSSupport') 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(Endpoint.data()); + if (!a_Callbacks.OnNameResolvedV4(Hostname, sin)) { - sockaddr_in * sin = reinterpret_cast(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(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(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 @@ -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 cHostnameLookupPtr; -typedef std::vector 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 cResolveNameCallbacksPtr; + typedef std::unique_ptr 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 +#include +#include #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(res, a_Port)); + cNetwork::HostnameToIP(a_Host, std::make_unique(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(&sa), &salen) != 0) { // a_Host is a hostname, we need to do a lookup first: - auto queue = std::make_shared(a_Payload, a_Port, m_MainSock, m_SecondarySock, m_IsMainSockIPv6); - return cNetwork::HostnameToIP(a_Host, queue); + return cNetwork::HostnameToIP(a_Host, std::make_unique(a_Payload, a_Port, m_MainSock, m_SecondarySock, m_IsMainSockIPv6)); } // a_Host is an IP address and has been parsed into "sa" -- cgit v1.2.3