aboutsummaryrefslogtreecommitdiff
path: root/contrib/epee/include
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/epee/include')
-rw-r--r--contrib/epee/include/math_helper.h1
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.h42
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl339
-rw-r--r--contrib/epee/include/net/connection_basic.hpp46
-rw-r--r--contrib/epee/include/net/http_client.h25
-rw-r--r--contrib/epee/include/net/http_protocol_handler.inl2
-rw-r--r--contrib/epee/include/net/http_server_impl_base.h7
-rw-r--r--contrib/epee/include/net/net_helper.h199
-rw-r--r--contrib/epee/include/net/net_ssl.h68
-rw-r--r--contrib/epee/include/net/net_utils_base.h16
-rw-r--r--contrib/epee/include/net/network_throttle-detail.hpp3
-rw-r--r--contrib/epee/include/stats.h58
-rw-r--r--contrib/epee/include/stats.inl359
13 files changed, 964 insertions, 201 deletions
diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h
index e22e8ee6e..35b649972 100644
--- a/contrib/epee/include/math_helper.h
+++ b/contrib/epee/include/math_helper.h
@@ -243,6 +243,7 @@ namespace math_helper
present = present << 32;
present |= fileTime.dwLowDateTime;
present /= 10; // mic-sec
+ return present;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h
index 6f9e4db5b..76773192e 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.h
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -46,6 +46,7 @@
#include <memory>
#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
#include <boost/array.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
@@ -102,15 +103,19 @@ namespace net_utils
/// Construct a connection with the given io_service.
explicit connection( boost::asio::io_service& io_service,
boost::shared_ptr<shared_state> state,
- t_connection_type connection_type);
+ t_connection_type connection_type,
+ epee::net_utils::ssl_support_t ssl_support,
+ ssl_context_t &ssl_context);
explicit connection( boost::asio::ip::tcp::socket&& sock,
- boost::shared_ptr<shared_state> state,
- t_connection_type connection_type);
+ boost::shared_ptr<shared_state> state,
+ t_connection_type connection_type,
+ epee::net_utils::ssl_support_t ssl_support,
+ ssl_context_t &ssl_context);
+
+
virtual ~connection() noexcept(false);
- /// Get the socket associated with the connection.
- boost::asio::ip::tcp::socket& socket();
/// Start the first asynchronous operation for the connection.
bool start(bool is_income, bool is_multithreaded);
@@ -143,6 +148,10 @@ namespace net_utils
//------------------------------------------------------
boost::shared_ptr<connection<t_protocol_handler> > safe_shared_from_this();
bool shutdown();
+ /// Handle completion of a receive operation.
+ void handle_receive(const boost::system::error_code& e,
+ std::size_t bytes_transferred);
+
/// Handle completion of a read operation.
void handle_read(const boost::system::error_code& e,
std::size_t bytes_transferred);
@@ -160,7 +169,7 @@ namespace net_utils
/// Buffer for incoming data.
boost::array<char, 8192> buffer_;
- //boost::array<char, 1024> buffer_;
+ size_t buffer_ssl_init_fill;
t_connection_context context;
@@ -199,6 +208,13 @@ namespace net_utils
class boosted_tcp_server
: private boost::noncopyable
{
+ enum try_connect_result_t
+ {
+ CONNECT_SUCCESS,
+ CONNECT_FAILURE,
+ CONNECT_NO_SSL,
+ };
+
public:
typedef boost::shared_ptr<connection<t_protocol_handler> > connection_ptr;
typedef typename t_protocol_handler::connection_context t_connection_context;
@@ -212,8 +228,8 @@ namespace net_utils
std::map<std::string, t_connection_type> server_type_map;
void create_server_type_map();
- bool init_server(uint32_t port, const std::string address = "0.0.0.0");
- bool init_server(const std::string port, const std::string& address = "0.0.0.0");
+ bool init_server(uint32_t port, const std::string address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, bool allow_any_cert = false);
+ bool init_server(const std::string port, const std::string& address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, bool allow_any_cert = false);
/// Run the server's io_service loop.
bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes());
@@ -241,10 +257,11 @@ namespace net_utils
default_remote = std::move(remote);
}
- bool add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote);
- bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0");
+ bool add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
+ try_connect_result_t try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support);
+ bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
template<class t_callback>
- bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0");
+ bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect);
typename t_protocol_handler::config_type& get_config_object()
{
@@ -364,6 +381,9 @@ namespace net_utils
boost::mutex connections_mutex;
std::set<connection_ptr> connections_;
+ ssl_context_t m_ssl_context;
+ std::list<std::string> m_allowed_certificates;
+
}; // class <>boosted_tcp_server
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index eda4d7f7b..39d6911e3 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -78,19 +78,23 @@ PRAGMA_WARNING_DISABLE_VS(4355)
template<class t_protocol_handler>
connection<t_protocol_handler>::connection( boost::asio::io_service& io_service,
boost::shared_ptr<shared_state> state,
- t_connection_type connection_type
+ t_connection_type connection_type,
+ epee::net_utils::ssl_support_t ssl_support,
+ ssl_context_t &ssl_context
)
- : connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type)
+ : connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type, ssl_support, ssl_context)
{
}
template<class t_protocol_handler>
connection<t_protocol_handler>::connection( boost::asio::ip::tcp::socket&& sock,
boost::shared_ptr<shared_state> state,
- t_connection_type connection_type
+ t_connection_type connection_type,
+ epee::net_utils::ssl_support_t ssl_support,
+ ssl_context_t &ssl_context
)
:
- connection_basic(std::move(sock), state),
+ connection_basic(std::move(sock), state, ssl_support, ssl_context),
m_protocol_handler(this, check_and_get(state).config, context),
m_connection_type( connection_type ),
m_throttle_speed_in("speed_in", "throttle_speed_in"),
@@ -109,17 +113,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
{
if(!m_was_shutdown)
{
- _dbg3("[sock " << socket_.native_handle() << "] Socket destroyed without shutdown.");
+ _dbg3("[sock " << socket().native_handle() << "] Socket destroyed without shutdown.");
shutdown();
}
- _dbg3("[sock " << socket_.native_handle() << "] Socket destroyed");
- }
- //---------------------------------------------------------------------------------
- template<class t_protocol_handler>
- boost::asio::ip::tcp::socket& connection<t_protocol_handler>::socket()
- {
- return socket_;
+ _dbg3("[sock " << socket().native_handle() << "] Socket destroyed");
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
@@ -142,7 +140,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
TRY_ENTRY();
boost::system::error_code ec;
- auto remote_ep = socket_.remote_endpoint(ec);
+ auto remote_ep = socket().remote_endpoint(ec);
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get remote endpoint: " << ec.message() << ':' << ec.value());
CHECK_AND_NO_ASSERT_MES(remote_ep.address().is_v4(), false, "IPv6 not supported here");
@@ -168,10 +166,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
const boost::uuids::uuid random_uuid = boost::uuids::random_generator()();
context = t_connection_context{};
- context.set_details(random_uuid, std::move(real_remote), is_income);
+ bool ssl = m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ context.set_details(random_uuid, std::move(real_remote), is_income, ssl);
boost::system::error_code ec;
- auto local_ep = socket_.local_endpoint(ec);
+ auto local_ep = socket().local_endpoint(ec);
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value());
_dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
@@ -180,7 +179,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
if(static_cast<shared_state&>(get_stats()).pfilter && !static_cast<shared_state&>(get_stats()).pfilter->is_remote_host_allowed(context.m_remote_address))
{
- _dbg2("[sock " << socket_.native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection");
+ _dbg2("[sock " << socket().native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection");
close();
return false;
}
@@ -192,11 +191,21 @@ PRAGMA_WARNING_DISABLE_VS(4355)
reset_timer(get_default_timeout(), false);
- socket_.async_read_some(boost::asio::buffer(buffer_),
- strand_.wrap(
- boost::bind(&connection<t_protocol_handler>::handle_read, self,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred)));
+ // first read on the raw socket to detect SSL for the server
+ buffer_ssl_init_fill = 0;
+ if (is_income && m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
+ socket().async_receive(boost::asio::buffer(buffer_),
+ boost::asio::socket_base::message_peek,
+ strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_receive, self,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ else
+ async_read_some(boost::asio::buffer(buffer_),
+ strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_read, self,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
#if !defined(_WIN32) || !defined(__i686)
// not supported before Windows7, too lazy for runtime check
// Just exclude for 32bit windows builds
@@ -204,12 +213,12 @@ PRAGMA_WARNING_DISABLE_VS(4355)
int tos = get_tos_flag();
boost::asio::detail::socket_option::integer< IPPROTO_IP, IP_TOS >
optionTos( tos );
- socket_.set_option( optionTos );
+ socket().set_option( optionTos );
//_dbg1("Set ToS flag to " << tos);
#endif
boost::asio::ip::tcp::no_delay noDelayOption(false);
- socket_.set_option(noDelayOption);
+ socket().set_option(noDelayOption);
return true;
@@ -234,7 +243,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
template<class t_protocol_handler>
boost::asio::io_service& connection<t_protocol_handler>::get_io_service()
{
- return socket_.get_io_service();
+ return socket().get_io_service();
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
@@ -246,9 +255,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
auto self = safe_shared_from_this();
if(!self)
return false;
- //_dbg3("[sock " << socket_.native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number);
+ //_dbg3("[sock " << socket().native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number);
CRITICAL_REGION_LOCAL(self->m_self_refs_lock);
- //_dbg3("[sock " << socket_.native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number);
+ //_dbg3("[sock " << socket().native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number);
if(m_was_shutdown)
return false;
++m_reference_count;
@@ -262,9 +271,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
{
TRY_ENTRY();
boost::shared_ptr<connection<t_protocol_handler> > back_connection_copy;
- LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] release");
+ LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] release");
CRITICAL_REGION_BEGIN(m_self_refs_lock);
- CHECK_AND_ASSERT_MES(m_reference_count, false, "[sock " << socket_.native_handle() << "] m_reference_count already at 0 at connection<t_protocol_handler>::release() call");
+ CHECK_AND_ASSERT_MES(m_reference_count, false, "[sock " << socket().native_handle() << "] m_reference_count already at 0 at connection<t_protocol_handler>::release() call");
// is this the last reference?
if (--m_reference_count == 0) {
// move the held reference to a local variable, keeping the object alive until the function terminates
@@ -290,7 +299,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
std::string address, port;
boost::system::error_code e;
- boost::asio::ip::tcp::endpoint endpoint = socket_.remote_endpoint(e);
+ boost::asio::ip::tcp::endpoint endpoint = socket().remote_endpoint(e);
if (e)
{
address = "<not connected>";
@@ -302,7 +311,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
port = boost::lexical_cast<std::string>(endpoint.port());
}
MDEBUG(" connection type " << to_string( m_connection_type ) << " "
- << socket_.local_endpoint().address().to_string() << ":" << socket_.local_endpoint().port()
+ << socket().local_endpoint().address().to_string() << ":" << socket().local_endpoint().port()
<< " <--> " << context.m_remote_address.str() << " (via " << address << ":" << port << ")");
}
//---------------------------------------------------------------------------------
@@ -311,7 +320,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
std::size_t bytes_transferred)
{
TRY_ENTRY();
- //_info("[sock " << socket_.native_handle() << "] Async read calledback.");
+ //_info("[sock " << socket().native_handle() << "] Async read calledback.");
if (!e)
{
@@ -347,7 +356,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
} while(delay > 0);
} // any form of sleeping
- //_info("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred);
+ //_info("[sock " << socket().native_handle() << "] RECV " << bytes_transferred);
logger_handle_net_read(bytes_transferred);
context.m_last_recv = time(NULL);
context.m_recv_cnt += bytes_transferred;
@@ -355,7 +364,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred);
if(!recv_res)
{
- //_info("[sock " << socket_.native_handle() << "] protocol_want_close");
+ //_info("[sock " << socket().native_handle() << "] protocol_want_close");
//some error in protocol, protocol handler ask to close connection
boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1);
@@ -369,24 +378,24 @@ PRAGMA_WARNING_DISABLE_VS(4355)
}else
{
reset_timer(get_timeout_from_bytes_read(bytes_transferred), false);
- socket_.async_read_some(boost::asio::buffer(buffer_),
+ async_read_some(boost::asio::buffer(buffer_),
strand_.wrap(
boost::bind(&connection<t_protocol_handler>::handle_read, connection<t_protocol_handler>::shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
- //_info("[sock " << socket_.native_handle() << "]Async read requested.");
+ //_info("[sock " << socket().native_handle() << "]Async read requested.");
}
}else
{
- _dbg3("[sock " << socket_.native_handle() << "] Some not success at read: " << e.message() << ':' << e.value());
+ _dbg3("[sock " << socket().native_handle() << "] Some not success at read: " << e.message() << ':' << e.value());
if(e.value() != 2)
{
- _dbg3("[sock " << socket_.native_handle() << "] Some problems at read: " << e.message() << ':' << e.value());
+ _dbg3("[sock " << socket().native_handle() << "] Some problems at read: " << e.message() << ':' << e.value());
shutdown();
}
else
{
- _dbg3("[sock " << socket_.native_handle() << "] peer closed connection");
+ _dbg3("[sock " << socket().native_handle() << "] peer closed connection");
if (m_ready_to_close)
shutdown();
}
@@ -400,13 +409,85 @@ PRAGMA_WARNING_DISABLE_VS(4355)
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
+ void connection<t_protocol_handler>::handle_receive(const boost::system::error_code& e,
+ std::size_t bytes_transferred)
+ {
+ TRY_ENTRY();
+ if (e)
+ {
+ // offload the error case
+ handle_read(e, bytes_transferred);
+ return;
+ }
+
+ reset_timer(get_timeout_from_bytes_read(bytes_transferred), false);
+
+ buffer_ssl_init_fill += bytes_transferred;
+ if (buffer_ssl_init_fill <= get_ssl_magic_size())
+ {
+ socket().async_receive(boost::asio::buffer(buffer_.data() + buffer_ssl_init_fill, buffer_.size() - buffer_ssl_init_fill),
+ boost::asio::socket_base::message_peek,
+ strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_receive, connection<t_protocol_handler>::shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ return;
+ }
+
+ // detect SSL
+ if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
+ {
+ if (is_ssl((const unsigned char*)buffer_.data(), buffer_ssl_init_fill))
+ {
+ MDEBUG("That looks like SSL");
+ m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; // read/write to the SSL socket
+ }
+ else
+ {
+ MDEBUG("That does not look like SSL");
+ m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; // read/write to the raw socket
+ }
+ }
+
+ if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ {
+ // Handshake
+ if (!handshake(boost::asio::ssl::stream_base::server))
+ {
+ MERROR("SSL handshake failed");
+ boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1);
+ bool do_shutdown = false;
+ CRITICAL_REGION_BEGIN(m_send_que_lock);
+ if(!m_send_que.size())
+ do_shutdown = true;
+ CRITICAL_REGION_END();
+ if(do_shutdown)
+ shutdown();
+ return;
+ }
+ }
+
+ async_read_some(boost::asio::buffer(buffer_),
+ strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_read, connection<t_protocol_handler>::shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+
+ // If an error occurs then no new asynchronous operations are started. This
+ // means that all shared_ptr references to the connection object will
+ // disappear and the object will be destroyed automatically after this
+ // handler returns. The connection class's destructor closes the socket.
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::handle_receive", void());
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
bool connection<t_protocol_handler>::call_run_once_service_io()
{
TRY_ENTRY();
if(!m_is_multithreaded)
{
//single thread model, we can wait in blocked call
- size_t cnt = socket_.get_io_service().run_one();
+ size_t cnt = socket().get_io_service().run_one();
if(!cnt)//service is going to quit
return false;
}else
@@ -416,7 +497,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
//if no handlers were called
//TODO: Maybe we need to have have critical section + event + callback to upper protocol to
//ask it inside(!) critical region if we still able to go in event wait...
- size_t cnt = socket_.get_io_service().poll_one();
+ size_t cnt = socket().get_io_service().poll_one();
if(!cnt)
misc_utils::sleep_no_w(1);
}
@@ -525,7 +606,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
context.m_max_speed_up = std::max(context.m_max_speed_up, context.m_current_speed_up);
}
- //_info("[sock " << socket_.native_handle() << "] SEND " << cb);
+ //_info("[sock " << socket().native_handle() << "] SEND " << cb);
context.m_last_send = time(NULL);
context.m_send_cnt += cb;
//some data should be wrote to stream
@@ -570,7 +651,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
MDEBUG("do_send_chunk() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size());
//do_send_handler_delayed( ptr , size_now ); // (((H))) // empty function
- LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
+ LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] Async send requested " << m_send_que.front().size());
}
else
{ // no active operation
@@ -588,14 +669,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), false, "Unexpected queue size");
reset_timer(get_default_timeout(), false);
- boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now ) ,
+ async_write(boost::asio::buffer(m_send_que.front().data(), size_now ) ,
//strand_.wrap(
boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
//)
);
//_dbg3("(chunk): " << size_now);
//logger_handle_net_write(size_now);
- //_info("[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
+ //_info("[sock " << socket().native_handle() << "] Async send requested " << m_send_que.front().size());
}
//do_send_handler_stop( ptr , cb ); // empty function
@@ -680,7 +761,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
// Initiate graceful connection closure.
m_timer.cancel();
boost::system::error_code ignored_ec;
- socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
+ socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
+ socket().close();
if (!m_host.empty())
{
try { host_count(m_host, -1); } catch (...) { /* ignore */ }
@@ -698,7 +780,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
auto self = safe_shared_from_this();
if(!self)
return false;
- //_info("[sock " << socket_.native_handle() << "] Que Shutdown called.");
+ //_info("[sock " << socket().native_handle() << "] Que Shutdown called.");
m_timer.cancel();
size_t send_que_size = 0;
CRITICAL_REGION_BEGIN(m_send_que_lock);
@@ -733,11 +815,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
void connection<t_protocol_handler>::handle_write(const boost::system::error_code& e, size_t cb)
{
TRY_ENTRY();
- LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send calledback " << cb);
+ LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] Async send calledback " << cb);
if (e)
{
- _dbg1("[sock " << socket_.native_handle() << "] Some problems at write: " << e.message() << ':' << e.value());
+ _dbg1("[sock " << socket().native_handle() << "] Some problems at write: " << e.message() << ':' << e.value());
shutdown();
return;
}
@@ -752,7 +834,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
CRITICAL_REGION_BEGIN(m_send_que_lock);
if(m_send_que.empty())
{
- _erro("[sock " << socket_.native_handle() << "] m_send_que.size() == 0 at handle_write!");
+ _erro("[sock " << socket().native_handle() << "] m_send_que.size() == 0 at handle_write!");
return;
}
@@ -772,11 +854,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
if (speed_limit_is_enabled())
do_send_handler_write_from_queue(e, m_send_que.front().size() , m_send_que.size()); // (((H)))
CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), void(), "Unexpected queue size");
- boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now) ,
- // strand_.wrap(
- boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2)
- // )
- );
+ async_write(boost::asio::buffer(m_send_que.front().data(), size_now) ,
+ // strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2)
+ // )
+ );
//_dbg3("(normal)" << size_now);
}
CRITICAL_REGION_END();
@@ -817,7 +899,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
m_threads_count(0),
m_thread_index(0),
m_connection_type( connection_type ),
- new_connection_()
+ new_connection_(),
+ m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}})
{
create_server_type_map();
m_thread_name_prefix = "NET";
@@ -833,7 +916,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
m_threads_count(0),
m_thread_index(0),
m_connection_type(connection_type),
- new_connection_()
+ new_connection_(),
+ m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}})
{
create_server_type_map();
m_thread_name_prefix = "NET";
@@ -855,12 +939,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
- bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address)
+ bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, bool allow_any_cert)
{
TRY_ENTRY();
m_stop_signal_sent = false;
m_port = port;
m_address = address;
+ if (ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
+ m_ssl_context = create_ssl_context(private_key_and_certificate_path, allowed_certificates, allow_any_cert);
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
@@ -872,7 +958,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
m_port = binded_endpoint.port();
MDEBUG("start accept");
- new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type));
+ new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error));
@@ -894,7 +980,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
PUSH_WARNINGS
DISABLE_GCC_WARNING(maybe-uninitialized)
template<class t_protocol_handler>
- bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address)
+ bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, bool allow_any_cert)
{
uint32_t p = 0;
@@ -902,7 +988,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
MERROR("Failed to convert port no = " << port);
return false;
}
- return this->init_server(p, address);
+ return this->init_server(p, address, ssl_support, private_key_and_certificate_path, allowed_certificates, allow_any_cert);
}
POP_WARNINGS
//---------------------------------------------------------------------------------
@@ -1066,11 +1152,18 @@ POP_WARNINGS
if (!e)
{
if (m_connection_type == e_connection_type_RPC) {
- MDEBUG("New server for RPC connections");
+ const char *ssl_message = "unknown";
+ switch (new_connection_->get_ssl_support())
+ {
+ case epee::net_utils::ssl_support_t::e_ssl_support_disabled: ssl_message = "disabled"; break;
+ case epee::net_utils::ssl_support_t::e_ssl_support_enabled: ssl_message = "enabled"; break;
+ case epee::net_utils::ssl_support_t::e_ssl_support_autodetect: ssl_message = "autodetection"; break;
+ }
+ MDEBUG("New server for RPC connections, SSL " << ssl_message);
new_connection_->setRpcStation(); // hopefully this is not needed actually
}
connection_ptr conn(std::move(new_connection_));
- new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type));
+ new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support(), m_ssl_context));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error));
@@ -1078,10 +1171,16 @@ POP_WARNINGS
boost::asio::socket_base::keep_alive opt(true);
conn->socket().set_option(opt);
+ bool res;
if (default_remote.get_type_id() == net_utils::address_type::invalid)
- conn->start(true, 1 < m_threads_count);
+ res = conn->start(true, 1 < m_threads_count);
else
- conn->start(true, 1 < m_threads_count, default_remote);
+ res = conn->start(true, 1 < m_threads_count, default_remote);
+ if (!res)
+ {
+ conn->cancel();
+ return;
+ }
conn->save_dbg_log();
return;
}
@@ -1099,18 +1198,18 @@ POP_WARNINGS
assert(m_state != nullptr); // always set in constructor
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
misc_utils::sleep_no_w(100);
- new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type));
+ new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, new_connection_->get_ssl_support(), m_ssl_context));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
boost::asio::placeholders::error));
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
- bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote)
+ bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support)
{
if(std::addressof(get_io_service()) == std::addressof(sock.get_io_service()))
{
- connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type));
+ connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type, ssl_support, m_ssl_context));
if(conn->start(false, 1 < m_threads_count, std::move(real_remote)))
{
conn->get_context(out);
@@ -1126,34 +1225,10 @@ POP_WARNINGS
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
- bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip)
+ typename boosted_tcp_server<t_protocol_handler>::try_connect_result_t boosted_tcp_server<t_protocol_handler>::try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support)
{
TRY_ENTRY();
- connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type) );
- connections_mutex.lock();
- connections_.insert(new_connection_l);
- MDEBUG("connections_ size now " << connections_.size());
- connections_mutex.unlock();
- epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); });
- boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
-
- //////////////////////////////////////////////////////////////////////////
- boost::asio::ip::tcp::resolver resolver(io_service_);
- boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
- boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
- boost::asio::ip::tcp::resolver::iterator end;
- if(iterator == end)
- {
- _erro("Failed to resolve " << adr);
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
-
-
- //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
- boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
-
sock_.open(remote_endpoint.protocol());
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
{
@@ -1165,7 +1240,7 @@ POP_WARNINGS
MERROR("Error binding to " << bind_ip << ": " << ec.message());
if (sock_.is_open())
sock_.close();
- return false;
+ return CONNECT_FAILURE;
}
}
@@ -1199,14 +1274,14 @@ POP_WARNINGS
{
if (sock_.is_open())
sock_.close();
- return false;
+ return CONNECT_FAILURE;
}
if(local_shared_context->ec == boost::asio::error::would_block && !r)
{
//timeout
sock_.close();
_dbg3("Failed to connect to " << adr << ":" << port << ", because of timeout (" << conn_timeout << ")");
- return false;
+ return CONNECT_FAILURE;
}
}
ec = local_shared_context->ec;
@@ -1216,11 +1291,79 @@ POP_WARNINGS
_dbg3("Some problems at connect, message: " << ec.message());
if (sock_.is_open())
sock_.close();
- return false;
+ return CONNECT_FAILURE;
}
_dbg3("Connected success to " << adr << ':' << port);
+ const epee::net_utils::ssl_support_t ssl_support = new_connection_l->get_ssl_support();
+ if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
+ {
+ // Handshake
+ MDEBUG("Handshaking SSL...");
+ if (!new_connection_l->handshake(boost::asio::ssl::stream_base::client))
+ {
+ if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
+ {
+ boost::system::error_code ignored_ec;
+ sock_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
+ sock_.close();
+ return CONNECT_NO_SSL;
+ }
+ MERROR("SSL handshake failed");
+ if (sock_.is_open())
+ sock_.close();
+ return CONNECT_FAILURE;
+ }
+ }
+
+ return CONNECT_SUCCESS;
+
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::try_connect", CONNECT_FAILURE);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
+ {
+ TRY_ENTRY();
+
+ connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context) );
+ connections_mutex.lock();
+ connections_.insert(new_connection_l);
+ MDEBUG("connections_ size now " << connections_.size());
+ connections_mutex.unlock();
+ epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); });
+ boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
+
+ //////////////////////////////////////////////////////////////////////////
+ boost::asio::ip::tcp::resolver resolver(io_service_);
+ boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
+ boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
+ boost::asio::ip::tcp::resolver::iterator end;
+ if(iterator == end)
+ {
+ _erro("Failed to resolve " << adr);
+ return false;
+ }
+ //////////////////////////////////////////////////////////////////////////
+
+
+ //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
+ boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
+
+ auto try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip, conn_timeout, ssl_support);
+ if (try_connect_result == CONNECT_FAILURE)
+ return false;
+ if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL)
+ {
+ // we connected, but could not connect with SSL, try without
+ MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
+ new_connection_l->disable_ssl();
+ try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip, conn_timeout, epee::net_utils::ssl_support_t::e_ssl_support_disabled);
+ if (try_connect_result != CONNECT_SUCCESS)
+ return false;
+ }
+
// start adds the connection to the config object's list, so we don't need to have it locally anymore
connections_mutex.lock();
connections_.erase(new_connection_l);
@@ -1245,10 +1388,10 @@ POP_WARNINGS
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler> template<class t_callback>
- bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip)
+ bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
{
TRY_ENTRY();
- connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type) );
+ connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context) );
connections_mutex.lock();
connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size());
diff --git a/contrib/epee/include/net/connection_basic.hpp b/contrib/epee/include/net/connection_basic.hpp
index b1b271db9..328f9afbf 100644
--- a/contrib/epee/include/net/connection_basic.hpp
+++ b/contrib/epee/include/net/connection_basic.hpp
@@ -47,8 +47,10 @@
#include <memory>
#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
#include "net/net_utils_base.h"
+#include "net/net_ssl.h"
#include "syncobj.h"
namespace epee
@@ -95,16 +97,56 @@ class connection_basic { // not-templated base class for rapid developmet of som
/// Strand to ensure the connection's handlers are not called concurrently.
boost::asio::io_service::strand strand_;
/// Socket for the connection.
- boost::asio::ip::tcp::socket socket_;
+ ssl_context_t &m_ssl_context;
+ ssl_support_t m_ssl_support;
+ boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
public:
// first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator
- connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats);
+ connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context);
+ connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context);
virtual ~connection_basic() noexcept(false);
//! \return `socket_stats` object passed in construction (ptr never changes).
socket_stats& get_stats() noexcept { return *m_stats; /* verified in constructor */ }
+ connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number, ssl_support_t ssl, ssl_context_t &ssl_context);
+
+ boost::asio::ip::tcp::socket& socket() { return socket_.next_layer(); }
+ ssl_support_t get_ssl_support() const { return m_ssl_support; }
+ void disable_ssl() { m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; }
+
+ bool handshake(boost::asio::ssl::stream_base::handshake_type type)
+ {
+ return ssl_handshake(socket_, type, m_ssl_context);
+ }
+
+ template<typename MutableBufferSequence, typename ReadHandler>
+ void async_read_some(const MutableBufferSequence &buffers, ReadHandler &&handler)
+ {
+ if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ socket_.async_read_some(buffers, std::forward<ReadHandler>(handler));
+ else
+ socket().async_read_some(buffers, std::forward<ReadHandler>(handler));
+ }
+
+ template<typename ConstBufferSequence, typename WriteHandler>
+ void async_write_some(const ConstBufferSequence &buffers, WriteHandler &&handler)
+ {
+ if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ socket_.async_write_some(buffers, std::forward<WriteHandler>(handler));
+ else
+ socket().async_write_some(buffers, std::forward<WriteHandler>(handler));
+ }
+
+ template<typename ConstBufferSequence, typename WriteHandler>
+ void async_write(const ConstBufferSequence &buffers, WriteHandler &&handler)
+ {
+ if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ boost::asio::async_write(socket_, buffers, std::forward<WriteHandler>(handler));
+ else
+ boost::asio::async_write(socket(), buffers, std::forward<WriteHandler>(handler));
+ }
// various handlers to be called from connection class:
void do_send_handler_write(const void * ptr , size_t cb);
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h
index e01691794..34b3ac06c 100644
--- a/contrib/epee/include/net/http_client.h
+++ b/contrib/epee/include/net/http_client.h
@@ -275,7 +275,10 @@ namespace net_utils
chunked_state m_chunked_state;
std::string m_chunked_cache;
critical_section m_lock;
- bool m_ssl;
+ epee::net_utils::ssl_support_t m_ssl_support;
+ std::pair<std::string, std::string> m_ssl_private_key_and_certificate_path;
+ std::list<std::string> m_ssl_allowed_certificates;
+ bool m_ssl_allow_any_cert;
public:
explicit http_simple_client_template()
@@ -293,35 +296,39 @@ namespace net_utils
, m_chunked_state()
, m_chunked_cache()
, m_lock()
- , m_ssl(false)
+ , m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{}
const std::string &get_host() const { return m_host_buff; };
const std::string &get_port() const { return m_port; };
- bool set_server(const std::string& address, boost::optional<login> user, bool ssl = false)
+ bool set_server(const std::string& address, boost::optional<login> user, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_ssl_certificates = {}, bool allow_any_cert = false)
{
http::url_content parsed{};
const bool r = parse_url(address, parsed);
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
- set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl);
+ set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl_support, private_key_and_certificate_path, allowed_ssl_certificates, allow_any_cert);
return true;
}
- void set_server(std::string host, std::string port, boost::optional<login> user, bool ssl = false)
+ void set_server(std::string host, std::string port, boost::optional<login> user, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_ssl_certificates = {}, bool allow_any_cert = false)
{
CRITICAL_REGION_LOCAL(m_lock);
disconnect();
m_host_buff = std::move(host);
m_port = std::move(port);
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
- m_ssl = ssl;
+ m_ssl_support = ssl_support;
+ m_ssl_private_key_and_certificate_path = private_key_and_certificate_path;
+ m_ssl_allowed_certificates = allowed_ssl_certificates;
+ m_ssl_allow_any_cert = allow_any_cert;
+ m_net_client.set_ssl(m_ssl_support, m_ssl_private_key_and_certificate_path, m_ssl_allowed_certificates, m_ssl_allow_any_cert);
}
bool connect(std::chrono::milliseconds timeout)
{
CRITICAL_REGION_LOCAL(m_lock);
- return m_net_client.connect(m_host_buff, m_port, timeout, m_ssl);
+ return m_net_client.connect(m_host_buff, m_port, timeout, "0.0.0.0");
}
//---------------------------------------------------------------------------
bool disconnect()
@@ -330,10 +337,10 @@ namespace net_utils
return m_net_client.disconnect();
}
//---------------------------------------------------------------------------
- bool is_connected()
+ bool is_connected(bool *ssl = NULL)
{
CRITICAL_REGION_LOCAL(m_lock);
- return m_net_client.is_connected();
+ return m_net_client.is_connected(ssl);
}
//---------------------------------------------------------------------------
virtual bool handle_target_data(std::string& piece_of_transfer)
diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl
index b53bdc200..ae8e43477 100644
--- a/contrib/epee/include/net/http_protocol_handler.inl
+++ b/contrib/epee/include/net/http_protocol_handler.inl
@@ -677,7 +677,7 @@ namespace net_utils
//add additional fields, if it is
for(fields_list::const_iterator it = response.m_additional_fields.begin(); it!=response.m_additional_fields.end(); it++)
- buf += it->first + ":" + it->second + "\r\n";
+ buf += it->first + ": " + it->second + "\r\n";
buf+="\r\n";
diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h
index 5669824c1..236067580 100644
--- a/contrib/epee/include/net/http_server_impl_base.h
+++ b/contrib/epee/include/net/http_server_impl_base.h
@@ -58,7 +58,10 @@ namespace epee
bool init(std::function<void(size_t, uint8_t*)> rng, const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
std::vector<std::string> access_control_origins = std::vector<std::string>(),
- boost::optional<net_utils::http::login> user = boost::none)
+ boost::optional<net_utils::http::login> user = boost::none,
+ epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect,
+ const std::pair<std::string, std::string> &private_key_and_certificate_path = {},
+ const std::list<std::string> &allowed_certificates = std::list<std::string>(), bool allow_any_cert = false)
{
//set self as callback handler
@@ -75,7 +78,7 @@ namespace epee
m_net_server.get_config_object().m_user = std::move(user);
MGINFO("Binding on " << bind_ip << ":" << bind_port);
- bool res = m_net_server.init_server(bind_port, bind_ip);
+ bool res = m_net_server.init_server(bind_port, bind_ip, ssl_support, private_key_and_certificate_path, allowed_certificates, allow_any_cert);
if(!res)
{
LOG_ERROR("Failed to bind server");
diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h
index 94744ac21..5d9bb61cf 100644
--- a/contrib/epee/include/net/net_helper.h
+++ b/contrib/epee/include/net/net_helper.h
@@ -40,6 +40,7 @@
#include <boost/lambda/lambda.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include "net/net_utils_base.h"
+#include "net/net_ssl.h"
#include "misc_language.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -57,6 +58,13 @@ namespace net_utils
class blocked_mode_client
{
+ enum try_connect_result_t
+ {
+ CONNECT_SUCCESS,
+ CONNECT_FAILURE,
+ CONNECT_NO_SSL,
+ };
+
struct handler_obj
@@ -84,9 +92,9 @@ namespace net_utils
m_connected(false),
m_deadline(m_io_service),
m_shutdowned(0),
- m_ssl(false),
- m_ctx(boost::asio::ssl::context::sslv23),
- m_ssl_socket(m_io_service,m_ctx)
+ m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect),
+ m_ctx({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}}),
+ m_ssl_socket(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service,m_ctx.context))
{
@@ -110,28 +118,92 @@ namespace net_utils
catch(...) { /* ignore */ }
}
+ inline void set_ssl(epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_certificates = std::list<std::string>(), bool allow_any_cert = false)
+ {
+ if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_disabled)
+ m_ctx = {boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}};
+ else
+ m_ctx = create_ssl_context(private_key_and_certificate_path, allowed_certificates, allow_any_cert);
+ m_ssl_support = ssl_support;
+ }
+
inline
- bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
+ bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
{
- return connect(addr, std::to_string(port), timeout, ssl, bind_ip);
+ return connect(addr, std::to_string(port), timeout, bind_ip);
}
inline
- bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
+ try_connect_result_t try_connect(const std::string& addr, const std::string& port, const boost::asio::ip::tcp::endpoint &remote_endpoint, std::chrono::milliseconds timeout, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
{
- m_connected = false;
- m_ssl = ssl;
+ m_ssl_socket->next_layer().open(remote_endpoint.protocol());
+ if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
+ {
+ boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0);
+ m_ssl_socket->next_layer().bind(local_endpoint);
+ }
+
+
+ m_deadline.expires_from_now(timeout);
+
+ boost::system::error_code ec = boost::asio::error::would_block;
+
+ m_ssl_socket->next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
+ while (ec == boost::asio::error::would_block)
+ {
+ m_io_service.run_one();
+ }
+
+ if (!ec && m_ssl_socket->next_layer().is_open())
+ {
+ m_connected = true;
+ m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
+ // SSL Options
+ if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
+ {
+ if (!ssl_handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, m_ctx))
+ {
+ if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
+ {
+ boost::system::error_code ignored_ec;
+ m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
+ m_ssl_socket->next_layer().close();
+ m_connected = false;
+ return CONNECT_NO_SSL;
+ }
+ else
+ {
+ MWARNING("Failed to establish SSL connection");
+ m_connected = false;
+ return CONNECT_FAILURE;
+ }
+ }
+ m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ }
+ return CONNECT_SUCCESS;
+ }else
+ {
+ MWARNING("Some problems at connect, message: " << ec.message());
+ return CONNECT_FAILURE;
+ }
+
+ }
+
+ inline
+ bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
+ {
+ m_connected = false;
try
{
- m_ssl_socket.next_layer().close();
+ m_ssl_socket->next_layer().close();
// Set SSL options
// disable sslv2
- m_ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
- m_ctx.set_default_verify_paths();
+ m_ctx.context.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
+ m_ctx.context.set_default_verify_paths();
+ m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx.context));
// Get a list of endpoints corresponding to the server name.
-
//////////////////////////////////////////////////////////////////////////
@@ -151,45 +223,20 @@ namespace net_utils
//boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
-
- m_ssl_socket.next_layer().open(remote_endpoint.protocol());
- if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
- {
- boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0);
- m_ssl_socket.next_layer().bind(local_endpoint);
- }
-
-
- m_deadline.expires_from_now(timeout);
-
-
- boost::system::error_code ec = boost::asio::error::would_block;
-
- m_ssl_socket.next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
- while (ec == boost::asio::error::would_block)
- {
- m_io_service.run_one();
- }
-
- if (!ec && m_ssl_socket.next_layer().is_open())
+ try_connect_result_t try_connect_result = try_connect(addr, port, remote_endpoint, timeout, bind_ip, m_ssl_support);
+ if (try_connect_result == CONNECT_FAILURE)
+ return false;
+ if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{
- m_connected = true;
- m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
- // SSL Options
- if(m_ssl) {
- // Disable verification of host certificate
- m_ssl_socket.set_verify_mode(boost::asio::ssl::verify_peer);
- // Handshake
- m_ssl_socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
- m_ssl_socket.handshake(boost::asio::ssl::stream_base::client);
+ m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ if (try_connect_result == CONNECT_NO_SSL)
+ {
+ MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL");
+ m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled;
+ if (try_connect(addr, port, remote_endpoint, timeout, bind_ip, m_ssl_support) != CONNECT_SUCCESS)
+ return false;
}
- return true;
- }else
- {
- MWARNING("Some problems at connect, message: " << ec.message());
- return false;
}
-
}
catch(const boost::system::system_error& er)
{
@@ -213,9 +260,9 @@ namespace net_utils
if(m_connected)
{
m_connected = false;
- if(m_ssl)
+ if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
shutdown_ssl();
- m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
+ m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
}
}
@@ -342,9 +389,13 @@ namespace net_utils
return true;
}
- bool is_connected()
+ bool is_connected(bool *ssl = NULL)
{
- return m_connected && m_ssl_socket.next_layer().is_open();
+ if (!m_connected || !m_ssl_socket->next_layer().is_open())
+ return false;
+ if (ssl)
+ *ssl = m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+ return true;
}
inline
@@ -506,15 +557,15 @@ namespace net_utils
{
m_deadline.cancel();
boost::system::error_code ec;
- if(m_ssl)
+ if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
shutdown_ssl();
- m_ssl_socket.next_layer().cancel(ec);
+ m_ssl_socket->next_layer().cancel(ec);
if(ec)
MDEBUG("Problems at cancel: " << ec.message());
- m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
+ m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
if(ec)
MDEBUG("Problems at shutdown: " << ec.message());
- m_ssl_socket.next_layer().close(ec);
+ m_ssl_socket->next_layer().close(ec);
if(ec)
MDEBUG("Problems at close: " << ec.message());
boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1);
@@ -533,7 +584,7 @@ namespace net_utils
boost::asio::ip::tcp::socket& get_socket()
{
- return m_ssl_socket.next_layer();
+ return m_ssl_socket->next_layer();
}
private:
@@ -550,7 +601,7 @@ namespace net_utils
// connect(), read_line() or write_line() functions to return.
LOG_PRINT_L3("Timed out socket");
m_connected = false;
- m_ssl_socket.next_layer().close();
+ m_ssl_socket->next_layer().close();
// There is no longer an active deadline. The expiry is set to positive
// infinity so that the actor takes no action until a new deadline is set.
@@ -565,7 +616,7 @@ namespace net_utils
// ssl socket shutdown blocks if server doesn't respond. We close after 2 secs
boost::system::error_code ec = boost::asio::error::would_block;
m_deadline.expires_from_now(std::chrono::milliseconds(2000));
- m_ssl_socket.async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
+ m_ssl_socket->async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
while (ec == boost::asio::error::would_block)
{
m_io_service.run_one();
@@ -586,35 +637,39 @@ namespace net_utils
bool write(const void* data, size_t sz, boost::system::error_code& ec)
{
bool success;
- if(m_ssl)
- success = boost::asio::write(m_ssl_socket, boost::asio::buffer(data, sz), ec);
+ if(m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ success = boost::asio::write(*m_ssl_socket, boost::asio::buffer(data, sz), ec);
else
- success = boost::asio::write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), ec);
+ success = boost::asio::write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), ec);
return success;
}
void async_write(const void* data, size_t sz, boost::system::error_code& ec)
{
- if(m_ssl)
- boost::asio::async_write(m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
+ if(m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ boost::asio::async_write(*m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
else
- boost::asio::async_write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
+ boost::asio::async_write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
}
void async_read(char* buff, size_t sz, boost::asio::detail::transfer_at_least_t transfer_at_least, handler_obj& hndlr)
{
- if(!m_ssl)
- boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
+ if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_enabled)
+ boost::asio::async_read(m_ssl_socket->next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
else
- boost::asio::async_read(m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
+ boost::asio::async_read(*m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
}
protected:
boost::asio::io_service m_io_service;
- boost::asio::ssl::context m_ctx;
- boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_ssl_socket;
- bool m_ssl;
+ epee::net_utils::ssl_context_t m_ctx;
+ std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket;
+ epee::net_utils::ssl_support_t m_ssl_support;
+ std::string m_ssl_private_key;
+ std::string m_ssl_certificate;
+ std::list<std::string> m_ssl_allowed_certificates;
+ bool m_ssl_allow_any_cerl;
bool m_initialized;
bool m_connected;
boost::asio::steady_timer m_deadline;
@@ -722,7 +777,7 @@ namespace net_utils
// asynchronous operations are cancelled. This allows the blocked
// connect(), read_line() or write_line() functions to return.
LOG_PRINT_L3("Timed out socket");
- m_ssl_socket.next_layer().close();
+ m_ssl_socket->next_layer().close();
// There is no longer an active deadline. The expiry is set to positive
// infinity so that the actor takes no action until a new deadline is set.
diff --git a/contrib/epee/include/net/net_ssl.h b/contrib/epee/include/net/net_ssl.h
new file mode 100644
index 000000000..9ae1883af
--- /dev/null
+++ b/contrib/epee/include/net/net_ssl.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the Andrey N. Sabelnikov nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+
+
+#ifndef _NET_SSL_H
+#define _NET_SSL_H
+
+#include <stdint.h>
+#include <string>
+#include <list>
+#include <boost/utility/string_ref.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ssl.hpp>
+
+namespace epee
+{
+namespace net_utils
+{
+ enum class ssl_support_t: uint8_t {
+ e_ssl_support_disabled,
+ e_ssl_support_enabled,
+ e_ssl_support_autodetect,
+ };
+
+ struct ssl_context_t
+ {
+ boost::asio::ssl::context context;
+ std::list<std::string> allowed_certificates;
+ bool allow_any_cert;
+ };
+
+ // https://security.stackexchange.com/questions/34780/checking-client-hello-for-https-classification
+ constexpr size_t get_ssl_magic_size() { return 9; }
+ bool is_ssl(const unsigned char *data, size_t len);
+ ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, std::list<std::string> allowed_certificates, bool allow_any_cert);
+ void use_ssl_certificate(ssl_context_t &ssl_context, const std::pair<std::string, std::string> &private_key_and_certificate_path);
+ bool create_ssl_certificate(std::string &pkey_buffer, std::string &cert_buffer);
+ bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const std::list<std::string> &allowed_certificates);
+ bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const epee::net_utils::ssl_context_t &ssl_context);
+ bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s);
+}
+}
+
+#endif //_NET_SSL_H
diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h
index 82f8a7fe8..7b5b07ef2 100644
--- a/contrib/epee/include/net/net_utils_base.h
+++ b/contrib/epee/include/net/net_utils_base.h
@@ -47,6 +47,7 @@
namespace net
{
class tor_address;
+ class i2p_address;
}
namespace epee
@@ -196,7 +197,7 @@ namespace net_utils
template<typename Type> const Type &as() const { return as_mutable<const Type>(); }
BEGIN_KV_SERIALIZE_MAP()
- // need to `#include "net/tor_address.h"` when serializing `network_address`
+ // need to `#include "net/[i2p|tor]_address.h"` when serializing `network_address`
static constexpr std::integral_constant<bool, is_store> is_store_{};
std::uint8_t type = std::uint8_t(is_store ? this_ref.get_type_id() : address_type::invalid);
@@ -209,6 +210,8 @@ namespace net_utils
return this_ref.template serialize_addr<ipv4_network_address>(is_store_, stg, hparent_section);
case address_type::tor:
return this_ref.template serialize_addr<net::tor_address>(is_store_, stg, hparent_section);
+ case address_type::i2p:
+ return this_ref.template serialize_addr<net::i2p_address>(is_store_, stg, hparent_section);
case address_type::invalid:
default:
break;
@@ -241,6 +244,7 @@ namespace net_utils
const network_address m_remote_address;
const bool m_is_income;
const time_t m_started;
+ const time_t m_ssl;
time_t m_last_recv;
time_t m_last_send;
uint64_t m_recv_cnt;
@@ -251,13 +255,14 @@ namespace net_utils
double m_max_speed_up;
connection_context_base(boost::uuids::uuid connection_id,
- const network_address &remote_address, bool is_income,
+ const network_address &remote_address, bool is_income, bool ssl,
time_t last_recv = 0, time_t last_send = 0,
uint64_t recv_cnt = 0, uint64_t send_cnt = 0):
m_connection_id(connection_id),
m_remote_address(remote_address),
m_is_income(is_income),
m_started(time(NULL)),
+ m_ssl(ssl),
m_last_recv(last_recv),
m_last_send(last_send),
m_recv_cnt(recv_cnt),
@@ -272,6 +277,7 @@ namespace net_utils
m_remote_address(),
m_is_income(false),
m_started(time(NULL)),
+ m_ssl(false),
m_last_recv(0),
m_last_send(0),
m_recv_cnt(0),
@@ -284,17 +290,17 @@ namespace net_utils
connection_context_base& operator=(const connection_context_base& a)
{
- set_details(a.m_connection_id, a.m_remote_address, a.m_is_income);
+ set_details(a.m_connection_id, a.m_remote_address, a.m_is_income, a.m_ssl);
return *this;
}
private:
template<class t_protocol_handler>
friend class connection;
- void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income)
+ void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income, bool ssl)
{
this->~connection_context_base();
- new(this) connection_context_base(connection_id, remote_address, is_income);
+ new(this) connection_context_base(connection_id, remote_address, is_income, ssl);
}
};
diff --git a/contrib/epee/include/net/network_throttle-detail.hpp b/contrib/epee/include/net/network_throttle-detail.hpp
index 955668d62..9d12291f4 100644
--- a/contrib/epee/include/net/network_throttle-detail.hpp
+++ b/contrib/epee/include/net/network_throttle-detail.hpp
@@ -36,6 +36,7 @@
#ifndef INCLUDED_throttle_detail_hpp
#define INCLUDED_throttle_detail_hpp
+#include <boost/circular_buffer.hpp>
#include "network_throttle.hpp"
namespace epee
@@ -61,7 +62,7 @@ class network_throttle : public i_network_throttle {
network_time_seconds m_slot_size; // the size of one slot. TODO: now hardcoded for 1 second e.g. in time_to_slot()
// TODO for big window size, for performance better the substract on change of m_last_sample_time instead of recalculating average of eg >100 elements
- std::vector< packet_info > m_history; // the history of bw usage
+ boost::circular_buffer< packet_info > m_history; // the history of bw usage
network_time_seconds m_last_sample_time; // time of last history[0] - so we know when to rotate the buffer
network_time_seconds m_start_time; // when we were created
bool m_any_packet_yet; // did we yet got any packet to count
diff --git a/contrib/epee/include/stats.h b/contrib/epee/include/stats.h
new file mode 100644
index 000000000..1cf9c68fb
--- /dev/null
+++ b/contrib/epee/include/stats.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include <vector>
+
+template<typename T, typename Tpod = T>
+class Stats
+{
+public:
+ Stats(const std::vector<T> &v): values(v), cached(0) {}
+ ~Stats() {}
+
+ size_t get_size() const;
+ Tpod get_min() const;
+ Tpod get_max() const;
+ Tpod get_median() const;
+ double get_mean() const;
+ double get_confidence_interval_95() const;
+ double get_confidence_interval_99() const;
+ double get_standard_deviation() const;
+ double get_standard_error() const;
+ double get_variance() const;
+ double get_kurtosis() const;
+ double get_non_parametric_skew() const;
+ double get_t_test(T t) const;
+ double get_t_test(size_t npoints, double mean, double stddev) const;
+ double get_t_test(const Stats<T> &other) const;
+ double get_z_test(const Stats<T> &other) const;
+ double get_test(const Stats<T> &other) const;
+ std::vector<Tpod> get_quantiles(unsigned int quantiles) const;
+ std::vector<size_t> get_bins(unsigned int bins) const;
+ bool is_same_distribution_95(size_t npoints, double mean, double stddev) const;
+ bool is_same_distribution_95(const Stats<T> &other) const;
+ bool is_same_distribution_99(size_t npoints, double mean, double stddev) const;
+ bool is_same_distribution_99(const Stats<T> &other) const;
+
+ double get_cdf95(size_t df) const;
+ double get_cdf95(const Stats<T> &other) const;
+ double get_cdf99(size_t df) const;
+ double get_cdf99(const Stats<T> &other) const;
+
+private:
+ inline bool is_cached(int bit) const;
+ inline void set_cached(int bit) const;
+
+ const std::vector<T> &values;
+
+ mutable uint64_t cached;
+ mutable Tpod min;
+ mutable Tpod max;
+ mutable Tpod median;
+ mutable double mean;
+ mutable double standard_deviation;
+ mutable double standard_error;
+ mutable double variance;
+ mutable double kurtosis;
+};
+
+#include "stats.inl"
diff --git a/contrib/epee/include/stats.inl b/contrib/epee/include/stats.inl
new file mode 100644
index 000000000..5a5cd0b93
--- /dev/null
+++ b/contrib/epee/include/stats.inl
@@ -0,0 +1,359 @@
+#include <math.h>
+#include <limits>
+#include <algorithm>
+#include "stats.h"
+
+enum
+{
+ bit_min = 0,
+ bit_max,
+ bit_median,
+ bit_mean,
+ bit_standard_deviation,
+ bit_standard_error,
+ bit_variance,
+ bit_kurtosis,
+};
+
+static inline double square(double x)
+{
+ return x * x;
+}
+
+template<typename T>
+static inline double interpolate(T v, T v0, double i0, T v1, double i1)
+{
+ return i0 + (i1 - i0) * (v - v0) / (v1 - v0);
+}
+
+template<typename T, typename Tpod>
+inline bool Stats<T, Tpod>::is_cached(int bit) const
+{
+ return cached & (1<<bit);
+}
+
+template<typename T, typename Tpod>
+inline void Stats<T, Tpod>::set_cached(int bit) const
+{
+ cached |= 1<<bit;
+}
+
+template<typename T, typename Tpod>
+size_t Stats<T, Tpod>::get_size() const
+{
+ return values.size();
+}
+
+template<typename T, typename Tpod>
+Tpod Stats<T, Tpod>::get_min() const
+{
+ if (!is_cached(bit_min))
+ {
+ min = std::numeric_limits<Tpod>::max();
+ for (const T &v: values)
+ min = std::min<Tpod>(min, v);
+ set_cached(bit_min);
+ }
+ return min;
+}
+
+template<typename T, typename Tpod>
+Tpod Stats<T, Tpod>::get_max() const
+{
+ if (!is_cached(bit_max))
+ {
+ max = std::numeric_limits<Tpod>::min();
+ for (const T &v: values)
+ max = std::max<Tpod>(max, v);
+ set_cached(bit_max);
+ }
+ return max;
+}
+
+template<typename T, typename Tpod>
+Tpod Stats<T, Tpod>::get_median() const
+{
+ if (!is_cached(bit_median))
+ {
+ std::vector<Tpod> sorted;
+ sorted.reserve(values.size());
+ for (const T &v: values)
+ sorted.push_back(v);
+ std::sort(sorted.begin(), sorted.end());
+ if (sorted.size() & 1)
+ {
+ median = sorted[sorted.size() / 2];
+ }
+ else
+ {
+ median = (sorted[(sorted.size() - 1) / 2] + sorted[sorted.size() / 2]) / 2;
+ }
+ set_cached(bit_median);
+ }
+ return median;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_mean() const
+{
+ if (values.empty())
+ return 0.0;
+ if (!is_cached(bit_mean))
+ {
+ mean = 0.0;
+ for (const T &v: values)
+ mean += v;
+ mean /= values.size();
+ set_cached(bit_mean);
+ }
+ return mean;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_cdf95(size_t df) const
+{
+ static const double p[101] = {
+ -1, 12.706, 4.3027, 3.1824, 2.7765, 2.5706, 2.4469, 2.3646, 2.3060, 2.2622, 2.2281, 2.2010, 2.1788, 2.1604, 2.1448, 2.1315,
+ 2.1199, 2.1098, 2.1009, 2.0930, 2.0860, 2.0796, 2.0739, 2.0687, 2.0639, 2.0595, 2.0555, 2.0518, 2.0484, 2.0452, 2.0423, 2.0395,
+ 2.0369, 2.0345, 2.0322, 2.0301, 2.0281, 2.0262, 2.0244, 2.0227, 2.0211, 2.0195, 2.0181, 2.0167, 2.0154, 2.0141, 2.0129, 2.0117,
+ 2.0106, 2.0096, 2.0086, 2.0076, 2.0066, 2.0057, 2.0049, 2.0040, 2.0032, 2.0025, 2.0017, 2.0010, 2.0003, 1.9996, 1.9990, 1.9983,
+ 1.9977, 1.9971, 1.9966, 1.9960, 1.9955, 1.9949, 1.9944, 1.9939, 1.9935, 1.9930, 1.9925, 1.9921, 1.9917, 1.9913, 1.9908, 1.9905,
+ 1.9901, 1.9897, 1.9893, 1.9890, 1.9886, 1.9883, 1.9879, 1.9876, 1.9873, 1.9870, 1.9867, 1.9864, 1.9861, 1.9858, 1.9855, 1.9852,
+ 1.9850, 1.9847, 1.9845, 1.9842, 1.9840,
+ };
+ if (df <= 100)
+ return p[df];
+ if (df <= 120)
+ return interpolate<size_t>(df, 100, 1.9840, 120, 1.98);
+ return 1.96;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_cdf95(const Stats<T> &other) const
+{
+ return get_cdf95(get_size() + other.get_size() - 2);
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_cdf99(size_t df) const
+{
+ static const double p[101] = {
+ -1, 9.9250, 5.8408, 4.6041, 4.0321, 3.7074, 3.4995, 3.3554, 3.2498, 3.1693, 3.1058, 3.0545, 3.0123, 2.9768, 2.9467, 2.9208, 2.8982,
+ 2.8784, 2.8609, 2.8453, 2.8314, 2.8188, 2.8073, 2.7970, 2.7874, 2.7787, 2.7707, 2.7633, 2.7564, 2.7500, 2.7440, 2.7385, 2.7333,
+ 2.7284, 2.7238, 2.7195, 2.7154, 2.7116, 2.7079, 2.7045, 2.7012, 2.6981, 2.6951, 2.6923, 2.6896, 2.6870, 2.6846, 2.6822, 2.6800,
+ 2.6778, 2.6757, 2.6737, 2.6718, 2.6700, 2.6682, 2.6665, 2.6649, 2.6633, 2.6618, 2.6603, 2.6589, 2.6575, 2.6561, 2.6549, 2.6536,
+ 2.6524, 2.6512, 2.6501, 2.6490, 2.6479, 2.6469, 2.6458, 2.6449, 2.6439, 2.6430, 2.6421, 2.6412, 2.6403, 2.6395, 2.6387, 2.6379,
+ 2.6371, 2.6364, 2.6356, 2.6349, 2.6342, 2.6335, 2.6329, 2.6322, 2.6316, 2.6309, 2.6303, 2.6297, 2.6291, 2.6286, 2.6280, 2.6275,
+ 2.6269, 2.6264, 2.6259,
+ };
+ if (df <= 100)
+ return p[df];
+ if (df <= 120)
+ return interpolate<size_t>(df, 100, 2.6529, 120, 2.617);
+ return 2.576;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_cdf99(const Stats<T> &other) const
+{
+ return get_cdf99(get_size() + other.get_size() - 2);
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_confidence_interval_95() const
+{
+ const size_t df = get_size() - 1;
+ return get_standard_error() * get_cdf95(df);
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_confidence_interval_99() const
+{
+ const size_t df = get_size() - 1;
+ return get_standard_error() * get_cdf99(df);
+}
+
+template<typename T, typename Tpod>
+bool Stats<T, Tpod>::is_same_distribution_95(size_t npoints, double mean, double stddev) const
+{
+ return fabs(get_t_test(npoints, mean, stddev)) < get_cdf95(get_size() + npoints - 2);
+}
+
+template<typename T, typename Tpod>
+bool Stats<T, Tpod>::is_same_distribution_95(const Stats<T> &other) const
+{
+ return fabs(get_t_test(other)) < get_cdf95(other);
+}
+
+template<typename T, typename Tpod>
+bool Stats<T, Tpod>::is_same_distribution_99(size_t npoints, double mean, double stddev) const
+{
+ return fabs(get_t_test(npoints, mean, stddev)) < get_cdf99(get_size() + npoints - 2);
+}
+
+template<typename T, typename Tpod>
+bool Stats<T, Tpod>::is_same_distribution_99(const Stats<T> &other) const
+{
+ return fabs(get_t_test(other)) < get_cdf99(other);
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_standard_deviation() const
+{
+ if (values.size() <= 1)
+ return 0.0;
+ if (!is_cached(bit_standard_deviation))
+ {
+ Tpod m = get_mean(), t = 0;
+ for (const T &v: values)
+ t += ((T)v - m) * ((T)v - m);
+ standard_deviation = sqrt(t / ((double)values.size() - 1));
+ set_cached(bit_standard_deviation);
+ }
+ return standard_deviation;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_standard_error() const
+{
+ if (!is_cached(bit_standard_error))
+ {
+ standard_error = get_standard_deviation() / sqrt(get_size());
+ set_cached(bit_standard_error);
+ }
+ return standard_error;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_variance() const
+{
+ if (!is_cached(bit_variance))
+ {
+ double stddev = get_standard_deviation();
+ variance = stddev * stddev;
+ set_cached(bit_variance);
+ }
+ return variance;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_kurtosis() const
+{
+ if (values.empty())
+ return 0.0;
+ if (!is_cached(bit_kurtosis))
+ {
+ double m = get_mean();
+ double n = 0, d = 0;
+ for (const T &v: values)
+ {
+ T p2 = (v - m) * (v - m);
+ T p4 = p2 * p2;
+ n += p4;
+ d += p2;
+ }
+ n /= values.size();
+ d /= values.size();
+ d *= d;
+ kurtosis = n / d;
+ set_cached(bit_kurtosis);
+ }
+ return kurtosis;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_non_parametric_skew() const
+{
+ return (get_mean() - get_median()) / get_standard_deviation();
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_t_test(T t) const
+{
+ const double n = get_mean() - t;
+ const double d = get_standard_deviation() / sqrt(get_size());
+ return n / d;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_t_test(size_t npoints, double mean, double stddev) const
+{
+ const double n = get_mean() - mean;
+ const double d = sqrt(get_variance() / get_size() + square(stddev) / npoints);
+ return n / d;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_t_test(const Stats<T> &other) const
+{
+ const double n = get_mean() - other.get_mean();
+ const double d = sqrt(get_variance() / get_size() + other.get_variance() / other.get_size());
+ return n / d;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_z_test(const Stats<T> &other) const
+{
+ const double m0 = get_mean();
+ const double m1 = other.get_mean();
+ const double sd0 = get_standard_deviation();
+ const double sd1 = other.get_standard_deviation();
+ const size_t s0 = get_size();
+ const size_t s1 = other.get_size();
+
+ const double n = m0 - m1;
+ const double d = sqrt(square(sd0 / sqrt(s0)) + square(sd1 / sqrt(s1)));
+
+ return n / d;
+}
+
+template<typename T, typename Tpod>
+double Stats<T, Tpod>::get_test(const Stats<T> &other) const
+{
+ if (get_size() >= 30 && other.get_size() >= 30)
+ return get_z_test(other);
+ else
+ return get_t_test(other);
+}
+
+template<typename T, typename Tpod>
+std::vector<Tpod> Stats<T, Tpod>::get_quantiles(unsigned int quantiles) const
+{
+ std::vector<Tpod> sorted;
+ sorted.reserve(values.size());
+ for (const T &v: values)
+ sorted.push_back(v);
+ std::sort(sorted.begin(), sorted.end());
+ std::vector<Tpod> q(quantiles + 1, 0);
+ for (unsigned int i = 1; i <= quantiles; ++i)
+ {
+ unsigned idx = (unsigned)ceil(values.size() * i / (double)quantiles);
+ q[i] = sorted[idx - 1];
+ }
+ if (!is_cached(bit_min))
+ {
+ min = sorted.front();
+ set_cached(bit_min);
+ }
+ q[0] = min;
+ if (!is_cached(bit_max))
+ {
+ max = sorted.back();
+ set_cached(bit_max);
+ }
+ return q;
+}
+
+template<typename T, typename Tpod>
+std::vector<size_t> Stats<T, Tpod>::get_bins(unsigned int bins) const
+{
+ std::vector<size_t> b(bins, 0);
+ const double scale = 1.0 / (get_max() - get_min());
+ const T base = get_min();
+ for (const T &v: values)
+ {
+ unsigned int idx = (v - base) * scale;
+ ++b[idx];
+ }
+ return b;
+}