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