mirror of
https://github.com/cuberite/cuberite.git
synced 2025-01-07 03:16:55 +08:00
PoC: C++ ASIO
This commit is contained in:
parent
99f8c44342
commit
072fdf3488
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||
|
@ -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
|
||||
|
1
lib/asio
Submodule
1
lib/asio
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit efff0de89920eb66afead00dfd8bb8cf588ccee4
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
Callback(*Callbacks.get(), a_Results);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cHostnameLookup::Lookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks)
|
||||
void cHostnameLookup::Callback(cNetwork::cResolveNameCallbacks & a_Callbacks, const asio::ip::tcp::resolver::results_type & a_Addr)
|
||||
{
|
||||
// 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, addrinfo * 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;
|
||||
}
|
||||
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:
|
||||
{
|
||||
// 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 if (Address.is_v6())
|
||||
{
|
||||
const auto sin =
|
||||
reinterpret_cast<const sockaddr_in6 *>(Endpoint.data());
|
||||
if (!a_Callbacks.OnNameResolvedV6(Hostname, sin))
|
||||
{
|
||||
// Callback indicated that the IP shouldn't be serialized to
|
||||
// a string, just continue with the next address:
|
||||
HasResolved = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
}();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user