From 5cc61ceeda0ce2e81e46ece407b7d5ca634e5bc3 Mon Sep 17 00:00:00 2001
From: Hoop77 <p.badenhoop@gmx.de>
Date: Sat, 13 Jan 2018 01:27:30 +0100
Subject: [PATCH] added Resolver public class

---
 NetworkingLib/CMakeLists.txt           |   1 +
 NetworkingLib/include/DatagramSender.h |   4 +-
 NetworkingLib/include/Resolver.h       | 130 +++++++++++++++++++++++++
 NetworkingLib/include/Socket.h         |   2 +-
 NetworkingLib/test/Main.cpp            |  10 +-
 NetworkingLib/test/Test.cpp            |  38 ++++++++
 NetworkingLib/test/Test.h              |   2 +
 7 files changed, 181 insertions(+), 6 deletions(-)

diff --git a/NetworkingLib/CMakeLists.txt b/NetworkingLib/CMakeLists.txt
index 9ca3ec97..fb17fdbd 100644
--- a/NetworkingLib/CMakeLists.txt
+++ b/NetworkingLib/CMakeLists.txt
@@ -54,6 +54,7 @@ set(PUBLIC_HEADER_FILES
         include/DatagramSender.h
         include/Utils.h
         include/Error.h
+        include/Resolver.h
         ${CMAKE_CURRENT_BINARY_DIR}/Config.h)
 
 foreach(HEADER ${PUBLIC_HEADER_FILES})
diff --git a/NetworkingLib/include/DatagramSender.h b/NetworkingLib/include/DatagramSender.h
index b2bb8d63..f76dc690 100644
--- a/NetworkingLib/include/DatagramSender.h
+++ b/NetworkingLib/include/DatagramSender.h
@@ -47,7 +47,9 @@ public:
               const time::Duration & timeout)
     {
         if (sending)
-            throw error::Busy();
+            throw error::Busy{};
+
+        sending = true;
 
         // Use RAII to reset the sending flag when leaving this function.
         utils::RAIIObject sendingFlagReset{[this]
diff --git a/NetworkingLib/include/Resolver.h b/NetworkingLib/include/Resolver.h
index 30dc3c98..97b05fde 100644
--- a/NetworkingLib/include/Resolver.h
+++ b/NetworkingLib/include/Resolver.h
@@ -72,6 +72,136 @@ private:
 
 }
 
+class Resolver : public std::enable_shared_from_this<Resolver>
+{
+private:
+    struct PrivateTag
+    {
+    };
+
+public:
+    struct Endpoint
+    {
+        Endpoint(const std::string & ip, std::uint16_t port)
+            : ip(ip), port(port)
+        {}
+
+        std::string ip;
+        std::uint16_t port;
+    };
+
+    using Ptr = std::shared_ptr<Resolver>;
+
+    using Protocol = boost::asio::ip::tcp;
+    using UnderlyingResolver = internal::CloseableResolver<Protocol>;
+
+    using ResolveHandler = std::function<void(const error::ErrorCode & error, const std::vector<Endpoint> & endpoints)>;
+
+    static Ptr create(Networking & net)
+    {
+        return std::make_shared<Resolver>(PrivateTag{}, net);
+    }
+
+    Resolver(PrivateTag, Networking & net)
+        : net(net)
+          , resolver(net.getIoService())
+    {}
+
+    std::vector<Endpoint> resolve(const std::string & host,
+                                  const std::string & service,
+                                  const time::Duration & timeout)
+    {
+        if (resolving)
+            throw error::Busy{};
+
+        // Use RAII to reset the resolving flag when leaving this function.
+        utils::RAIIObject resolvingFlagReset{[this]
+                                             { resolving = false; }};
+
+        resolving = true;
+        resolver.open();
+
+        UnderlyingResolver::Query query{host, service};
+        UnderlyingResolver::Iterator endpointIterator;
+
+        auto resolveOperation = [this](auto && ... args)
+        { resolver.async_resolve(std::forward<decltype(args)>(args)...); };
+        closeable::timedOperation(net, resolveOperation, resolver, timeout, query, endpointIterator);
+
+        return endpointsFromIterator(endpointIterator);
+    }
+
+    void asyncResolve(const std::string & host,
+                      const std::string & service,
+                      const time::Duration & timeout,
+                      ResolveHandler handler)
+    {
+        if (resolving)
+            throw error::Busy{};
+
+        try
+        {
+            resolving = true;
+            resolver.open();
+
+            UnderlyingResolver::Query query{host, service};
+            auto endpointIterator = std::make_shared<UnderlyingResolver::Iterator>();
+
+            auto self = shared_from_this();
+
+            auto resolveOperation = [this](auto && ... args)
+            { resolver.async_resolve(std::forward<decltype(args)>(args)...); };
+
+            closeable::timedAsyncOperation(
+                net, resolveOperation, resolver, timeout,
+                [self, endpointIterator, handler](const auto & error)
+                {
+                    self->resolving = false;
+                    auto endpoints = self->endpointsFromIterator(*endpointIterator);
+                    handler(error, endpoints);
+                },
+                query, *endpointIterator);
+        }
+        catch (...)
+        {
+            resolving = false;
+            throw error::FailedOperation{};
+        }
+    }
+
+    void stop()
+    {
+        if (!resolving)
+            return;
+
+        closeable::Closer<UnderlyingResolver>::close(resolver);
+    }
+
+    bool isResolving() const noexcept
+    {
+        return resolving;
+    }
+
+private:
+    Networking & net;
+    UnderlyingResolver resolver;
+    std::atomic<bool> resolving;
+
+    std::vector<Endpoint> endpointsFromIterator(UnderlyingResolver::Iterator iterator)
+    {
+        std::vector<Endpoint> endpoints;
+
+        while (iterator != UnderlyingResolver::Iterator{})
+        {
+            endpoints.emplace_back(iterator->endpoint().address().to_string(),
+                                   iterator->endpoint().port());
+            iterator++;
+        }
+
+        return endpoints;
+    }
+};
+
 }
 
 #endif //NETWORKINGLIB_RESOLVER_H
