/** * Digital Voice Modem - Host Software * GPLv2 Open Source. Use is subject to license terms. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * @package DVM / Host Software * */ /* * Copyright (C) 2023 by Bryan Biedenkapp N2PLL * * Permission is hereby granted, free of charge, to any person or organization * obtaining a copy of the software and accompanying documentation covered by * this license (the “Software”) to use, reproduce, display, distribute, execute, * and transmit the Software, and to prepare derivative works of the Software, and * to permit third-parties to whom the Software is furnished to do so, all subject * to the following: * * The copyright notices in the Software and this entire statement, including the * above license grant, this restriction and the following disclaimer, must be included * in all copies of the Software, in whole or in part, and all derivative works of the * Software, unless such copies or derivative works are solely in the form of * machine-executable object code generated by a source language processor. * * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE * DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if !defined(__REST_HTTP__HTTP_CLIENT_H__) #define __REST_HTTP__HTTP_CLIENT_H__ #include "Defines.h" #include "network/rest/http/ClientConnection.h" #include "network/rest/http/HTTPRequestHandler.h" #include "Thread.h" #include #include #include #include #include #include #include namespace network { namespace rest { namespace http { // --------------------------------------------------------------------------- // Class Declaration // This class implements top-level routines of the HTTP client. // --------------------------------------------------------------------------- template class ConnectionImpl = ClientConnection> class HTTPClient : private Thread { public: /// Initializes a new instance of the HTTPClient class. HTTPClient(const std::string& address, uint16_t port) : m_address(address), m_port(port), m_connection(nullptr), m_ioContext(), m_socket(m_ioContext), m_requestHandler() { /* stub */ } /// Initializes a copy instance of the HTTPClient class. HTTPClient(const HTTPClient&) = delete; /// Finalizes a instance of the HTTPClient class. ~HTTPClient() { if (m_connection != nullptr) { close(); } } /// HTTPClient& operator=(const HTTPClient&) = delete; /// Helper to set the HTTP request handlers. template void setHandler(Handler&& handler) { m_requestHandler = RequestHandlerType(std::forward(handler)); } /// Send HTTP request to HTTP server. bool request(HTTPPayload& request) { if (m_completed) { return false; } asio::post(m_ioContext, [this, request]() { std::lock_guard guard(m_lock); { if (m_connection != nullptr) { m_connection->send(request); } } }); return true; } /// Opens connection to the network. bool open() { if (m_completed) { return false; } return run(); } /// Closes connection to the network. void close() { if (m_completed) { return; } m_completed = true; m_ioContext.stop(); wait(); } private: /// virtual void entry() { if (m_completed) { return; } asio::ip::tcp::resolver resolver(m_ioContext); auto endpoints = resolver.resolve(m_address, std::to_string(m_port)); try { connect(endpoints); // the entry() call will block until all asynchronous operations // have finished m_ioContext.run(); } catch (std::exception&) { /* stub */ } if (m_connection != nullptr) { m_connection->stop(); } } /// Perform an asynchronous connect operation. void connect(asio::ip::basic_resolver_results& endpoints) { asio::connect(m_socket, endpoints); // enable SO_LINGER timeout 0 asio::socket_base::linger linger(true, 0); m_socket.set_option(linger); // enable TCP_NODELAY asio::ip::tcp::no_delay noDelay(true); m_socket.set_option(noDelay); m_connection = new_unique(ConnectionType, std::move(m_socket), m_requestHandler); m_connection->start(); } std::string m_address; uint16_t m_port; typedef ConnectionImpl ConnectionType; std::unique_ptr m_connection; bool m_completed = false; asio::io_context m_ioContext; asio::ip::tcp::socket m_socket; RequestHandlerType m_requestHandler; std::mutex m_lock; }; } // namespace http } // namespace rest } // namespace network #endif // __REST_HTTP__HTTP_CLIENT_H__