1
0

cNetwork: Implemented HostnameToIP lookups.

This commit is contained in:
Mattes D 2015-01-11 11:21:18 +01:00
parent c7335255ac
commit fde44cba08
6 changed files with 256 additions and 9 deletions

View File

@ -123,6 +123,27 @@ public:
////////////////////////////////////////////////////////////////////////////////
// Class definitions:
/** Holds information about an in-progress hostname 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;
/** Implements the cTCPLink details so that it can represent the single connection between two endpoints. */
class cTCPLinkImpl:
public cTCPLink
@ -214,7 +235,8 @@ typedef std::vector<cServerHandleImplPtr> cServerHandleImplPtrs;
class cNetworkSingleton
{
friend class cTCPLinkImpl;
friend class cHostnameLookup; // Needs access to m_DNSBase
friend class cTCPLinkImpl; // Needs access to m_EventBase and m_DNSBase
public:
/** Returns the singleton instance of this class */
@ -280,6 +302,9 @@ protected:
/** Container for all servers that are currently active. */
cServerHandleImplPtrs m_Servers;
/** Container for all pending hostname lookups. */
cHostnameLookupPtrs m_HostnameLookups;
/** Initializes the LibEvent internals. */
cNetworkSingleton(void);
@ -289,12 +314,94 @@ protected:
/** Implements the thread that runs LibEvent's event dispatcher loop. */
static void RunEventLoop(cNetworkSingleton * a_Self);
/** Removes the specified hostname lookup from m_HostnameLookups. */
void RemoveHostnameLookup(cHostnameLookup * a_HostnameLookup);
};
////////////////////////////////////////////////////////////////////////////////
// cHostnameLookup:
cHostnameLookup::cHostnameLookup(const AString & a_Hostname, cNetwork::cResolveNameCallbacksPtr a_Callbacks):
m_Callbacks(a_Callbacks),
m_Hostname(a_Hostname)
{
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().m_DNSBase, a_Hostname.c_str(), nullptr, &hints, Callback, this);
}
void cHostnameLookup::Callback(int a_ErrCode, struct evutil_addrinfo * a_Addr, void * a_Self)
{
// 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);
cNetworkSingleton::Get().RemoveHostnameLookup(Self);
return;
}
// Call the success handler for each entry received:
bool HasResolved = false;
for (;a_Addr != nullptr; a_Addr = a_Addr->ai_next)
{
char IP[128];
switch (a_Addr->ai_family)
{
case AF_INET: // IPv4
{
sockaddr_in * sin = reinterpret_cast<sockaddr_in *>(a_Addr->ai_addr);
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);
evutil_inet_ntop(AF_INET6, &(sin->sin6_addr), IP, sizeof(IP));
break;
}
default:
{
// Unknown address family, handle as error
continue;
}
}
Self->m_Callbacks->OnNameResolved(Self->m_Hostname, IP);
HasResolved = true;
}
// If only unsupported families were reported, call the Error handler:
if (!HasResolved)
{
Self->m_Callbacks->OnError(1);
}
else
{
Self->m_Callbacks->OnFinished();
}
cNetworkSingleton::Get().RemoveHostnameLookup(Self);
}
////////////////////////////////////////////////////////////////////////////////
// cTCPLinkImpl:
@ -716,9 +823,15 @@ bool cNetworkSingleton::HostnameToIP(
cNetwork::cResolveNameCallbacksPtr a_Callbacks
)
{
// TODO
ASSERT(!"Not implemented yet!");
return false;
try
{
m_HostnameLookups.push_back(std::make_shared<cHostnameLookup>(a_Hostname, a_Callbacks));
}
catch (...)
{
return false;
}
return true;
}
@ -765,3 +878,18 @@ void cNetworkSingleton::RunEventLoop(cNetworkSingleton * a_Self)
void cNetworkSingleton::RemoveHostnameLookup(cHostnameLookup * a_HostnameLookup)
{
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[]
}

View File

