mirror of
https://github.com/monero-project/monero.git
synced 2024-12-12 16:24:21 -05:00
bootstrap_daemon: proxy configuration support
This commit is contained in:
parent
a6df656b4e
commit
52dcc03068
@ -887,16 +887,66 @@ bool t_command_parser_executor::check_blockchain_pruning(const std::vector<std::
|
|||||||
|
|
||||||
bool t_command_parser_executor::set_bootstrap_daemon(const std::vector<std::string>& args)
|
bool t_command_parser_executor::set_bootstrap_daemon(const std::vector<std::string>& args)
|
||||||
{
|
{
|
||||||
|
struct parsed_t
|
||||||
|
{
|
||||||
|
std::string address;
|
||||||
|
std::string user;
|
||||||
|
std::string password;
|
||||||
|
std::string proxy;
|
||||||
|
};
|
||||||
|
|
||||||
|
boost::optional<parsed_t> parsed = [&args]() -> boost::optional<parsed_t> {
|
||||||
const size_t args_count = args.size();
|
const size_t args_count = args.size();
|
||||||
if (args_count < 1 || args_count > 3)
|
if (args_count == 0)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (args[0] == "auto")
|
||||||
|
{
|
||||||
|
if (args_count == 1)
|
||||||
|
{
|
||||||
|
return {{args[0], "", "", ""}};
|
||||||
|
}
|
||||||
|
if (args_count == 2)
|
||||||
|
{
|
||||||
|
return {{args[0], "", "", args[1]}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[0] == "none")
|
||||||
|
{
|
||||||
|
if (args_count == 1)
|
||||||
|
{
|
||||||
|
return {{"", "", "", ""}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (args_count == 1)
|
||||||
|
{
|
||||||
|
return {{args[0], "", "", ""}};
|
||||||
|
}
|
||||||
|
if (args_count == 2)
|
||||||
|
{
|
||||||
|
return {{args[0], "", "", args[1]}};
|
||||||
|
}
|
||||||
|
if (args_count == 3)
|
||||||
|
{
|
||||||
|
return {{args[0], args[1], args[2], ""}};
|
||||||
|
}
|
||||||
|
if (args_count == 4)
|
||||||
|
{
|
||||||
|
return {{args[0], args[1], args[2], args[3]}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (!parsed)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_executor.set_bootstrap_daemon(
|
return m_executor.set_bootstrap_daemon(parsed->address, parsed->user, parsed->password, parsed->proxy);
|
||||||
args[0] != "none" ? args[0] : std::string(),
|
|
||||||
args_count > 1 ? args[1] : std::string(),
|
|
||||||
args_count > 2 ? args[2] : std::string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool t_command_parser_executor::flush_cache(const std::vector<std::string>& args)
|
bool t_command_parser_executor::flush_cache(const std::vector<std::string>& args)
|
||||||
|
@ -324,7 +324,7 @@ t_command_server::t_command_server(
|
|||||||
m_command_lookup.set_handler(
|
m_command_lookup.set_handler(
|
||||||
"set_bootstrap_daemon"
|
"set_bootstrap_daemon"
|
||||||
, std::bind(&t_command_parser_executor::set_bootstrap_daemon, &m_parser, p::_1)
|
, std::bind(&t_command_parser_executor::set_bootstrap_daemon, &m_parser, p::_1)
|
||||||
, "set_bootstrap_daemon (auto | none | host[:port] [username] [password])"
|
, "set_bootstrap_daemon (auto | none | host[:port] [username] [password]) [proxy_ip:proxy_port]"
|
||||||
, "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced.\n"
|
, "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced.\n"
|
||||||
"Use 'auto' to enable automatic public nodes discovering and bootstrap daemon switching"
|
"Use 'auto' to enable automatic public nodes discovering and bootstrap daemon switching"
|
||||||
);
|
);
|
||||||
|
@ -2405,7 +2405,8 @@ bool t_rpc_command_executor::check_blockchain_pruning()
|
|||||||
bool t_rpc_command_executor::set_bootstrap_daemon(
|
bool t_rpc_command_executor::set_bootstrap_daemon(
|
||||||
const std::string &address,
|
const std::string &address,
|
||||||
const std::string &username,
|
const std::string &username,
|
||||||
const std::string &password)
|
const std::string &password,
|
||||||
|
const std::string &proxy)
|
||||||
{
|
{
|
||||||
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request req;
|
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request req;
|
||||||
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response res;
|
cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response res;
|
||||||
@ -2414,6 +2415,7 @@ bool t_rpc_command_executor::set_bootstrap_daemon(
|
|||||||
req.address = address;
|
req.address = address;
|
||||||
req.username = username;
|
req.username = username;
|
||||||
req.password = password;
|
req.password = password;
|
||||||
|
req.proxy = proxy;
|
||||||
|
|
||||||
if (m_is_rpc)
|
if (m_is_rpc)
|
||||||
{
|
{
|
||||||
|
@ -168,7 +168,8 @@ public:
|
|||||||
bool set_bootstrap_daemon(
|
bool set_bootstrap_daemon(
|
||||||
const std::string &address,
|
const std::string &address,
|
||||||
const std::string &username,
|
const std::string &username,
|
||||||
const std::string &password);
|
const std::string &password,
|
||||||
|
const std::string &proxy);
|
||||||
|
|
||||||
bool rpc_payments();
|
bool rpc_payments();
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "crypto/crypto.h"
|
#include "crypto/crypto.h"
|
||||||
#include "cryptonote_core/cryptonote_core.h"
|
#include "cryptonote_core/cryptonote_core.h"
|
||||||
#include "misc_log_ex.h"
|
#include "misc_log_ex.h"
|
||||||
|
#include "net/parse.h"
|
||||||
|
|
||||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||||
#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc.bootstrap_daemon"
|
#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc.bootstrap_daemon"
|
||||||
@ -16,19 +17,23 @@ namespace cryptonote
|
|||||||
|
|
||||||
bootstrap_daemon::bootstrap_daemon(
|
bootstrap_daemon::bootstrap_daemon(
|
||||||
std::function<std::map<std::string, bool>()> get_public_nodes,
|
std::function<std::map<std::string, bool>()> get_public_nodes,
|
||||||
bool rpc_payment_enabled)
|
bool rpc_payment_enabled,
|
||||||
|
const std::string &proxy)
|
||||||
: m_selector(new bootstrap_node::selector_auto(std::move(get_public_nodes)))
|
: m_selector(new bootstrap_node::selector_auto(std::move(get_public_nodes)))
|
||||||
, m_rpc_payment_enabled(rpc_payment_enabled)
|
, m_rpc_payment_enabled(rpc_payment_enabled)
|
||||||
{
|
{
|
||||||
|
set_proxy(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrap_daemon::bootstrap_daemon(
|
bootstrap_daemon::bootstrap_daemon(
|
||||||
const std::string &address,
|
const std::string &address,
|
||||||
boost::optional<epee::net_utils::http::login> credentials,
|
boost::optional<epee::net_utils::http::login> credentials,
|
||||||
bool rpc_payment_enabled)
|
bool rpc_payment_enabled,
|
||||||
|
const std::string &proxy)
|
||||||
: m_selector(nullptr)
|
: m_selector(nullptr)
|
||||||
, m_rpc_payment_enabled(rpc_payment_enabled)
|
, m_rpc_payment_enabled(rpc_payment_enabled)
|
||||||
{
|
{
|
||||||
|
set_proxy(proxy);
|
||||||
if (!set_server(address, std::move(credentials)))
|
if (!set_server(address, std::move(credentials)))
|
||||||
{
|
{
|
||||||
throw std::runtime_error("invalid bootstrap daemon address or credentials");
|
throw std::runtime_error("invalid bootstrap daemon address or credentials");
|
||||||
@ -78,6 +83,18 @@ namespace cryptonote
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bootstrap_daemon::set_proxy(const std::string &address)
|
||||||
|
{
|
||||||
|
if (!address.empty() && !net::get_tcp_endpoint(address))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid proxy address format");
|
||||||
|
}
|
||||||
|
if (!m_http_client.set_proxy(address))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("failed to set proxy address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool bootstrap_daemon::set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials /* = boost::none */)
|
bool bootstrap_daemon::set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials /* = boost::none */)
|
||||||
{
|
{
|
||||||
if (!m_http_client.set_server(address, credentials))
|
if (!m_http_client.set_server(address, credentials))
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/utility/string_ref.hpp>
|
#include <boost/utility/string_ref.hpp>
|
||||||
|
|
||||||
#include "net/http_client.h"
|
#include "net/http.h"
|
||||||
#include "storages/http_abstract_invoke.h"
|
#include "storages/http_abstract_invoke.h"
|
||||||
|
|
||||||
#include "bootstrap_node_selector.h"
|
#include "bootstrap_node_selector.h"
|
||||||
@ -21,11 +21,13 @@ namespace cryptonote
|
|||||||
public:
|
public:
|
||||||
bootstrap_daemon(
|
bootstrap_daemon(
|
||||||
std::function<std::map<std::string, bool>()> get_public_nodes,
|
std::function<std::map<std::string, bool>()> get_public_nodes,
|
||||||
bool rpc_payment_enabled);
|
bool rpc_payment_enabled,
|
||||||
|
const std::string &proxy);
|
||||||
bootstrap_daemon(
|
bootstrap_daemon(
|
||||||
const std::string &address,
|
const std::string &address,
|
||||||
boost::optional<epee::net_utils::http::login> credentials,
|
boost::optional<epee::net_utils::http::login> credentials,
|
||||||
bool rpc_payment_enabled);
|
bool rpc_payment_enabled,
|
||||||
|
const std::string &proxy);
|
||||||
|
|
||||||
std::string address() const noexcept;
|
std::string address() const noexcept;
|
||||||
boost::optional<std::pair<uint64_t, uint64_t>> get_height();
|
boost::optional<std::pair<uint64_t, uint64_t>> get_height();
|
||||||
@ -72,12 +74,14 @@ namespace cryptonote
|
|||||||
return handle_result(result, result_struct.status);
|
return handle_result(result, result_struct.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_proxy(const std::string &address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials = boost::none);
|
bool set_server(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials = boost::none);
|
||||||
bool switch_server_if_needed();
|
bool switch_server_if_needed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
epee::net_utils::http::http_simple_client m_http_client;
|
net::http::client m_http_client;
|
||||||
const bool m_rpc_payment_enabled;
|
const bool m_rpc_payment_enabled;
|
||||||
const std::unique_ptr<bootstrap_node::selector> m_selector;
|
const std::unique_ptr<bootstrap_node::selector> m_selector;
|
||||||
boost::mutex m_selector_mutex;
|
boost::mutex m_selector_mutex;
|
||||||
|
@ -154,6 +154,7 @@ namespace cryptonote
|
|||||||
command_line::add_arg(desc, arg_restricted_rpc);
|
command_line::add_arg(desc, arg_restricted_rpc);
|
||||||
command_line::add_arg(desc, arg_bootstrap_daemon_address);
|
command_line::add_arg(desc, arg_bootstrap_daemon_address);
|
||||||
command_line::add_arg(desc, arg_bootstrap_daemon_login);
|
command_line::add_arg(desc, arg_bootstrap_daemon_login);
|
||||||
|
command_line::add_arg(desc, arg_bootstrap_daemon_proxy);
|
||||||
cryptonote::rpc_args::init_options(desc, true);
|
cryptonote::rpc_args::init_options(desc, true);
|
||||||
command_line::add_arg(desc, arg_rpc_payment_address);
|
command_line::add_arg(desc, arg_rpc_payment_address);
|
||||||
command_line::add_arg(desc, arg_rpc_payment_difficulty);
|
command_line::add_arg(desc, arg_rpc_payment_difficulty);
|
||||||
@ -172,7 +173,10 @@ namespace cryptonote
|
|||||||
, m_rpc_payment_allow_free_loopback(false)
|
, m_rpc_payment_allow_free_loopback(false)
|
||||||
{}
|
{}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const std::string &username_password)
|
bool core_rpc_server::set_bootstrap_daemon(
|
||||||
|
const std::string &address,
|
||||||
|
const std::string &username_password,
|
||||||
|
const std::string &proxy)
|
||||||
{
|
{
|
||||||
boost::optional<epee::net_utils::http::login> credentials;
|
boost::optional<epee::net_utils::http::login> credentials;
|
||||||
const auto loc = username_password.find(':');
|
const auto loc = username_password.find(':');
|
||||||
@ -180,7 +184,7 @@ namespace cryptonote
|
|||||||
{
|
{
|
||||||
credentials = epee::net_utils::http::login(username_password.substr(0, loc), username_password.substr(loc + 1));
|
credentials = epee::net_utils::http::login(username_password.substr(0, loc), username_password.substr(loc + 1));
|
||||||
}
|
}
|
||||||
return set_bootstrap_daemon(address, credentials);
|
return set_bootstrap_daemon(address, credentials, proxy);
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
std::map<std::string, bool> core_rpc_server::get_public_nodes(uint32_t credits_per_hash_threshold/* = 0*/)
|
std::map<std::string, bool> core_rpc_server::get_public_nodes(uint32_t credits_per_hash_threshold/* = 0*/)
|
||||||
@ -217,7 +221,10 @@ namespace cryptonote
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials)
|
bool core_rpc_server::set_bootstrap_daemon(
|
||||||
|
const std::string &address,
|
||||||
|
const boost::optional<epee::net_utils::http::login> &credentials,
|
||||||
|
const std::string &proxy)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
|
boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
|
||||||
|
|
||||||
@ -233,11 +240,11 @@ namespace cryptonote
|
|||||||
auto get_nodes = [this]() {
|
auto get_nodes = [this]() {
|
||||||
return get_public_nodes(credits_per_hash_threshold);
|
return get_public_nodes(credits_per_hash_threshold);
|
||||||
};
|
};
|
||||||
m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled));
|
m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled, proxy));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, rpc_payment_enabled));
|
m_bootstrap_daemon.reset(new bootstrap_daemon(address, credentials, rpc_payment_enabled, proxy));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_should_use_bootstrap_daemon = m_bootstrap_daemon.get() != nullptr;
|
m_should_use_bootstrap_daemon = m_bootstrap_daemon.get() != nullptr;
|
||||||
@ -318,8 +325,10 @@ namespace cryptonote
|
|||||||
MWARNING("The RPC server is accessible from the outside, but no RPC payment was setup. RPC access will be free for all.");
|
MWARNING("The RPC server is accessible from the outside, but no RPC payment was setup. RPC access will be free for all.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!set_bootstrap_daemon(command_line::get_arg(vm, arg_bootstrap_daemon_address),
|
if (!set_bootstrap_daemon(
|
||||||
command_line::get_arg(vm, arg_bootstrap_daemon_login)))
|
command_line::get_arg(vm, arg_bootstrap_daemon_address),
|
||||||
|
command_line::get_arg(vm, arg_bootstrap_daemon_login),
|
||||||
|
command_line::get_arg(vm, arg_bootstrap_daemon_proxy)))
|
||||||
{
|
{
|
||||||
MFATAL("Failed to parse bootstrap daemon address");
|
MFATAL("Failed to parse bootstrap daemon address");
|
||||||
return false;
|
return false;
|
||||||
@ -1597,7 +1606,7 @@ namespace cryptonote
|
|||||||
credentials = epee::net_utils::http::login(req.username, req.password);
|
credentials = epee::net_utils::http::login(req.username, req.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_bootstrap_daemon(req.address, credentials))
|
if (set_bootstrap_daemon(req.address, credentials, req.proxy))
|
||||||
{
|
{
|
||||||
res.status = CORE_RPC_STATUS_OK;
|
res.status = CORE_RPC_STATUS_OK;
|
||||||
}
|
}
|
||||||
@ -3386,6 +3395,12 @@ namespace cryptonote
|
|||||||
, ""
|
, ""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_proxy = {
|
||||||
|
"bootstrap-daemon-proxy"
|
||||||
|
, "<ip>:<port> socks proxy to use for bootstrap daemon connections"
|
||||||
|
, ""
|
||||||
|
};
|
||||||
|
|
||||||
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_payment_address = {
|
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_payment_address = {
|
||||||
"rpc-payment-address"
|
"rpc-payment-address"
|
||||||
, "Restrict RPC to clients sending micropayment to this address"
|
, "Restrict RPC to clients sending micropayment to this address"
|
||||||
|
@ -72,6 +72,7 @@ namespace cryptonote
|
|||||||
static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert;
|
static const command_line::arg_descriptor<bool> arg_rpc_ssl_allow_any_cert;
|
||||||
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
|
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
|
||||||
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login;
|
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login;
|
||||||
|
static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_proxy;
|
||||||
static const command_line::arg_descriptor<std::string> arg_rpc_payment_address;
|
static const command_line::arg_descriptor<std::string> arg_rpc_payment_address;
|
||||||
static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_difficulty;
|
static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_difficulty;
|
||||||
static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_credits;
|
static const command_line::arg_descriptor<uint64_t> arg_rpc_payment_credits;
|
||||||
@ -270,8 +271,14 @@ private:
|
|||||||
uint64_t get_block_reward(const block& blk);
|
uint64_t get_block_reward(const block& blk);
|
||||||
bool fill_block_header_response(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_response& response, bool fill_pow_hash);
|
bool fill_block_header_response(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_response& response, bool fill_pow_hash);
|
||||||
std::map<std::string, bool> get_public_nodes(uint32_t credits_per_hash_threshold = 0);
|
std::map<std::string, bool> get_public_nodes(uint32_t credits_per_hash_threshold = 0);
|
||||||
bool set_bootstrap_daemon(const std::string &address, const std::string &username_password);
|
bool set_bootstrap_daemon(
|
||||||
bool set_bootstrap_daemon(const std::string &address, const boost::optional<epee::net_utils::http::login> &credentials);
|
const std::string &address,
|
||||||
|
const std::string &username_password,
|
||||||
|
const std::string &proxy);
|
||||||
|
bool set_bootstrap_daemon(
|
||||||
|
const std::string &address,
|
||||||
|
const boost::optional<epee::net_utils::http::login> &credentials,
|
||||||
|
const std::string &proxy);
|
||||||
enum invoke_http_mode { JON, BIN, JON_RPC };
|
enum invoke_http_mode { JON, BIN, JON_RPC };
|
||||||
template <typename COMMAND_TYPE>
|
template <typename COMMAND_TYPE>
|
||||||
bool use_bootstrap_daemon_if_necessary(const invoke_http_mode &mode, const std::string &command_name, const typename COMMAND_TYPE::request& req, typename COMMAND_TYPE::response& res, bool &r);
|
bool use_bootstrap_daemon_if_necessary(const invoke_http_mode &mode, const std::string &command_name, const typename COMMAND_TYPE::request& req, typename COMMAND_TYPE::response& res, bool &r);
|
||||||
|
@ -1663,11 +1663,13 @@ namespace cryptonote
|
|||||||
std::string address;
|
std::string address;
|
||||||
std::string username;
|
std::string username;
|
||||||
std::string password;
|
std::string password;
|
||||||
|
std::string proxy;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(address)
|
KV_SERIALIZE(address)
|
||||||
KV_SERIALIZE(username)
|
KV_SERIALIZE(username)
|
||||||
KV_SERIALIZE(password)
|
KV_SERIALIZE(password)
|
||||||
|
KV_SERIALIZE(proxy)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
typedef epee::misc_utils::struct_init<request_t> request;
|
typedef epee::misc_utils::struct_init<request_t> request;
|
||||||
|
Loading…
Reference in New Issue
Block a user