diff --git a/src/network/rest/http/HTTPClient.h b/src/network/rest/http/HTTPClient.h index 8ee234e8..c58fa76d 100644 --- a/src/network/rest/http/HTTPClient.h +++ b/src/network/rest/http/HTTPClient.h @@ -62,7 +62,7 @@ namespace network class HTTPClient : private Thread { public: /// Initializes a new instance of the HTTPClient class. - explicit HTTPClient(const std::string& address, uint16_t port) : + HTTPClient(const std::string& address, uint16_t port) : m_address(address), m_port(port), m_connection(nullptr), @@ -74,6 +74,13 @@ namespace network } /// 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; @@ -86,8 +93,12 @@ namespace network } /// Send HTTP request to HTTP server. - void request(HTTPPayload& request) + bool request(HTTPPayload& request) { + if (m_completed) { + return false; + } + asio::post(m_ioContext, [this, request]() { std::lock_guard guard(m_lock); { @@ -96,19 +107,28 @@ namespace network } } }); + + return true; } /// Opens connection to the network. bool open() { - m_running = true; + if (m_completed) { + return false; + } + return run(); } /// Closes connection to the network. void close() { - m_running = false; + if (m_completed) { + return; + } + + m_completed = true; m_ioContext.stop(); if (m_connection != nullptr) { @@ -124,36 +144,28 @@ namespace network /// virtual void entry() { - while (m_running) { - asio::ip::tcp::resolver resolver(m_ioContext); - auto endpoints = resolver.resolve(m_address, std::to_string(m_port)); + asio::ip::tcp::resolver resolver(m_ioContext); + auto endpoints = resolver.resolve(m_address, std::to_string(m_port)); - connect(endpoints); + connect(endpoints); - // the entry() call will block until all asynchronous operations - // have finished - m_ioContext.run(); - m_ioContext.restart(); + // the entry() call will block until all asynchronous operations + // have finished + m_ioContext.run(); + + if (m_connection != nullptr) { + m_connection->stop(); + delete m_connection; + m_connection = nullptr; } } /// Perform an asynchronous connect operation. void connect(asio::ip::basic_resolver_results& endpoints) { - std::lock_guard guard(m_lock); - { - if (m_connection != nullptr) { - m_connection->stop(); - delete m_connection; - m_connection = nullptr; - - m_socket = asio::ip::tcp::socket(m_ioContext); - } - - asio::connect(m_socket, endpoints); - m_connection = new ConnectionType(std::move(m_socket), m_requestHandler); - m_connection->start(); - } + asio::connect(m_socket, endpoints); + m_connection = new ConnectionType(std::move(m_socket), m_requestHandler); + m_connection->start(); } std::string m_address; @@ -163,7 +175,7 @@ namespace network ConnectionType* m_connection; - bool m_running = false; + bool m_completed = false; asio::io_context m_ioContext; asio::ip::tcp::socket m_socket; diff --git a/src/remote/RESTClient.cpp b/src/remote/RESTClient.cpp index eca06434..b1be6677 100644 --- a/src/remote/RESTClient.cpp +++ b/src/remote/RESTClient.cpp @@ -167,12 +167,16 @@ int RESTClient::send(const std::string& address, uint32_t port, const std::strin typedef network::rest::BasicRequestDispatcher RESTDispatcherType; RESTDispatcherType m_dispatcher(RESTClient::responseHandler); - HTTPClient client(address, port); + HTTPClient* client = nullptr; try { - if (!client.open()) + // setup HTTP client for authentication payload + client = new HTTPClient(address, port); + if (!client->open()) { + delete client; return ERRNO_SOCK_OPEN; - client.setHandler(m_dispatcher); + } + client->setHandler(m_dispatcher); // generate password SHA hash size_t size = password.size(); @@ -203,11 +207,12 @@ int RESTClient::send(const std::string& address, uint32_t port, const std::strin HTTPPayload httpPayload = HTTPPayload::requestPayload(HTTP_PUT, "/auth"); httpPayload.payload(request); - client.request(httpPayload); + client->request(httpPayload); // wait for response and parse if (wait()) { - client.close(); + client->close(); + delete client; return ERRNO_API_CALL_TIMEOUT; } @@ -222,19 +227,30 @@ int RESTClient::send(const std::string& address, uint32_t port, const std::strin token = rsp["token"].get(); } else { - client.close(); + client->close(); + delete client; return ERRNO_BAD_API_RESPONSE; } + client->close(); + delete client; + + // reset the HTTP client and setup for actual payload request + client = new HTTPClient(address, port); + if (!client->open()) + return ERRNO_SOCK_OPEN; + client->setHandler(m_dispatcher); + // send actual API request httpPayload = HTTPPayload::requestPayload(method, endpoint); httpPayload.headers.add("X-DVM-Auth-Token", token); httpPayload.payload(payload); - client.request(httpPayload); + client->request(httpPayload); // wait for response and parse if (wait()) { - client.close(); + client->close(); + delete client; return ERRNO_API_CALL_TIMEOUT; } @@ -247,10 +263,13 @@ int RESTClient::send(const std::string& address, uint32_t port, const std::strin } } - client.close(); + client->close(); + delete client; } catch (std::exception&) { - client.close(); + if (client != nullptr) { + delete client; + } return ERRNO_INTERNAL_ERROR; }