@ -148,11 +148,18 @@ public:
// Force a virtual destructor for all descendants:
virtual ~cResolveNameCallbacks() {}
/** Called when the hostname is successfully resolved into an IP address. */
/** Called when the hostname is successfully resolved into an IP address.
May be called multiple times if an address resolves to multiple addresses.
a_IP may be either an IPv4 or an IPv6 address with their proper formatting. */
virtual void OnNameResolved(const AString & a_Name, const AString & a_IP) = 0;
/** Called when an error is encountered while resolving. */
/** Called when an error is encountered while resolving.
If an error is reported, the OnFinished() callback is not called. */
virtual void OnError(int a_ErrorCode) = 0;
/** Called when all the addresses resolved have been reported via the OnNameResolved() callback.
Only called if there was no error reported. */
virtual void OnFinished(void) = 0;
};
typedef SharedPtr<cResolveNameCallbacks> cResolveNameCallbacksPtr;

View File

@ -8,7 +8,16 @@ include_directories(${CMAKE_SOURCE_DIR}/lib/libevent/include)
add_definitions(-DTEST_GLOBALS=1)
add_library(Network ${CMAKE_SOURCE_DIR}/src/OSSupport/Network.cpp ${CMAKE_SOURCE_DIR}/src/OSSupport/Event.cpp ${CMAKE_SOURCE_DIR}/src/StringUtils.cpp)
target_link_libraries(Network event_core event_extra)
if (MSVC)
target_link_libraries(Network ws2_32.lib)
endif()
add_executable(Google-exe Google.cpp)
target_link_libraries(Google-exe Network)
add_test(NAME Google-test COMMAND Google-exe)
add_executable(EchoServer EchoServer.cpp)
target_link_libraries(EchoServer Network)
add_executable(NameLookup NameLookup.cpp)
target_link_libraries(NameLookup Network)

View File

@ -0,0 +1,19 @@
// EchoServer.cpp
// Implements an Echo server using the LibEvent-based cNetwork API, as a test of that API
int main()
{
// TODO
return 0;
}

View File

@ -1,11 +1,17 @@
// Google.cpp
// Implements a HTTP download of the google's front page using the LibEvent-based cNetwork API
#include "Globals.h"
#include <thread>
#include "OSSupport/Event.h"
#include "OSSupport/Network.h"
/** Connect callbacks that send a HTTP GET request for google.com when connected. */
class cHTTPConnectCallbacks:
public cNetwork::cConnectCallbacks
@ -35,6 +41,9 @@ public:
};
/** cTCPLink callbacks that dump everything it received to the log. */
class cDumpCallbacks:
public cTCPLink::cCallbacks
@ -69,7 +78,11 @@ public:
};
int main() {
int main()
{
cEvent evtFinish;
LOGD("Network test: Connecting to google.com:80, reading front page via HTTP.");
@ -83,3 +96,7 @@ int main() {
evtFinish.Wait();
LOGD("Network test finished");
}

View File

@ -0,0 +1,67 @@
// NameLookup.cpp
// Implements a DNS name lookup using the LibEvent-based cNetwork API
#include "Globals.h"
#include <thread>
#include "OSSupport/Event.h"
#include "OSSupport/Network.h"
class cFinishLookupCallbacks:
public cNetwork::cResolveNameCallbacks
{
cEvent & m_Event;
virtual void OnNameResolved(const AString & a_Name, const AString & a_IP) override
{
LOGD("%s resolves to IP %s", a_Name.c_str(), a_IP.c_str());
}
virtual void OnError(int a_ErrorCode) override
{
LOGD("Error %d while performing lookup!", a_ErrorCode);
abort();
}
virtual void OnFinished(void) override
{
LOGD("Resolving finished.");
m_Event.Set();
}
public:
cFinishLookupCallbacks(cEvent & a_Event):
m_Event(a_Event)
{
}
};
int main()
{
cEvent evtFinish;
LOGD("Network test: Looking up google.com");
if (!cNetwork::HostnameToIP("google.com", std::make_shared<cFinishLookupCallbacks>(evtFinish)))
{
LOGWARNING("Cannot resolve google.com");
abort();
}
LOGD("Name lookup has been successfully queued");
evtFinish.Wait();
LOGD("Network test finished");
return 0;
}