Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configuration options to HTTP server #9765

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion contrib/epee/include/net/abstract_tcp_server2.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
#define MONERO_DEFAULT_LOG_CATEGORY "net"

#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 1000
#define ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT 100 * 1024 * 1024

namespace epee
{
Expand Down Expand Up @@ -170,6 +171,7 @@ namespace net_utils
} read;
struct {
std::deque<epee::byte_slice> queue;
std::size_t total_bytes;
bool wait_consume;
} write;
};
Expand Down Expand Up @@ -268,11 +270,17 @@ namespace net_utils
struct shared_state : connection_basic_shared_state, t_protocol_handler::config_type
{
shared_state()
: connection_basic_shared_state(), t_protocol_handler::config_type(), pfilter(nullptr), plimit(nullptr), stop_signal_sent(false)
: connection_basic_shared_state(),
t_protocol_handler::config_type(),
pfilter(nullptr),
plimit(nullptr),
response_soft_limit(ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT),
stop_signal_sent(false)
{}

i_connection_filter* pfilter;
i_connection_limit* plimit;
std::size_t response_soft_limit;
bool stop_signal_sent;
};

Expand Down Expand Up @@ -380,6 +388,7 @@ namespace net_utils

void set_connection_filter(i_connection_filter* pfilter);
void set_connection_limit(i_connection_limit* plimit);
void set_response_soft_limit(std::size_t limit);

void set_default_remote(epee::net_utils::network_address remote)
{
Expand Down
36 changes: 32 additions & 4 deletions contrib/epee/include/net/abstract_tcp_server2.inl
Original file line number Diff line number Diff line change
Expand Up @@ -497,10 +497,12 @@ namespace net_utils
if (m_state.socket.cancel_write) {
m_state.socket.cancel_write = false;
m_state.data.write.queue.clear();
m_state.data.write.total_bytes = 0;
state_status_check();
}
else if (ec.value()) {
m_state.data.write.queue.clear();
m_state.data.write.total_bytes = 0;
interrupt();
}
else {
Expand All @@ -525,8 +527,11 @@ namespace net_utils

start_timer(get_default_timeout(), true);
}
assert(bytes_transferred == m_state.data.write.queue.back().size());
const std::size_t byte_count = m_state.data.write.queue.back().size();
assert(bytes_transferred == byte_count);
m_state.data.write.queue.pop_back();
m_state.data.write.total_bytes -=
std::min(m_state.data.write.total_bytes, byte_count);
m_state.condition.notify_all();
start_write();
}
Expand Down Expand Up @@ -757,6 +762,8 @@ namespace net_utils
std::lock_guard<std::mutex> guard(m_state.lock);
if (m_state.status != status_t::RUNNING || m_state.socket.wait_handshake)
return false;
if (std::numeric_limits<std::size_t>::max() - m_state.data.write.total_bytes < message.size())
return false;

// Wait for the write queue to fall below the max. If it doesn't after a
// randomized delay, drop the connection.
Expand All @@ -774,7 +781,14 @@ namespace net_utils
std::uniform_int_distribution<>(5000, 6000)(rng)
);
};
if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT)

