aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/epee/include/copyable_atomic.h2
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl4
-rw-r--r--contrib/epee/include/net/http_client.h12
-rw-r--r--contrib/epee/include/net/net_helper.h140
-rw-r--r--contrib/epee/include/net/net_utils_base.h194
-rw-r--r--contrib/epee/include/serialization/keyvalue_serialization_overloads.h46
-rw-r--r--contrib/epee/include/storages/http_abstract_invoke.h5
-rw-r--r--contrib/epee/include/storages/portable_storage_val_converters.h27
-rw-r--r--contrib/epee/include/string_tools.h6
-rw-r--r--contrib/epee/src/CMakeLists.txt4
-rw-r--r--contrib/epee/src/net_utils_base.cpp60
11 files changed, 376 insertions, 124 deletions
diff --git a/contrib/epee/include/copyable_atomic.h b/contrib/epee/include/copyable_atomic.h
index 410b4b4ff..00a5f484b 100644
--- a/contrib/epee/include/copyable_atomic.h
+++ b/contrib/epee/include/copyable_atomic.h
@@ -35,6 +35,8 @@ namespace epee
public:
copyable_atomic()
{};
+ copyable_atomic(uint32_t value)
+ { store(value); }
copyable_atomic(const copyable_atomic& a):std::atomic<uint32_t>(a.load())
{}
copyable_atomic& operator= (const copyable_atomic& a)
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 76988a26e..94ef7c3b3 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -137,14 +137,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value());
context = boost::value_initialized<t_connection_context>();
- long ip_ = boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong());
+ const unsigned long ip_{boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong())};
// create a random uuid
boost::uuids::uuid random_uuid;
// that stuff turns out to be included, even though it's from src... Taking advantage
random_uuid = crypto::rand<boost::uuids::uuid>();
- context.set_details(random_uuid, new epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income);
+ context.set_details(random_uuid, epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income);
_dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
" to " << local_ep.address().to_string() << ':' << local_ep.port() <<
", total sockets objects " << m_ref_sock_count);
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h
index 8e099e2bc..ed89ca0c7 100644
--- a/contrib/epee/include/net/http_client.h
+++ b/contrib/epee/include/net/http_client.h
@@ -274,6 +274,7 @@ using namespace std;
chunked_state m_chunked_state;
std::string m_chunked_cache;
critical_section m_lock;
+ bool m_ssl;
public:
explicit http_simple_client()
@@ -291,33 +292,35 @@ using namespace std;
, m_chunked_state()
, m_chunked_cache()
, m_lock()
+ , m_ssl(false)
{}
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 set_server(const std::string& address, boost::optional<login> user, bool ssl = 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));
+ set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl);
return true;
}
- void set_server(std::string host, std::string port, boost::optional<login> user)
+ void set_server(std::string host, std::string port, boost::optional<login> user, bool ssl = 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;
}
bool connect(std::chrono::milliseconds timeout)
{
CRITICAL_REGION_LOCAL(m_lock);
- return m_net_client.connect(m_host_buff, m_port, timeout);
+ return m_net_client.connect(m_host_buff, m_port, timeout, m_ssl);
}
//---------------------------------------------------------------------------
bool disconnect()
@@ -392,7 +395,6 @@ using namespace std;
res = m_net_client.send(body, timeout);
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
-
m_response_info.clear();
m_state = reciev_machine_state_header;
if (!handle_reciev(timeout))
diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h
index 1d808cc4c..c8e4c7818 100644
--- a/contrib/epee/include/net/net_helper.h
+++ b/contrib/epee/include/net/net_helper.h
@@ -37,6 +37,7 @@
#include <ostream>
#include <string>
#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/preprocessor/selection/min.hpp>
#include <boost/lambda/bind.hpp>
@@ -85,11 +86,13 @@ namespace net_utils
public:
inline
- blocked_mode_client():m_socket(m_io_service),
- m_initialized(false),
+ blocked_mode_client():m_initialized(false),
m_connected(false),
m_deadline(m_io_service),
- m_shutdowned(0)
+ m_shutdowned(0),
+ m_ssl(false),
+ m_ctx(boost::asio::ssl::context::sslv23),
+ m_ssl_socket(m_io_service,m_ctx)
{
@@ -113,18 +116,25 @@ namespace net_utils
}
inline
- bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
+ bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
{
- return connect(addr, std::to_string(port), timeout, bind_ip);
+ return connect(addr, std::to_string(port), timeout, ssl, bind_ip);
}
inline
- bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
+ 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")
{
m_connected = false;
+ m_ssl = ssl;
try
{
- m_socket.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();
+
// Get a list of endpoints corresponding to the server name.
@@ -147,11 +157,11 @@ namespace net_utils
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
- m_socket.open(remote_endpoint.protocol());
+ 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_socket.bind(local_endpoint);
+ m_ssl_socket.next_layer().bind(local_endpoint);
}
@@ -160,17 +170,24 @@ namespace net_utils
boost::system::error_code ec = boost::asio::error::would_block;
- //m_socket.connect(remote_endpoint);
- m_socket.async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
+ 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_socket.is_open())
+ 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(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);
+ }
return true;
}else
{
@@ -193,7 +210,6 @@ namespace net_utils
return true;
}
-
inline
bool disconnect()
{
@@ -202,8 +218,9 @@ namespace net_utils
if(m_connected)
{
m_connected = false;
- m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
-
+ if(m_ssl)
+ shutdown_ssl();
+ m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
}
}
@@ -240,7 +257,7 @@ namespace net_utils
// object is used as a callback and will update the ec variable when the
// operation completes. The blocking_udp_client.cpp example shows how you
// can use boost::bind rather than boost::lambda.
- boost::asio::async_write(m_socket, boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1);
+ async_write(buff.c_str(), buff.size(), ec);
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block)
@@ -302,9 +319,7 @@ namespace net_utils
*/
boost::system::error_code ec;
- size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec);
-
-
+ size_t writen = write(data, sz, ec);
if (!writen || ec)
{
@@ -334,10 +349,7 @@ namespace net_utils
bool is_connected()
{
- return m_connected && m_socket.is_open();
- //TRY_ENTRY()
- //return m_socket.is_open();
- //CATCH_ENTRY_L0("is_connected", false)
+ return m_connected && m_ssl_socket.next_layer().is_open();
}
inline
@@ -369,8 +381,8 @@ namespace net_utils
handler_obj hndlr(ec, bytes_transfered);
char local_buff[10000] = {0};
- //m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr);
- boost::asio::async_read(m_socket, boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr);
+
+ async_read(local_buff, boost::asio::transfer_at_least(1), hndlr);
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
@@ -451,10 +463,8 @@ namespace net_utils
handler_obj hndlr(ec, bytes_transfered);
-
- //char local_buff[10000] = {0};
- boost::asio::async_read(m_socket, boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr);
-
+ async_read((char*)buff.data(), boost::asio::transfer_at_least(buff.size()), hndlr);
+
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
{
@@ -500,10 +510,18 @@ namespace net_utils
bool shutdown()
{
m_deadline.cancel();
- boost::system::error_code ignored_ec;
- m_socket.cancel(ignored_ec);
- m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
- m_socket.close(ignored_ec);
+ boost::system::error_code ec;
+ if(m_ssl)
+ shutdown_ssl();
+ 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);
+ if(ec)
+ MDEBUG("Problems at shutdown: " << ec.message());
+ m_ssl_socket.next_layer().close(ec);
+ if(ec)
+ MDEBUG("Problems at close: " << ec.message());
boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1);
m_connected = false;
return true;
@@ -520,7 +538,7 @@ namespace net_utils
boost::asio::ip::tcp::socket& get_socket()
{
- return m_socket;
+ return m_ssl_socket.next_layer();
}
private:
@@ -537,7 +555,7 @@ namespace net_utils
// connect(), read_line() or write_line() functions to return.
LOG_PRINT_L3("Timed out socket");
m_connected = false;
- m_socket.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.
@@ -547,12 +565,54 @@ namespace net_utils
// Put the actor back to sleep.
m_deadline.async_wait(boost::bind(&blocked_mode_client::check_deadline, this));
}
-
+ void shutdown_ssl() {
+ // 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);
+ while (ec == boost::asio::error::would_block)
+ {
+ m_io_service.run_one();
+ }
+ // Ignore "short read" error
+ if (ec.category() == boost::asio::error::get_ssl_category() && ec.value() != ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ))
+ MDEBUG("Problems at ssl shutdown: " << ec.message());
+ }
+
+ protected:
+ 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);
+ else
+ 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);
+ else
+ 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, 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, sizeof(buff)), transfer_at_least, hndlr);
+ else
+ boost::asio::async_read(m_ssl_socket, boost::asio::buffer(buff, sizeof(buff)), transfer_at_least, hndlr);
+
+ }
protected:
boost::asio::io_service m_io_service;
- boost::asio::ip::tcp::socket m_socket;
+ boost::asio::ssl::context m_ctx;
+ boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_ssl_socket;
+ bool m_ssl;
bool m_initialized;
bool m_connected;
boost::asio::steady_timer m_deadline;
@@ -618,8 +678,8 @@ namespace net_utils
boost::system::error_code ec;
- size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec);
-
+ size_t writen = write(data, sz, ec);
+
if (!writen || ec)
{
LOG_PRINT_L3("Problems at write: " << ec.message());
@@ -660,7 +720,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_socket.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_utils_base.h b/contrib/epee/include/net/net_utils_base.h
index df83517ff..0e31ee86f 100644
--- a/contrib/epee/include/net/net_utils_base.h
+++ b/contrib/epee/include/net/net_utils_base.h
@@ -29,11 +29,12 @@
#ifndef _NET_UTILS_BASE_H_
#define _NET_UTILS_BASE_H_
-#include <typeinfo>
#include <boost/asio/io_service.hpp>
#include <boost/uuid/uuid.hpp>
+#include <memory>
+#include <typeinfo>
+#include <type_traits>
#include "serialization/keyvalue_serialization.h"
-#include "net/local_ip.h"
#include "string_tools.h"
#include "misc_log_ex.h"
@@ -49,78 +50,119 @@ namespace epee
{
namespace net_utils
{
- struct network_address_base
+ class ipv4_network_address
{
- public:
- bool operator==(const network_address_base &other) const { return m_full_id == other.m_full_id; }
- bool operator!=(const network_address_base &other) const { return !operator==(other); }
- bool operator<(const network_address_base &other) const { return m_full_id < other.m_full_id; }
- bool is_same_host(const network_address_base &other) const { return m_host_id == other.m_host_id; }
- virtual std::string str() const = 0;
- virtual std::string host_str() const = 0;
- virtual bool is_loopback() const = 0;
- virtual bool is_local() const = 0;
- virtual uint8_t get_type_id() const = 0;
- protected:
- // A very simple non cryptographic hash function by Fowler, Noll, Vo
- uint64_t fnv1a(const uint8_t *data, size_t len) const {
- uint64_t h = 0xcbf29ce484222325;
- while (len--)
- h = (h ^ *data++) * 0x100000001b3;
- return h;
- }
- uint64_t m_host_id;
- uint64_t m_full_id;
+ uint32_t m_ip;
+ uint16_t m_port;
- protected:
- virtual ~network_address_base() {}
- };
- struct ipv4_network_address: public network_address_base
- {
- void init_ids()
- {
- m_host_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip));
- m_full_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip) + sizeof(m_port));
- }
public:
- ipv4_network_address(uint32_t ip, uint16_t port): network_address_base(), m_ip(ip), m_port(port) { init_ids(); }
- uint32_t ip() const { return m_ip; }
- uint16_t port() const { return m_port; }
- virtual std::string str() const { return epee::string_tools::get_ip_string_from_int32(m_ip) + ":" + std::to_string(m_port); }
- virtual std::string host_str() const { return epee::string_tools::get_ip_string_from_int32(m_ip); }
- virtual bool is_loopback() const { return epee::net_utils::is_ip_loopback(m_ip); }
- virtual bool is_local() const { return epee::net_utils::is_ip_local(m_ip); }
- virtual uint8_t get_type_id() const { return ID; }
- public: // serialization
+ constexpr ipv4_network_address(uint32_t ip, uint16_t port) noexcept
+ : m_ip(ip), m_port(port) {}
+
+ bool equal(const ipv4_network_address& other) const noexcept;
+ bool less(const ipv4_network_address& other) const noexcept;
+ constexpr bool is_same_host(const ipv4_network_address& other) const noexcept
+ { return ip() == other.ip(); }
+
+ constexpr uint32_t ip() const noexcept { return m_ip; }
+ constexpr uint16_t port() const noexcept { return m_port; }
+ std::string str() const;
+ std::string host_str() const;
+ bool is_loopback() const;
+ bool is_local() const;
+ static constexpr uint8_t get_type_id() noexcept { return ID; }
+
static const uint8_t ID = 1;
-#pragma pack(push)
-#pragma pack(1)
- uint32_t m_ip;
- uint16_t m_port;
-#pragma pack(pop)
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_ip)
KV_SERIALIZE(m_port)
- if (!is_store)
- const_cast<ipv4_network_address&>(this_ref).init_ids();
END_KV_SERIALIZE_MAP()
};
- class network_address: public boost::shared_ptr<network_address_base>
+
+ inline bool operator==(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
+ { return lhs.equal(rhs); }
+ inline bool operator!=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
+ { return !lhs.equal(rhs); }
+ inline bool operator<(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
+ { return lhs.less(rhs); }
+ inline bool operator<=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
+ { return !rhs.less(lhs); }
+ inline bool operator>(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
+ { return rhs.less(lhs); }
+ inline bool operator>=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
+ { return !lhs.less(rhs); }
+
+ class network_address
{
+ struct interface
+ {
+ virtual ~interface() {};
+
+ virtual bool equal(const interface&) const = 0;
+ virtual bool less(const interface&) const = 0;
+ virtual bool is_same_host(const interface&) const = 0;
+
+ virtual std::string str() const = 0;
+ virtual std::string host_str() const = 0;
+ virtual bool is_loopback() const = 0;
+ virtual bool is_local() const = 0;
+ virtual uint8_t get_type_id() const = 0;
+ };
+
+ template<typename T>
+ struct implementation final : interface
+ {
+ T value;
+
+ implementation(const T& src) : value(src) {}
+ ~implementation() = default;
+
+ // Type-checks for cast are done in cpp
+ static const T& cast(const interface& src) noexcept
+ { return static_cast<const implementation<T>&>(src).value; }
+
+ virtual bool equal(const interface& other) const override
+ { return value.equal(cast(other)); }
+
+ virtual bool less(const interface& other) const override
+ { return value.less(cast(other)); }
+
+ virtual bool is_same_host(const interface& other) const override
+ { return value.is_same_host(cast(other)); }
+
+ virtual std::string str() const override { return value.str(); }
+ virtual std::string host_str() const override { return value.host_str(); }
+ virtual bool is_loopback() const override { return value.is_loopback(); }
+ virtual bool is_local() const override { return value.is_local(); }
+ virtual uint8_t get_type_id() const override { return value.get_type_id(); }
+ };
+
+ std::shared_ptr<interface> self;
+
+ template<typename Type>
+ Type& as_mutable() const
+ {
+ // types `implmentation<Type>` and `implementation<const Type>` are unique
+ using Type_ = typename std::remove_const<Type>::type;
+ network_address::interface* const self_ = self.get(); // avoid clang warning in typeid
+ if (!self_ || typeid(implementation<Type_>) != typeid(*self_))
+ throw std::bad_cast{};
+ return static_cast<implementation<Type_>*>(self_)->value;
+ }
public:
- network_address() {}
- network_address(ipv4_network_address *address): boost::shared_ptr<network_address_base>(address) {}
- bool operator==(const network_address &other) const { return (*this)->operator==(*other); }
- bool operator!=(const network_address &other) const { return (*this)->operator!=(*other); }
- bool operator<(const network_address &other) const { return (*this)->operator<(*other); }
- bool is_same_host(const network_address &other) const { return (*this)->is_same_host(*other); }
- std::string str() const { return (*this) ? (*this)->str() : "<none>"; }
- std::string host_str() const { return (*this) ? (*this)->host_str() : "<none>"; }
- bool is_loopback() const { return (*this)->is_loopback(); }
- bool is_local() const { return (*this)->is_local(); }
- uint8_t get_type_id() const { return (*this)->get_type_id(); }
- template<typename Type> Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); }
- template<typename Type> const Type &as() const { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(const Type*)get(); }
+ network_address() : self(nullptr) {}
+ template<typename T>
+ network_address(const T& src)
+ : self(std::make_shared<implementation<T>>(src)) {}
+ bool equal(const network_address &other) const;
+ bool less(const network_address &other) const;
+ bool is_same_host(const network_address &other) const;
+ std::string str() const { return self ? self->str() : "<none>"; }
+ std::string host_str() const { return self ? self->host_str() : "<none>"; }
+ bool is_loopback() const { return self ? self->is_loopback() : false; }
+ bool is_local() const { return self ? self->is_local() : false; }
+ uint8_t get_type_id() const { return self ? self->get_type_id() : 0; }
+ template<typename Type> const Type &as() const { return as_mutable<const Type>(); }
BEGIN_KV_SERIALIZE_MAP()
uint8_t type = is_store ? this_ref.get_type_id() : 0;
@@ -129,13 +171,27 @@ namespace net_utils
{
case ipv4_network_address::ID:
if (!is_store)
- const_cast<network_address&>(this_ref).reset(new ipv4_network_address(0, 0));
- KV_SERIALIZE(template as<ipv4_network_address>());
+ const_cast<network_address&>(this_ref) = ipv4_network_address{0, 0};
+ KV_SERIALIZE(template as_mutable<ipv4_network_address>());
break;
default: MERROR("Unsupported network address type: " << type); return false;
}
END_KV_SERIALIZE_MAP()
};
+
+ inline bool operator==(const network_address& lhs, const network_address& rhs)
+ { return lhs.equal(rhs); }
+ inline bool operator!=(const network_address& lhs, const network_address& rhs)
+ { return !lhs.equal(rhs); }
+ inline bool operator<(const network_address& lhs, const network_address& rhs)
+ { return lhs.less(rhs); }
+ inline bool operator<=(const network_address& lhs, const network_address& rhs)
+ { return !rhs.less(lhs); }
+ inline bool operator>(const network_address& lhs, const network_address& rhs)
+ { return rhs.less(lhs); }
+ inline bool operator>=(const network_address& lhs, const network_address& rhs)
+ { return !lhs.less(rhs); }
+
inline bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0)
{
uint32_t ip;
@@ -144,7 +200,7 @@ namespace net_utils
{
if (default_port && !port)
port = default_port;
- address.reset(new ipv4_network_address(ip, port));
+ address = ipv4_network_address{ip, port};
return true;
}
return false;
@@ -182,7 +238,7 @@ namespace net_utils
{}
connection_context_base(): m_connection_id(),
- m_remote_address(new ipv4_network_address(0,0)),
+ m_remote_address(ipv4_network_address{0,0}),
m_is_income(false),
m_started(time(NULL)),
m_last_recv(0),
@@ -235,7 +291,7 @@ namespace net_utils
std::string print_connection_context(const connection_context_base& ctx)
{
std::stringstream ss;
- ss << ctx.m_remote_address->str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
+ ss << ctx.m_remote_address.str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
return ss.str();
}
@@ -243,7 +299,7 @@ namespace net_utils
std::string print_connection_context_short(const connection_context_base& ctx)
{
std::stringstream ss;
- ss << ctx.m_remote_address->str() << (ctx.m_is_income ? " INC":" OUT");
+ ss << ctx.m_remote_address.str() << (ctx.m_is_income ? " INC":" OUT");
return ss.str();
}
diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
index 4423f2608..a94ecacc5 100644
--- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
+++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
@@ -117,9 +117,9 @@ namespace epee
typename stl_container::value_type exchange_val;
typename t_storage::harray hval_array = stg.get_first_value(pname, exchange_val, hparent_section);
if(!hval_array) return false;
- container.push_back(std::move(exchange_val));
+ container.insert(container.end(), std::move(exchange_val));
while(stg.get_next_value(hval_array, exchange_val))
- container.push_back(std::move(exchange_val));
+ container.insert(container.end(), std::move(exchange_val));
return true;
}//--------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
@@ -152,7 +152,7 @@ namespace epee
"size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type));
size_t count = (loaded_size/sizeof(typename stl_container::value_type));
for(size_t i = 0; i < count; i++)
- container.push_back(*(pelem++));
+ container.insert(container.end(), *(pelem++));
}
return res;
}
@@ -186,12 +186,12 @@ namespace epee
typename t_storage::harray hsec_array = stg.get_first_section(pname, hchild_section, hparent_section);
if(!hsec_array || !hchild_section) return false;
res = val._load(stg, hchild_section);
- container.push_back(val);
+ container.insert(container.end(), val);
while(stg.get_next_section(hsec_array, hchild_section))
{
typename stl_container::value_type val_l = typename stl_container::value_type();
res |= val_l._load(stg, hchild_section);
- container.push_back(std::move(val_l));
+ container.insert(container.end(), std::move(val_l));
}
return res;
}
@@ -250,6 +250,18 @@ namespace epee
return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_stl_container_t_val(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
};
template<>
struct kv_serialization_overloads_impl_is_base_serializable_types<false>
@@ -302,6 +314,18 @@ namespace epee
{
return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
}
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_stl_container_t_obj(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
+ }
};
template<class t_storage>
struct base_serializable_types: public boost::mpl::vector<uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, typename t_storage::meta_entry>::type
@@ -399,5 +423,17 @@ namespace epee
{
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
}
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
+ }
}
}
diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h
index 823ce6731..6517f1253 100644
--- a/contrib/epee/include/storages/http_abstract_invoke.h
+++ b/contrib/epee/include/storages/http_abstract_invoke.h
@@ -44,8 +44,11 @@ namespace epee
if(!serialization::store_t_to_json(out_struct, req_param))
return false;
+ http::fields_list additional_params;
+ additional_params.push_back(std::make_pair("Content-Type","application/json; charset=utf-8"));
+
const http::http_response_info* pri = NULL;
- if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri)))
+ if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri), std::move(additional_params)))
{
LOG_PRINT_L1("Failed to invoke http request to " << uri);
return false;
diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h
index e9b91c82b..f4a16cfae 100644
--- a/contrib/epee/include/storages/portable_storage_val_converters.h
+++ b/contrib/epee/include/storages/portable_storage_val_converters.h
@@ -28,6 +28,8 @@
#pragma once
+#include <regex>
+
#include "misc_language.h"
#include "portable_storage_base.h"
#include "warnings.h"
@@ -131,6 +133,31 @@ POP_WARNINGS
}
};
+ // For MyMonero/OpenMonero backend compatibility
+ // MyMonero backend sends amount, fees and timestamp values as strings.
+ // Until MM backend is updated, this is needed for compatibility between OpenMonero and MyMonero.
+ template<>
+ struct convert_to_integral<std::string, uint64_t, false>
+ {
+ static void convert(const std::string& from, uint64_t& to)
+ {
+ MTRACE("Converting std::string to uint64_t. Source: " << from);
+ // String only contains digits
+ if(std::all_of(from.begin(), from.end(), ::isdigit))
+ to = boost::lexical_cast<uint64_t>(from);
+ // MyMonero ISO 8061 timestamp (2017-05-06T16:27:06Z)
+ else if (std::regex_match (from, std::regex("\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\dZ")))
+ {
+ // Convert to unix timestamp
+ std::tm tm = {};
+ std::istringstream ss(from);
+ if (ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S"))
+ to = std::mktime(&tm);
+ } else
+ ASSERT_AND_THROW_WRONG_CONVERSION();
+ }
+ };
+
template<class from_type, class to_type>
struct is_convertable: std::integral_constant<bool,
std::is_integral<to_type>::value &&
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
index ce7b2fb87..25639263c 100644
--- a/contrib/epee/include/string_tools.h
+++ b/contrib/epee/include/string_tools.h
@@ -39,6 +39,7 @@
#include <cstdlib>
#include <string>
#include <type_traits>
+#include <regex>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>
@@ -349,6 +350,11 @@ POP_WARNINGS
s = *(t_pod_type*)bin_buff.data();
return true;
}
+ //----------------------------------------------------------------------------
+ inline bool validate_hex(uint64_t length, const std::string& str)
+ {
+ return std::regex_match(str, std::regex("'^[0-9abcdefABCDEF]+$'")) && str.size() == length;
+ }
//----------------------------------------------------------------------------
inline std::string get_extension(const std::string& str)
{
diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt
index c61a6e684..294515f83 100644
--- a/contrib/epee/src/CMakeLists.txt
+++ b/contrib/epee/src/CMakeLists.txt
@@ -27,9 +27,9 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (USE_READLINE AND GNU_READLINE_FOUND)
- add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp readline_buffer.cpp)
+ add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp readline_buffer.cpp)
else()
- add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp)
+ add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp)
endif()
# Build and install libepee if we're building for GUI
diff --git a/contrib/epee/src/net_utils_base.cpp b/contrib/epee/src/net_utils_base.cpp
new file mode 100644
index 000000000..22afcf819
--- /dev/null
+++ b/contrib/epee/src/net_utils_base.cpp
@@ -0,0 +1,60 @@
+
+#include "net/net_utils_base.h"
+
+#include <cstring>
+#include <typeindex>
+#include "net/local_ip.h"
+
+namespace epee { namespace net_utils
+{
+ const uint8_t ipv4_network_address::ID;
+
+ bool ipv4_network_address::equal(const ipv4_network_address& other) const noexcept
+ { return is_same_host(other) && port() == other.port(); }
+
+ bool ipv4_network_address::less(const ipv4_network_address& other) const noexcept
+ { return is_same_host(other) ? port() < other.port() : ip() < other.ip(); }
+
+ std::string ipv4_network_address::str() const
+ { return string_tools::get_ip_string_from_int32(ip()) + ":" + std::to_string(port()); }
+
+ std::string ipv4_network_address::host_str() const { return string_tools::get_ip_string_from_int32(ip()); }
+ bool ipv4_network_address::is_loopback() const { return net_utils::is_ip_loopback(ip()); }
+ bool ipv4_network_address::is_local() const { return net_utils::is_ip_local(ip()); }
+
+
+ bool network_address::equal(const network_address& other) const
+ {
+ // clang typeid workaround
+ network_address::interface const* const self_ = self.get();
+ network_address::interface const* const other_self = other.self.get();
+ if (self_ == other_self) return true;
+ if (!self_ || !other_self) return false;
+ if (typeid(*self_) != typeid(*other_self)) return false;
+ return self_->equal(*other_self);
+ }
+
+ bool network_address::less(const network_address& other) const
+ {
+ // clang typeid workaround
+ network_address::interface const* const self_ = self.get();
+ network_address::interface const* const other_self = other.self.get();
+ if (self_ == other_self) return false;
+ if (!self_ || !other_self) return self == nullptr;
+ if (typeid(*self_) != typeid(*other_self))
+ return self_->get_type_id() < other_self->get_type_id();
+ return self_->less(*other_self);
+ }
+
+ bool network_address::is_same_host(const network_address& other) const
+ {
+ // clang typeid workaround
+ network_address::interface const* const self_ = self.get();
+ network_address::interface const* const other_self = other.self.get();
+ if (self_ == other_self) return true;
+ if (!self_ || !other_self) return false;
+ if (typeid(*self_) != typeid(*other_self)) return false;
+ return self_->is_same_host(*other_self);
+ }
+}}
+