mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-08 04:21:51 +00:00
http: segment resolving & connection from request
set connection id to unsigned int
use service string instead of int port
segment connection from request
save endpoint associated with a conn
add Connection is_v6 ip method
propagate resolve errors
This commit is contained in:
1 parent
0e509318bb
commit
93f7251805
5 files changed
+304
-232
No files matched your search
@@ -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<ListenState> &state, ListenMethod method = ListenMethod::LISTEN);
|
||||
void sendListen(const restinio::http_request_header_t header,
|
||||
const ValueCallback &cb, const Value::Filter &filter,
|
||||
const Sp<ListenState> &state, Listener &listener,
|
||||
ListenMethod method = ListenMethod::LISTEN);
|
||||
|
||||
void doPut(const InfoHash&, Sp<Value>, DoneCallback, time_point created, bool permanent);
|
||||
|
||||
@@ -322,9 +323,7 @@ private:
|
||||
*/
|
||||
void cancelAllOperations();
|
||||
|
||||
std::string serverHost_;
|
||||
std::string serverHostIp_;
|
||||
uint16_t serverHostPort_;
|
||||
std::pair<std::string, std::string> serverHostService_;
|
||||
std::string pushClientId_;
|
||||
|
||||
/*
|
||||
|
||||
+28
-16
@@ -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<dht::Logger> logger = {});
|
||||
using HandlerCb = std::function<void(const asio::error_code &ec)>;
|
||||
using ConnectionCb = std::function<void(std::shared_ptr<Connection>)>;
|
||||
|
||||
Client(asio::io_context &ctx, const std::string host, const std::string service = "80",
|
||||
std::shared_ptr<dht::Logger> logger = {}, const bool resolve = true);
|
||||
|
||||
asio::io_context& io_context();
|
||||
|
||||
void set_logger(std::shared_ptr<dht::Logger> 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<http_parser> parser,
|
||||
std::shared_ptr<http_parser_settings> parser_s);
|
||||
void async_request(std::shared_ptr<http::Connection> conn,
|
||||
std::string request, std::shared_ptr<http_parser> parser,
|
||||
std::shared_ptr<http_parser_settings> parser_s);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Connection> create_connection();
|
||||
|
||||
void handle_connect(const asio::error_code &ec,
|
||||
asio::ip::tcp::resolver::iterator endpoint_it,
|
||||
std::shared_ptr<Connection> conn = {});
|
||||
std::shared_ptr<Connection> 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<Connection> 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<asio::ip::tcp> endpoints_;
|
||||
|
||||
uint16_t connId_ {1};
|
||||
ConnectionId connId_ {1};
|
||||
/*
|
||||
* An association between an active connection and its context, a Request.
|
||||
*/
|
||||
std::map<uint16_t, Request> requests_;
|
||||
std::map<ConnectionId, Request> requests_;
|
||||
|
||||
std::shared_ptr<dht::Logger> logger_;
|
||||
};
|
||||
|
||||
+130
-120
@@ -73,16 +73,15 @@ DhtProxyClient::DhtProxyClient() {}
|
||||
|
||||
DhtProxyClient::DhtProxyClient(std::function<void()> signal, const std::string &serverHost,
|
||||
const std::string &pushClientId, std::shared_ptr<dht::Logger> 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<http::Client>(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<void()> 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<asio::steady_timer>(
|
||||
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<GetContext>();
|
||||
context->filter = w.empty() ? f : f.chain(w.getFilter());
|
||||
// keeping context data alive
|
||||
context->cb = [this, context, cb]
|
||||
(const std::vector<dht::Sp<dht::Value>>& 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<GetContext*>(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<http::Connection> conn)
|
||||
{
|
||||
httpClient_->async_request(conn, request, parser, parser_s);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -503,7 +503,11 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
httpClient_->post_request(request, parser, parser_s);
|
||||
httpClient_->async_connect([this, request, parser, parser_s]
|
||||
(std::shared_ptr<http::Connection> 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<http::Connection> 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<void(Json::Value infos)> cb; // wrapper
|
||||
std::atomic_bool ok {true};
|
||||
std::shared_ptr<InfoState> infoState;
|
||||
std::function<void(const Json::Value&, sa_family_t)> proxyInfo;
|
||||
std::shared_ptr<dht::Logger> logger;
|
||||
};
|
||||
auto context = std::make_shared<GetContext>();
|
||||
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<void(Json::Value infos)> cb; // wrapper
|
||||
std::atomic_bool ok {true};
|
||||
std::shared_ptr<InfoState> infoState;
|
||||
std::function<void(const Json::Value&, sa_family_t)> proxyInfo;
|
||||
std::shared_ptr<dht::Logger> logger;
|
||||
};
|
||||
auto context = std::make_shared<GetContext>();
|
||||
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>();
|
||||
http_parser_init(parser.get(), HTTP_RESPONSE);
|
||||
parser->data = static_cast<void*>(context.get());
|
||||
|
||||
// initialize the parser
|
||||
auto parser = std::make_shared<http_parser>();
|
||||
http_parser_init(parser.get(), HTTP_RESPONSE);
|
||||
parser->data = static_cast<void*>(context.get());
|
||||
|
||||
// init the parser callbacks
|
||||
auto parser_s = std::make_shared<http_parser_settings>();
|
||||
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<GetContext*>(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<GetContext*>(parser->data);
|
||||
try{
|
||||
std::string err;
|
||||
Json::Value proxyInfos;
|
||||
Json::CharReaderBuilder rbuilder;
|
||||
auto body = std::string(at, length);
|
||||
auto* char_data = static_cast<const char*>(&body[0]);
|
||||
auto reader = std::unique_ptr<Json::CharReader>(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>();
|
||||
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<GetContext*>(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<GetContext*>(parser->data);
|
||||
try{
|
||||
std::string err;
|
||||
Json::Value proxyInfos;
|
||||
Json::CharReaderBuilder rbuilder;
|
||||
auto body = std::string(at, length);
|
||||
auto* char_data = static_cast<const char*>(&body[0]);
|
||||
auto reader = std::unique_ptr<Json::CharReader>(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<ListenState> &state, ListenMethod method)
|
||||
const Sp<ListenState> &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<http::Connection> 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<http::Connection> 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;
|
||||
|
||||
@@ -83,9 +83,8 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> 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<http::Connection> conn)
|
||||
{
|
||||
httpClient_->async_request(conn, request, parser, parser_s);
|
||||
});
|
||||
}
|
||||
|
||||
#endif //OPENDHT_PUSH_NOTIFICATIONS
|
||||
|
||||
+133
-86
@@ -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<dht::Logger> logger):
|
||||
Client::Client(asio::io_context &ctx, const std::string host, const std::string service,
|
||||
std::shared_ptr<dht::Logger> 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<dht::Logger> logger)
|
||||
{
|
||||
logger_ = logger;
|
||||
}
|
||||
void
|
||||
Client::set_query_address(const std::string host, const uint16_t port)
|
||||
{
|
||||
host_ = host;
|
||||
port_ = port;
|
||||
}
|
||||
|
||||
std::shared_ptr<Connection>
|
||||
Client::create_connection()
|
||||
{
|
||||
auto conn = std::make_shared<Connection>(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<http_parser> parser,
|
||||
std::shared_ptr<http_parser_settings> 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<Connection>(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<Connection> 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<Connection> conn, std::string request,
|
||||
std::shared_ptr<http_parser> parser,
|
||||
std::shared_ptr<http_parser_settings> 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<Connection> 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<Connection> 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<Connection> 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<Connection>
|
||||
|
||||
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<Connection>
|
||||
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<Connection>
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user