// The bytes check intentionally does not include incoming message size.
// This allows for a soft overflow; a single http response will never fail
// this check, but multiple responses could. Clients can avoid this case
// by reading the entire response before making another request. P2P
// should never hit the MAX_BYTES check (when using default values).
if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
m_state.data.write.total_bytes <= static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit)
return true;
m_state.data.write.wait_consume = true;
bool success = m_state.condition.wait_for(
Expand All @@ -783,8 +797,12 @@ namespace net_utils
[this]{
return (
m_state.status != status_t::RUNNING ||
m_state.data.write.queue.size() <=
ABSTRACT_SERVER_SEND_QUE_MAX_COUNT
(
m_state.data.write.queue.size() <=
ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
m_state.data.write.total_bytes <=
static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit
)
);
}
);
Expand Down Expand Up @@ -816,7 +834,9 @@ namespace net_utils
) {
if (!wait_consume())
return false;
const std::size_t byte_count = message.size();
m_state.data.write.queue.emplace_front(std::move(message));
m_state.data.write.total_bytes += byte_count;
start_write();
}
else {
Expand All @@ -826,6 +846,7 @@ namespace net_utils
m_state.data.write.queue.emplace_front(
message.take_slice(CHUNK_SIZE)
);
m_state.data.write.total_bytes += m_state.data.write.queue.front().size();
start_write();
}
}
Expand Down Expand Up @@ -1369,6 +1390,13 @@ namespace net_utils
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
void boosted_tcp_server<t_protocol_handler>::set_response_soft_limit(const std::size_t limit)
{
assert(m_state != nullptr); // always set in constructor
m_state->response_soft_limit = limit;
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
bool boosted_tcp_server<t_protocol_handler>::run_server(size_t threads_count, bool wait, const boost::thread::attributes& attrs)
{
TRY_ENTRY();
Expand Down
15 changes: 6 additions & 9 deletions contrib/epee/include/net/http_protocol_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include <boost/optional/optional.hpp>
#include <string>
#include <unordered_map>
#include "net_utils_base.h"
#include "http_auth.h"
#include "http_base.h"
Expand All @@ -54,8 +55,10 @@ namespace net_utils
{
std::string m_folder;
std::vector<std::string> m_access_control_origins;
std::unordered_map<std::string, std::size_t> m_connections;
boost::optional<login> m_user;
size_t m_max_content_length{std::numeric_limits<size_t>::max()};
std::size_t m_max_connections{3};
critical_section m_lock;
};

Expand All @@ -70,7 +73,7 @@ namespace net_utils
typedef http_server_config config_type;

simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context);
virtual ~simple_http_connection_handler(){}
virtual ~simple_http_connection_handler();

bool release_protocol()
{
Expand All @@ -86,10 +89,7 @@ namespace net_utils
{
return true;
}
bool after_init_connection()
{
return true;
}
bool after_init_connection();
virtual bool handle_recv(const void* ptr, size_t cb);
virtual bool handle_request(const http::http_request_info& query_info, http_response_info& response);

Expand Down Expand Up @@ -146,6 +146,7 @@ namespace net_utils
protected:
i_service_endpoint* m_psnd_hndlr;
t_connection_context& m_conn_context;
bool m_initialized;
};

template<class t_connection_context>
Expand Down Expand Up @@ -212,10 +213,6 @@ namespace net_utils
}
void handle_qued_callback()
{}
bool after_init_connection()
{
return true;
}

private:
//simple_http_connection_handler::config_type m_stub_config;
Expand Down
34 changes: 33 additions & 1 deletion contrib/epee/include/net/http_protocol_handler.inl
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,43 @@ namespace net_utils
m_newlines(0),
m_bytes_read(0),
m_psnd_hndlr(psnd_hndlr),
m_conn_context(conn_context)
m_conn_context(conn_context),
m_initialized(false)
{

}
//--------------------------------------------------------------------------------------------
template<class t_connection_context>
simple_http_connection_handler<t_connection_context>::~simple_http_connection_handler()
{
try
{
if (m_initialized)
{
CRITICAL_REGION_LOCAL(m_config.m_lock);
auto elem = m_config.m_connections.find(m_conn_context.m_remote_address.host_str());
if (elem != m_config.m_connections.end())
{
if (elem->second == 1 || elem->second == 0)
m_config.m_connections.erase(elem);
else
--(elem->second);
}
}
}
catch (...)
{}
}
//--------------------------------------------------------------------------------------------
template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::after_init_connection()
{
CRITICAL_REGION_LOCAL(m_config.m_lock);
++m_config.m_connections[m_conn_context.m_remote_address.host_str()];
m_initialized = true;
return true;
}
//--------------------------------------------------------------------------------------------
template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::set_ready_state()
{
Expand Down
20 changes: 18 additions & 2 deletions contrib/epee/include/net/http_server_impl_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ namespace epee
{

template<class t_child_class, class t_connection_context = epee::net_utils::connection_context_base>
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>,
net_utils::i_connection_limit
{

public:
Expand All @@ -60,7 +61,8 @@ namespace epee
const std::string& bind_ipv6_address = "::", bool use_ipv6 = false, bool require_ipv4 = true,
std::vector<std::string> access_control_origins = std::vector<std::string>(),
boost::optional<net_utils::http::login> user = boost::none,
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect)
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect,
const std::size_t max_ip_connections = 3, const std::size_t response_soft_limit = 0)
{

//set self as callback handler
Expand All @@ -75,6 +77,9 @@ namespace epee
m_net_server.get_config_object().m_access_control_origins = std::move(access_control_origins);

m_net_server.get_config_object().m_user = std::move(user);
m_net_server.get_config_object().m_max_connections = max_ip_connections;
m_net_server.set_response_soft_limit(response_soft_limit);
m_net_server.set_connection_limit(this);

MGINFO("Binding on " << bind_ip << " (IPv4):" << bind_port);
if (use_ipv6)
Expand Down Expand Up @@ -131,6 +136,17 @@ namespace epee
}

protected:

virtual bool is_host_limit(const net_utils::network_address& na) override final
{
auto& config = m_net_server.get_config_object();
CRITICAL_REGION_LOCAL(config.m_lock);
const auto elem = config.m_connections.find(na.host_str());
if (elem != config.m_connections.end())
return config.m_max_connections <= elem->second;
return false;
}

net_utils::boosted_tcp_server<net_utils::http::http_custom_handler<t_connection_context> > m_net_server;
};
}
18 changes: 17 additions & 1 deletion src/rpc/core_rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ namespace cryptonote
command_line::add_arg(desc, arg_rpc_payment_difficulty);
command_line::add_arg(desc, arg_rpc_payment_credits);
command_line::add_arg(desc, arg_rpc_payment_allow_free_loopback);
command_line::add_arg(desc, arg_rpc_max_ip_connections);
command_line::add_arg(desc, arg_rpc_response_soft_limit);
}
//------------------------------------------------------------------------------------------------------------------------------
core_rpc_server::core_rpc_server(
Expand Down Expand Up @@ -400,7 +402,9 @@ namespace cryptonote
const bool inited = epee::http_server_impl_base<core_rpc_server, connection_context>::init(
rng, std::move(port), std::move(bind_ip_str),
std::move(bind_ipv6_str), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4),
std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options)
std::move(rpc_config->access_control_origins), std::move(http_login), std::move(rpc_config->ssl_options),
command_line::get_arg(vm, arg_rpc_max_ip_connections),
command_line::get_arg(vm, arg_rpc_response_soft_limit)
);