diff --git a/NetworkingLib/include/Socket.h b/NetworkingLib/include/Socket.h
index ee27e258..47aa1a76 100644
--- a/NetworkingLib/include/Socket.h
+++ b/NetworkingLib/include/Socket.h
@@ -59,7 +59,7 @@ void asyncConnect(Networking & net,
     Resolver::Query query{host, std::to_string(port)};
     auto endpointIterator = std::make_shared<Resolver::Iterator>();
 
-    auto resolveOperation = [resolver](auto && ... args)
+    auto resolveOperation = [&resolver](auto && ... args)
     { resolver->async_resolve(std::forward<decltype(args)>(args)...); };
 
     closeable::timedAsyncOperation(
diff --git a/NetworkingLib/test/Main.cpp b/NetworkingLib/test/Main.cpp
index cc73322e..975a6707 100644
--- a/NetworkingLib/test/Main.cpp
+++ b/NetworkingLib/test/Main.cpp
@@ -20,9 +20,11 @@ int main(int argc, char ** argv)
 //    networking::test::testAsyncDatagramReceiver();
 //    std::cout << "\ntestPeriodicTimer\n\n";
 //    networking::test::testPeriodicTimer();
-    std::cout << "\ntestServiceClientAsyncCallTimeout\n\n";
-    networking::test::testServiceClientAsyncCallTimeout();
-    std::cout << "\ntestDatagramSenderAsyncSend\n\n";
-    networking::test::testDatagramSenderAsyncSend();
+//    std::cout << "\ntestServiceClientAsyncCallTimeout\n\n";
+//    networking::test::testServiceClientAsyncCallTimeout();
+//    std::cout << "\ntestDatagramSenderAsyncSend\n\n";
+//    networking::test::testDatagramSenderAsyncSend();
+    std::cout << "\ntestResolver\n\n";
+    networking::test::testResolver();
     return 0;
 }
\ No newline at end of file
diff --git a/NetworkingLib/test/Test.cpp b/NetworkingLib/test/Test.cpp
index acb5f53b..53c57135 100644
--- a/NetworkingLib/test/Test.cpp
+++ b/NetworkingLib/test/Test.cpp
@@ -285,3 +285,41 @@ void test::testDatagramSenderAsyncSend()
     while (running);
 }
 
+void test::testResolver()
+{
+    Networking net;
+
+    auto resolver = Resolver::create(net);
+
+    std::atomic<bool> running{true};
+    bool thrown{false};
+
+    auto endpoints = resolver->resolve("google.de", "http", 5s);
+    for (const auto & endpoint : endpoints)
+        std::cout << "ip: " << endpoint.ip << " port: " << endpoint.port << "\n";
+
+    resolver->asyncResolve(
+        "google.de", "http", 5s,
+        [&running](const auto & error, const auto & endpoints)
+        {
+            for (const auto & endpoint : endpoints)
+                std::cout << "ip: " << endpoint.ip << " port: " << endpoint.port << "\n";
+
+            running = false;
+        });
+
+    try
+    {
+        resolver->resolve("google.de", "http", 5s);
+    }
+    catch (const error::Busy & error)
+    {
+        thrown = true;
+    }
+
+    while (running);
+
+    if (thrown)
+        std::cout << "SUCCESS!\n";
+}
+
diff --git a/NetworkingLib/test/Test.h b/NetworkingLib/test/Test.h
index 1a3b97a7..f39fc156 100644
--- a/NetworkingLib/test/Test.h
+++ b/NetworkingLib/test/Test.h
@@ -26,6 +26,8 @@ void testServiceClientAsyncCallTimeout();
 
 void testDatagramSenderAsyncSend();
 
+void testResolver();
+
 }
 }
 
-- 
GitLab