diff --git a/include/opendht/dht_proxy_client.h b/include/opendht/dht_proxy_client.h index e855984a..9d6d51af 100644 --- a/include/opendht/dht_proxy_client.h +++ b/include/opendht/dht_proxy_client.h @@ -293,6 +293,7 @@ private: bool doCancelListen(const InfoHash& key, size_t token); + struct Listener; struct ListenState; enum class ListenMethod { LISTEN, @@ -301,11 +302,11 @@ private: }; /** * Send Listen with httpClient_ - * Return a Connection Id */ - uint16_t sendListen(const restinio::http_request_header_t header, - const ValueCallback &cb, const Value::Filter &filter, - const Sp &state, ListenMethod method = ListenMethod::LISTEN); + void sendListen(const restinio::http_request_header_t header, + const ValueCallback &cb, const Value::Filter &filter, + const Sp &state, Listener &listener, + ListenMethod method = ListenMethod::LISTEN); void doPut(const InfoHash&, Sp, DoneCallback, time_point created, bool permanent); @@ -322,9 +323,7 @@ private: */ void cancelAllOperations(); - std::string serverHost_; - std::string serverHostIp_; - uint16_t serverHostPort_; + std::pair serverHostService_; std::string pushClientId_; /* diff --git a/include/opendht/http.h b/include/opendht/http.h index 5f6e37d4..ad1585ef 100644 --- a/include/opendht/http.h +++ b/include/opendht/http.h @@ -28,24 +28,27 @@ namespace http { +using ConnectionId = unsigned int; + class Connection { public: - Connection(const uint16_t id, asio::ip::tcp::socket socket); + Connection(const ConnectionId id, asio::ip::tcp::socket socket); ~Connection(); - uint16_t id(); - void start(asio::ip::tcp::resolver::iterator &r_iter); + ConnectionId id(); bool is_open(); + bool is_v6(); void close(); private: friend class Client; - uint16_t id_; + ConnectionId id_; asio::ip::tcp::socket socket_; asio::streambuf request_; asio::streambuf response_; + asio::ip::tcp::endpoint endpoint_; }; /** @@ -98,32 +101,39 @@ private: class OPENDHT_PUBLIC Client { public: - Client(asio::io_context &ctx, std::string host, uint16_t port = 80, - std::shared_ptr logger = {}); + using HandlerCb = std::function; + using ConnectionCb = std::function)>; + + Client(asio::io_context &ctx, const std::string host, const std::string service = "80", + std::shared_ptr logger = {}, const bool resolve = true); asio::io_context& io_context(); void set_logger(std::shared_ptr logger); - void set_query_address(const std::string host, const uint16_t port); - bool active_connection(uint16_t conn_id); - void close_connection(uint16_t conn_id); + bool active_connection(ConnectionId conn_id); + void close_connection(ConnectionId conn_id); + + bool resolved(); + void async_resolve(const std::string host, const std::string service, HandlerCb cb = {}); + + void async_connect(ConnectionCb cb); std::string create_request(const restinio::http_request_header_t header, const restinio::http_header_fields_t header_fields, const restinio::http_connection_header_t connection, const std::string body); - uint16_t post_request(std::string request, - std::shared_ptr parser, - std::shared_ptr parser_s); + void async_request(std::shared_ptr conn, + std::string request, std::shared_ptr parser, + std::shared_ptr parser_s); private: std::shared_ptr create_connection(); void handle_connect(const asio::error_code &ec, asio::ip::tcp::resolver::iterator endpoint_it, - std::shared_ptr conn = {}); + std::shared_ptr conn = {}, HandlerCb cb = {}); void handle_resolve(const asio::error_code &ec, asio::ip::tcp::resolver::iterator endpoint_it, @@ -135,17 +145,19 @@ private: void handle_response(const asio::error_code &ec, std::shared_ptr conn = {}); - uint16_t port_; + std::string service_; std::string host_; // contains the io_context asio::ip::tcp::resolver resolver_; + // resolved endpoint + asio::ip::basic_resolver_results endpoints_; - uint16_t connId_ {1}; + ConnectionId connId_ {1}; /* * An association between an active connection and its context, a Request. */ - std::map requests_; + std::map requests_; std::shared_ptr logger_; }; diff --git a/src/dht_proxy_client.cpp b/src/dht_proxy_client.cpp index 585afcac..79ce1007 100644 --- a/src/dht_proxy_client.cpp +++ b/src/dht_proxy_client.cpp @@ -73,16 +73,15 @@ DhtProxyClient::DhtProxyClient() {} DhtProxyClient::DhtProxyClient(std::function signal, const std::string &serverHost, const std::string &pushClientId, std::shared_ptr logger): - serverHost_(serverHost), pushClientId_(pushClientId), loopSignal_(signal), + pushClientId_(pushClientId), loopSignal_(signal), logger_(logger) { // build http client - auto hostAndPort = splitPort(serverHost_); - serverHostIp_ = hostAndPort.first; - serverHostPort_ = std::atoi(hostAndPort.second.c_str()); - serverHostPort_ = serverHostPort_ == 0 ? 80 : serverHostPort_; + serverHostService_ = splitPort(serverHost); + serverHostService_.second = serverHostService_.second.empty() ? "80" : + serverHostService_.second; httpClient_ = std::make_unique(httpContext_, - serverHostIp_, serverHostPort_, logger); + serverHostService_.first, serverHostService_.second, logger); // run http client httpClientThread_ = std::thread([this](){ try { @@ -99,18 +98,14 @@ DhtProxyClient::DhtProxyClient(std::function signal, const std::string & logger_->e("[proxy:client] error starting io context"); } }); - - if (serverHost_.find("://") == std::string::npos) - serverHost_ = proxy::HTTP_PROTO + serverHost_; - - if (!serverHost_.empty()) + if (!serverHostService_.first.empty()) startProxy(); } void DhtProxyClient::confirmProxy() { - if (serverHost_.empty()) + if (serverHostService_.first.empty()) return; getConnectivityStatus(); } @@ -118,11 +113,11 @@ DhtProxyClient::confirmProxy() void DhtProxyClient::startProxy() { - if (serverHost_.empty()) + if (serverHostService_.first.empty()) return; if (logger_) - logger_->d("[proxy:client] staring proxy with %s", serverHost_.c_str()); + logger_->d("[proxy:client] staring proxy with %s", serverHostService_.first.c_str()); nextProxyConfirmationTimer_ = std::make_shared( httpContext_, std::chrono::steady_clock::now()); @@ -256,7 +251,7 @@ restinio::http_header_fields_t DhtProxyClient::initHeaderFields(){ restinio::http_header_fields_t header_fields; header_fields.append_field(restinio::http_field_t::host, - (serverHostIp_ + ":" + std::to_string(serverHostPort_)).c_str()); + (serverHostService_.first + ":" + serverHostService_.second).c_str()); header_fields.append_field(restinio::http_field_t::user_agent, "RESTinio client"); header_fields.append_field(restinio::http_field_t::accept, "*/*"); header_fields.append_field(restinio::http_field_t::content_type, "application/json"); @@ -279,7 +274,7 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, logger_->d(request.c_str()); struct GetContext { - GetCallback cb; + GetCallback cb; // wrapper DoneCallbackSimple donecb; // wrapper Value::Filter filter; std::atomic_bool ok {true}; @@ -288,6 +283,7 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, }; auto context = std::make_shared(); context->filter = w.empty() ? f : f.chain(w.getFilter()); + // keeping context data alive context->cb = [this, context, cb] (const std::vector>& values) -> bool { { @@ -332,7 +328,7 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, }; parser_s->on_body = [](http_parser *parser, const char *at, size_t length) -> int { auto context = static_cast(parser->data); - try{ + try { Json::Value json; std::string err; Json::CharReaderBuilder rbuilder; @@ -368,7 +364,11 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, } return 0; }; - httpClient_->post_request(request, parser, parser_s); + httpClient_->async_connect([this, request, parser, parser_s] + (std::shared_ptr conn) + { + httpClient_->async_request(conn, request, parser, parser_s); + }); } void @@ -503,7 +503,11 @@ DhtProxyClient::doPut(const InfoHash& key, Sp val, DoneCallback cb, time_ } return 0; }; - httpClient_->post_request(request, parser, parser_s); + httpClient_->async_connect([this, request, parser, parser_s] + (std::shared_ptr conn) + { + httpClient_->async_request(conn, request, parser, parser_s); + }); } /** @@ -594,105 +598,102 @@ DhtProxyClient::handleProxyStatus(const asio::error_code &ec, return; } } - auto serverHost = serverHost_; - try { - // A node can have a Ipv4 and a Ipv6. So, we need to retrieve all public ips - auto endpointStr = serverHost; - auto protocol = std::string(proxy::HTTP_PROTO); - auto protocolIdx = serverHost.find("://"); - if (protocolIdx != std::string::npos) { - protocol = endpointStr.substr(0, protocolIdx + 3); - endpointStr = endpointStr.substr(protocolIdx + 3); + // A node can have a Ipv4 and a Ipv6. So, we need to retrieve all public ips + httpClient_->async_resolve(serverHostService_.first, serverHostService_.second, + [this, infoState](const asio::error_code &ec){ + if (ec){ + logger_->e("[proxy:client] [status] error resolving: %s", ec.message().c_str()); + return; } - auto hostAndService = splitPort(endpointStr); - auto resolvedProxies = SockAddr::resolve(hostAndService.first, hostAndService.second); + // in all cases attempt to connect + httpClient_->async_connect([this, infoState](std::shared_ptr conn){ + try { + // make an http header + restinio::http_request_header_t header; + header.request_target("/"); + header.method(restinio::http_method_get()); + auto header_fields = this->initHeaderFields(); + auto request = httpClient_->create_request(header, header_fields, + restinio::http_connection_header_t::keep_alive, ""/*body*/); + if (logger_) + logger_->d("[proxy:client] [status] sending request:\n%s", request.c_str()); + // initalise the parser callback data + struct GetContext { + unsigned int family; + std::function cb; // wrapper + std::atomic_bool ok {true}; + std::shared_ptr infoState; + std::function proxyInfo; + std::shared_ptr logger; + }; + auto context = std::make_shared(); + context->infoState = infoState; + context->family = conn->is_v6() ? AF_INET6 : AF_INET; + context->proxyInfo = std::bind(&DhtProxyClient::onProxyInfos, this, + std::placeholders::_1, std::placeholders::_2); + // keeping context data alive + context->cb = [this, context](Json::Value infos){ + if (context->family == AF_INET) + context->infoState->ipv4++; + else if (context->family == AF_INET6) + context->infoState->ipv6++; + if (not context->infoState->cancel) + context->proxyInfo(infos, context->family); + }; + if (logger_) + context->logger = logger_; - for (const auto& resolvedProxy: resolvedProxies){ - auto server = resolvedProxy.toString(); - // make an http header - restinio::http_request_header_t header; - header.request_target("/"); - header.method(restinio::http_method_get()); - auto header_fields = this->initHeaderFields(); - auto request = httpClient_->create_request(header, header_fields, - restinio::http_connection_header_t::keep_alive, ""/*body*/); - if (logger_) - logger_->d("[proxy:client] [status] sending request:\n%s", request.c_str()); - // initalise the parser callback data - struct GetContext { - unsigned int family; - std::function cb; // wrapper - std::atomic_bool ok {true}; - std::shared_ptr infoState; - std::function proxyInfo; - std::shared_ptr logger; - }; - auto context = std::make_shared(); - context->infoState = infoState; - context->family = resolvedProxy.getFamily(); - context->proxyInfo = std::bind(&DhtProxyClient::onProxyInfos, this, - std::placeholders::_1, std::placeholders::_2); - // keeping context data alive - context->cb = [this, context](Json::Value infos){ - if (context->family == AF_INET) - context->infoState->ipv4++; - else if (context->family == AF_INET6) - context->infoState->ipv6++; - if (not context->infoState->cancel) - context->proxyInfo(infos, context->family); - }; - if (logger_) - context->logger = logger_; + // initialize the parser + auto parser = std::make_shared(); + http_parser_init(parser.get(), HTTP_RESPONSE); + parser->data = static_cast(context.get()); - // initialize the parser - auto parser = std::make_shared(); - http_parser_init(parser.get(), HTTP_RESPONSE); - parser->data = static_cast(context.get()); - - // init the parser callbacks - auto parser_s = std::make_shared(); - http_parser_settings_init(parser_s.get()); - parser_s->on_status = [](http_parser *parser, const char *at, size_t length) -> int { - auto context = static_cast(parser->data); - if (parser->status_code != 200){ - if (context->logger) - context->logger->e("[proxy:client] [status] error: %i", parser->status_code); - context->ok = true; - } - return 0; - }; - parser_s->on_body = [](http_parser *parser, const char *at, size_t length) -> int { - auto context = static_cast(parser->data); - try{ - std::string err; - Json::Value proxyInfos; - Json::CharReaderBuilder rbuilder; - auto body = std::string(at, length); - auto* char_data = static_cast(&body[0]); - auto reader = std::unique_ptr(rbuilder.newCharReader()); - if (!reader->parse(char_data, char_data + body.size(), &proxyInfos, &err)){ + // init the parser callbacks + auto parser_s = std::make_shared(); + http_parser_settings_init(parser_s.get()); + parser_s->on_status = [](http_parser *parser, const char *at, size_t length) -> int { + auto context = static_cast(parser->data); + if (parser->status_code != 200){ + if (context->logger) + context->logger->e("[proxy:client] [status] error: %i", parser->status_code); + context->ok = true; + } + return 0; + }; + parser_s->on_body = [](http_parser *parser, const char *at, size_t length) -> int { + auto context = static_cast(parser->data); + try{ + std::string err; + Json::Value proxyInfos; + Json::CharReaderBuilder rbuilder; + auto body = std::string(at, length); + auto* char_data = static_cast(&body[0]); + auto reader = std::unique_ptr(rbuilder.newCharReader()); + if (!reader->parse(char_data, char_data + body.size(), &proxyInfos, &err)){ + context->ok = false; + return 1; + } + context->cb(proxyInfos); + } + catch (const std::exception& e) { + if (context->logger) + context->logger->e("[proxy:client] [status] body error: %s", e.what()); context->ok = false; return 1; } - context->cb(proxyInfos); - } - catch (const std::exception& e) { - if (context->logger) - context->logger->e("[proxy:client] [status] body error: %s", e.what()); - context->ok = false; - return 1; - } - return 0; - }; - if (context->infoState->cancel) - return; - httpClient_->post_request(request, parser, parser_s); - } - } - catch (const std::exception& e) { - if (logger_) - logger_->e("[proxy:client] [info] error sending request: %s", e.what()); - } + return 0; + }; + if (context->infoState->cancel) + return; + + httpClient_->async_request(conn, request, parser, parser_s); + } + catch (const std::exception& e) { + if (logger_) + logger_->e("[proxy:client] [info] error sending request: %s", e.what()); + } + }); + }); } void @@ -860,7 +861,7 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt header.method(restinio::http_method_subscribe()); header.request_target("/" + key.toString()); } - l->second.connId = sendListen(header, vcb, filter, state, method); + sendListen(header, vcb, filter, state, l->second, method); return token; }); return token; @@ -908,10 +909,11 @@ DhtProxyClient::cancelListen(const InfoHash& key, size_t gtoken) { return canceled; } -uint16_t +void DhtProxyClient::sendListen(const restinio::http_request_header_t header, const ValueCallback &cb, const Value::Filter &filter, - const Sp &state, ListenMethod method) + const Sp &state, + Listener &listener, ListenMethod method) { auto headers = this->initHeaderFields(); auto conn = restinio::http_connection_header_t::close; @@ -986,8 +988,12 @@ DhtProxyClient::sendListen(const restinio::http_request_header_t header, } return 0; }; - auto connId = httpClient_->post_request(request, parser, parser_s); - return connId; + httpClient_->async_connect([this, &listener, request, parser, parser_s] + (std::shared_ptr conn) + { + listener.connId = conn->id(); + httpClient_->async_request(conn, request, parser, parser_s); + }); } bool @@ -1053,7 +1059,11 @@ DhtProxyClient::doCancelListen(const InfoHash& key, size_t ltoken) } return 0; }; - httpClient_->post_request(request, parser, parser_s); + httpClient_->async_connect([this, request, parser, parser_s] + (std::shared_ptr conn) + { + httpClient_->async_request(conn, request, parser, parser_s); + }); } else { // Just stop the request if (httpClient_->active_connection(listener.connId)){ @@ -1163,7 +1173,7 @@ DhtProxyClient::restartListeners() header.method(restinio::http_method_get()); header.request_target("/" + search.first.toString() + "/listen"); // send listen - listener.connId = sendListen(header, cb, filter, state, ListenMethod::LISTEN); + sendListen(header, cb, filter, state, listener, ListenMethod::LISTEN); } } } @@ -1291,7 +1301,7 @@ DhtProxyClient::resubscribe(const InfoHash& key, Listener& listener) proxy::OP_TIMEOUT - proxy::OP_MARGIN); auto vcb = listener.cb; auto filter = listener.filter; - listener.connId = sendListen(header, vcb, filter, state, ListenMethod::RESUBSCRIBE); + sendListen(header, vcb, filter, state, listener, ListenMethod::RESUBSCRIBE); #else (void) key; (void) listener; diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp index 3e029b42..fab916d1 100644 --- a/src/dht_proxy_server.cpp +++ b/src/dht_proxy_server.cpp @@ -83,9 +83,8 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr dht, in_port_t port, )); // build http client auto pushHostPort = splitPort(pushServer_); - uint16_t pushPort = std::atoi(pushHostPort.second.c_str()); httpClient_.reset(new http::Client(httpServer_->io_context(), - pushHostPort.first, pushPort, logger_)); + pushHostPort.first, pushHostPort.second, logger_)); // run http server httpServerThread_ = std::thread([this](){ try { @@ -663,7 +662,12 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso }; auto request = httpClient_->create_request(header, header_fields, restinio::http_connection_header_t::close, body); - httpClient_->post_request(request, parser, parser_s); + + httpClient_->async_connect([this, request, parser, parser_s] + (std::shared_ptr conn) + { + httpClient_->async_request(conn, request, parser, parser_s); + }); } #endif //OPENDHT_PUSH_NOTIFICATIONS diff --git a/src/http.cpp b/src/http.cpp index afc10d1a..bf4fb6e8 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -22,7 +22,7 @@ namespace http { // connection -Connection::Connection(const uint16_t id, asio::ip::tcp::socket socket): +Connection::Connection(const ConnectionId id, asio::ip::tcp::socket socket): id_(id), socket_(std::move(socket)) {} @@ -30,7 +30,7 @@ Connection::~Connection(){ close(); } -uint16_t +ConnectionId Connection::id(){ return id_; } @@ -40,6 +40,11 @@ Connection::is_open(){ return socket_.is_open(); } +bool +Connection::is_v6(){ + return endpoint_.address().is_v6(); +} + void Connection::close(){ socket_.close(); @@ -102,11 +107,12 @@ ConnectionListener::to_str(restinio::connection_state::cause_t cause) noexcept // client -Client::Client(asio::io_context &ctx, const std::string host, const uint16_t port, - std::shared_ptr logger): +Client::Client(asio::io_context &ctx, const std::string host, const std::string service, + std::shared_ptr logger, const bool resolve): resolver_(ctx), logger_(logger) { - set_query_address(host, port); + if (resolve) + async_resolve(host, service); } asio::io_context& @@ -120,26 +126,9 @@ Client::set_logger(std::shared_ptr logger) { logger_ = logger; } -void -Client::set_query_address(const std::string host, const uint16_t port) -{ - host_ = host; - port_ = port; -} - -std::shared_ptr -Client::create_connection() -{ - auto conn = std::make_shared(connId_, - std::move(asio::ip::tcp::socket{resolver_.get_io_context()})); - if (logger_) - logger_->d("[proxy:client] [connection:%i] created", conn->id()); - connId_++; - return conn; -} bool -Client::active_connection(const uint16_t conn_id) +Client::active_connection(const ConnectionId conn_id) { auto req = requests_.find(conn_id); if (req == requests_.end()) @@ -148,7 +137,7 @@ Client::active_connection(const uint16_t conn_id) } void -Client::close_connection(const uint16_t conn_id) +Client::close_connection(const ConnectionId conn_id) { auto &req = requests_[conn_id]; // ensure on_message_complete is fired @@ -158,7 +147,46 @@ Client::close_connection(const uint16_t conn_id) // remove from active requests requests_.erase(conn_id); if (logger_) - logger_->d("[proxy:client] [connection:%i] closed", conn_id); + logger_->d("[http::client] [connection:%i] closed", conn_id); +} + +bool +Client::resolved() +{ + return !endpoints_.empty(); +} + +void +Client::async_resolve(const std::string host, const std::string service, HandlerCb cb) +{ + // build the query + asio::ip::tcp::resolver::query query(host, service); + + // resolve the query to the server + resolver_.async_resolve(query, [this, host, service, cb]( + const asio::error_code &ec, + asio::ip::tcp::resolver::results_type endpoints) + { + if (ec){ + if (logger_) + logger_->e("[http::client] [resolve %s:%s] error resolving: %s", + host.c_str(), service.c_str(), ec.message().c_str()); + } + else { + for (auto it = endpoints.begin(); it != endpoints.end(); ++it){ + if (logger_){ + asio::ip::tcp::endpoint endpoint = *it; + logger_->d("[http::client] [resolve %s:%s] address=%s ipv%i", + host.c_str(), service.c_str(), + endpoint.address().to_string().c_str(), + endpoint.address().is_v6() ? 6 : 4); + } + } + endpoints_ = endpoints; + } + if (cb) + cb(ec); + }); } std::string @@ -203,13 +231,81 @@ Client::create_request(const restinio::http_request_header_t header, return request.str(); } -uint16_t -Client::post_request(std::string request, - std::shared_ptr parser, - std::shared_ptr parser_s) +void +Client::async_connect(ConnectionCb cb) { - auto conn = create_connection(); + if (endpoints_.empty()){ + if (logger_) + logger_->e("[http::client] host not resolved, can't send request"); + return; + } + auto conn = std::make_shared(connId_, + std::move(asio::ip::tcp::socket{resolver_.get_io_context()})); + if (logger_) + logger_->d("[http::client] [connection:%i] created", conn->id()); + connId_++; + auto endpoint_it = endpoints_.begin(); + // get the first endpoint + asio::ip::tcp::endpoint endpoint = *endpoint_it; + // try to connect + conn->socket_.async_connect(endpoint, std::bind( + &Client::handle_connect, this, std::placeholders::_1, ++endpoint_it, conn, + [this, endpoint, conn, cb](const asio::error_code &ec){ + if (!ec){ + // save the associated endpoint + conn->endpoint_ = endpoint; + // get back to user + cb(conn); + } + else + close(conn->id()); + })); +} + +void +Client::handle_connect(const asio::error_code &ec, + asio::ip::tcp::resolver::iterator endpoint_it, + std::shared_ptr conn, HandlerCb cb) +{ + if (ec && endpoint_it != endpoints_.end()){ + if (logger_) + logger_->e("[http::client] [connection:%i] error opening: %s", + conn->id(), ec.message().c_str()); + // close current + conn->socket_.close(); + // connect to next one + asio::ip::tcp::endpoint endpoint = endpoint_it->endpoint(); + conn->socket_.async_connect(endpoint, + std::bind(&Client::handle_connect, this, + std::placeholders::_1, ++endpoint_it, conn, cb)); + return; + } + if (logger_) + logger_->d("[http::client] [connection:%i] opened", conn->id()); + cb(ec); +} + +void +Client::async_request(std::shared_ptr conn, std::string request, + std::shared_ptr parser, + std::shared_ptr parser_s) +{ + if (endpoints_.empty()){ + if (logger_) + logger_->e("[http::client] host not resolved, can't send request"); + return; + } + if (!conn){ + if (logger_) + logger_->e("[http::client] invalid connection, can't post request"); + return; + } + else if (!conn->is_open()){ + if (logger_) + logger_->e("[http::client] closed connection, can't post request"); + return; + } // save the request context Request req = {}; req.connection = conn; @@ -222,57 +318,6 @@ Client::post_request(std::string request, std::ostream request_stream(&conn->request_); request_stream << request; - // resolve the query to the server - asio::ip::tcp::resolver::query query(host_, std::to_string(port_)); - resolver_.async_resolve(query, - std::bind(&Client::handle_resolve, this, - std::placeholders::_1, std::placeholders::_2, conn)); - - return conn->id(); -} - -void -Client::handle_resolve(const asio::error_code &ec, - asio::ip::tcp::resolver::iterator endpoint_it, - std::shared_ptr conn) -{ - if (ec){ - if (logger_) - logger_->e("[proxy:client] [connection:%i] error resolving", conn->id()); - conn->close(); - return; - } - if (logger_){ - logger_->d("[proxy:client] [connection:%i] resolved host=%s service=%s", conn->id(), - endpoint_it->host_name().c_str(), endpoint_it->service_name().c_str()); - } - asio::ip::tcp::endpoint endpoint = *endpoint_it; - conn->socket_.async_connect(endpoint, - std::bind(&Client::handle_connect, this, - std::placeholders::_1, ++endpoint_it, conn)); -} - -void -Client::handle_connect(const asio::error_code &ec, - asio::ip::tcp::resolver::iterator endpoint_it, - std::shared_ptr conn) -{ - if (ec){ - if (logger_) - logger_->e("[proxy:client] [connection:%i] error opening: %s", - conn->id(), ec.message().c_str()); - close(conn->id()); - return; - } - else if (endpoint_it != asio::ip::tcp::resolver::iterator()){ - conn->socket_.close(); - // connect to next one - asio::ip::tcp::endpoint endpoint = *endpoint_it; - conn->socket_.async_connect(endpoint, - std::bind(&Client::handle_connect, this, - std::placeholders::_1, ++endpoint_it, conn)); - return; - } // send the request asio::async_write(conn->socket_, conn->request_, std::bind(&Client::handle_request, this, std::placeholders::_1, conn)); @@ -286,13 +331,13 @@ Client::handle_request(const asio::error_code &ec, std::shared_ptr c if (ec and ec != asio::error::eof){ if (logger_) - logger_->e("[proxy:client] [connection:%i] error handling request: %s", + logger_->e("[http::client] [connection:%i] error handling request: %s", conn->id(), ec.message().c_str()); close_connection(conn->id()); return; } if (logger_) - logger_->d("[proxy:client] [connection:%i] request write", conn->id()); + logger_->d("[http::client] [connection:%i] request write", conn->id()); // read response asio::async_read_until(conn->socket_, conn->response_, "\r\n\r\n", @@ -307,7 +352,7 @@ Client::handle_response(const asio::error_code &ec, std::shared_ptr if (ec && ec != asio::error::eof){ if (logger_) - logger_->e("[proxy:client] [connection:%i] error handling response: %s", + logger_->e("[http::client] [connection:%i] error handling response: %s", conn->id(), ec.message().c_str()); return; } @@ -316,11 +361,13 @@ Client::handle_response(const asio::error_code &ec, std::shared_ptr return; } if (logger_) - logger_->d("[proxy:client] [connection:%i] response read", conn->id()); + logger_->d("[http::client] [connection:%i] response read", conn->id()); // read the response buffer std::ostringstream str_s; str_s << &conn->response_; + if (logger_) + logger_->d("%s", str_s.str().c_str()); // parse the request auto &req = requests_[conn->id()]; @@ -331,7 +378,7 @@ Client::handle_response(const asio::error_code &ec, std::shared_ptr if (HPE_OK != req.parser->http_errno && HPE_PAUSED != req.parser->http_errno){ if (logger_){ auto err = HTTP_PARSER_ERRNO(req.parser.get()); - logger_->e("[proxy:client] [connection:%i] error parsing: %s", + logger_->e("[http::client] [connection:%i] error parsing: %s", conn->id(), http_errno_name(err)); } }