m_net_server.get_config_object().m_max_content_length = MAX_RPC_CONTENT_LENGTH;
Expand Down Expand Up @@ -3885,4 +3889,16 @@ namespace cryptonote
, "Allow free access from the loopback address (ie, the local host)"
, false
};

const command_line::arg_descriptor<std::size_t> core_rpc_server::arg_rpc_max_ip_connections = {
"rpc-max-ip-connections"
, "Max RPC connections per IP permitted"
, 3
};

const command_line::arg_descriptor<std::size_t> core_rpc_server::arg_rpc_response_soft_limit = {
"rpc-response-soft-limit"
, "Max response bytes that can be queued, enforced at next response attempt"
, 25 * 1024 * 1024
};
} // namespace cryptonote
3 changes: 2 additions & 1 deletion src/rpc/core_rpc_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ namespace cryptonote
{
public:

static const command_line::arg_descriptor<bool> arg_public_node;
static const command_line::arg_descriptor<std::string, false, true, 2> arg_rpc_bind_port;
static const command_line::arg_descriptor<std::string> arg_rpc_restricted_bind_port;
static const command_line::arg_descriptor<bool> arg_restricted_rpc;
Expand All @@ -73,6 +72,8 @@ namespace cryptonote
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<bool> arg_rpc_payment_allow_free_loopback;
static const command_line::arg_descriptor<std::size_t> arg_rpc_max_ip_connections;
static const command_line::arg_descriptor<std::size_t> arg_rpc_response_soft_limit;

typedef epee::net_utils::connection_context_base connection_context;

Expand Down
6 changes: 5 additions & 1 deletion src/wallet/wallet_rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ namespace
const command_line::arg_descriptor<std::string> arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"};
const command_line::arg_descriptor<bool> arg_prompt_for_password = {"prompt-for-password", "Prompts for password when not provided", false};
const command_line::arg_descriptor<bool> arg_no_initial_sync = {"no-initial-sync", "Skips the initial sync before listening for connections", false};
const command_line::arg_descriptor<std::size_t> arg_rpc_max_ip_connections = {"rpc-max-ip-connections", "Max RPC connections per IP permitted", 3};
const command_line::arg_descriptor<std::size_t> arg_rpc_response_soft_limit = {"rpc-response-soft-limit", "Max response bytes that can be queued, enforced at next response attempt", 25 * 1024 * 1024};

constexpr const char default_rpc_username[] = "monero";

Expand Down Expand Up @@ -331,7 +333,8 @@ namespace tools
rng, std::move(bind_port), std::move(rpc_config->bind_ip),
std::move(rpc_config->bind_ipv6_address), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4),
std::move(rpc_config->access_control_origins), std::move(http_login),
std::move(rpc_config->ssl_options)
std::move(rpc_config->ssl_options),
command_line::get_arg(vm, arg_rpc_max_ip_connections)
);
}
//------------------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -4974,6 +4977,7 @@ int main(int argc, char** argv) {
command_line::add_arg(desc_params, arg_wallet_dir);
command_line::add_arg(desc_params, arg_prompt_for_password);
command_line::add_arg(desc_params, arg_no_initial_sync);
command_line::add_arg(desc_params, arg_rpc_max_ip_connections);
command_line::add_arg(hidden_options, daemonizer::arg_non_interactive);

daemonizer::init_options(hidden_options, desc_params);
Expand Down
Loading