summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/OSSupport/Network.cpp136
-rw-r--r--src/OSSupport/Network.h11
-rw-r--r--tests/Network/CMakeLists.txt9
-rw-r--r--tests/Network/EchoServer.cpp19
-rw-r--r--tests/Network/Google.cpp23
-rw-r--r--tests/Network/NameLookup.cpp67
6 files changed, 256 insertions, 9 deletions
diff --git a/src/OSSupport/Network.cpp b/src/OSSupport/Network.cpp
index 0f532624d..8e2d060b4 100644
--- a/src/OSSupport/Network.cpp
+++ b/src/OSSupport/Network.cpp
@@ -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,6 +314,9 @@ 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);
};
@@ -296,6 +324,85 @@ protected:
////////////////////////////////////////////////////////////////////////////////
+// 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:
cTCPLinkImpl::cTCPLinkImpl(cTCPLink::cCallbacksPtr a_LinkCallbacks):
@@ -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[]
+}
+
+
+
+
diff --git a/src/OSSupport/Network.h b/src/OSSupport/Network.h
index 5cca511dc..3f60b03a7 100644
--- a/src/OSSupport/Network.h
+++ b/src/OSSupport/Network.h
@@ -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;
diff --git a/tests/Network/CMakeLists.txt b/tests/Network/CMakeLists.txt
index 8aae84590..a63ce7dfe 100644
--- a/tests/Network/CMakeLists.txt
+++ b/tests/Network/CMakeLists.txt
@@ -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)
diff --git a/tests/Network/EchoServer.cpp b/tests/Network/EchoServer.cpp
new file mode 100644
index 000000000..def064083
--- /dev/null
+++ b/tests/Network/EchoServer.cpp
@@ -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;
+}
+
+
+
+
diff --git a/tests/Network/Google.cpp b/tests/Network/Google.cpp
index 0aa52d025..de5f95e1f 100644
--- a/tests/Network/Google.cpp
+++ b/tests/Network/Google.cpp
@@ -1,11 +1,17 @@
-#include "Globals.h"
+// 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");
}
+
+
+
+
diff --git a/tests/Network/NameLookup.cpp b/tests/Network/NameLookup.cpp
new file mode 100644
index 000000000..daa72a3cb
--- /dev/null
+++ b/tests/Network/NameLookup.cpp
@@ -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;
+}
+
+
+
+