diff --git a/contrib/epee/include/net/jsonrpc_protocol_handler.h b/contrib/epee/include/net/jsonrpc_protocol_handler.h new file mode 100644 index 00000000..b224c342 --- /dev/null +++ b/contrib/epee/include/net/jsonrpc_protocol_handler.h @@ -0,0 +1,167 @@ +#ifndef JSONRPC_PROTOCOL_HANDLER_H +#define JSONRPC_PROTOCOL_HANDLER_H + +#include +#include + +#include "net/net_utils_base.h" +#include "jsonrpc_structs.h" +#include "storages/portable_storage.h" +#include "storages/portable_storage_template_helper.h" + +namespace epee +{ +namespace net_utils +{ + namespace jsonrpc2 + { + inline + std::string& make_error_resp_json(int64_t code, const std::string& message, + std::string& response_data, + const epee::serialization::storage_entry& id = nullptr) + { + epee::json_rpc::error_response rsp; + rsp.id = id; + rsp.jsonrpc = "2.0"; + rsp.error.code = code; + rsp.error.message = message; + epee::serialization::store_t_to_json(static_cast(rsp), response_data, 0, false); + response_data += "\n"; + return response_data; + } + + template + struct i_jsonrpc2_server_handler + { + virtual ~i_jsonrpc2_server_handler() + {} + virtual bool handle_rpc_request(const std::string& req_data, + std::string& resp_data, + t_connection_context& conn_context) = 0; + virtual bool init_server_thread() + { return true; } + virtual bool deinit_server_thread() + { return true; } + }; + + template + struct jsonrpc2_server_config + { + i_jsonrpc2_server_handler* m_phandler; + critical_section m_lock; + }; + + template + class jsonrpc2_connection_handler + { + public: + typedef t_connection_context connection_context; + typedef jsonrpc2_server_config config_type; + + jsonrpc2_connection_handler(i_service_endpoint* psnd_hndlr, + config_type& config, + t_connection_context& conn_context) + : m_psnd_hndlr(psnd_hndlr), + m_config(config), + m_conn_context(conn_context), + m_is_stop_handling(false) + {} + virtual ~jsonrpc2_connection_handler() + {} + + bool release_protocol() + { + return true; + } + virtual bool thread_init() + { + return true; + } + virtual bool thread_deinit() + { + return true; + } + void handle_qued_callback() + {} + bool after_init_connection() + { + return true; + } + virtual bool handle_recv(const void* ptr, size_t cb) + { + std::string buf((const char*)ptr, cb); + LOG_PRINT_L0("JSONRPC2_RECV: " << ptr << "\r\n" << buf); + + bool res = handle_buff_in(buf); + return res; + } + private: + bool handle_buff_in(std::string& buf) + { + if(m_cache.size()) + m_cache += buf; + else + m_cache.swap(buf); + + m_is_stop_handling = false; + while (!m_is_stop_handling) { + std::string::size_type pos = match_end_of_request(m_cache); + if (std::string::npos == pos) { + m_is_stop_handling = true; + if (m_cache.size() > 4096) { + LOG_ERROR("jsonrpc2_connection_handler::handle_buff_in: Too long request"); + return false; + } + break; + } else { + extract_cached_request_and_handle(pos); + } + + if (!m_cache.size()) { + m_is_stop_handling = true; + } + } + + return true; + } + bool extract_cached_request_and_handle(std::string::size_type pos) + { + std::string request_data(m_cache.begin(), m_cache.begin() + pos); + m_cache.erase(0, pos); + return handle_request_and_send_response(request_data); + } + bool handle_request_and_send_response(const std::string& request_data) + { + CHECK_AND_ASSERT_MES(m_config.m_phandler, false, "m_config.m_phandler is NULL!!!!"); + std::string response_data; + + LOG_PRINT_L3("JSONRPC2_REQUEST: >> \r\n" << request_data); + bool rpc_result = m_config.m_phandler->handle_rpc_request(request_data, response_data, m_conn_context); + LOG_PRINT_L3("JSONRPC2_RESPONSE: << \r\n" << response_data); + + m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size()); + return rpc_result; + } + std::string::size_type match_end_of_request(const std::string& buf) + { + std::string::size_type res = buf.find("\n"); + if(std::string::npos != res) { + return res + 2; + } + return res; + } + + protected: + i_service_endpoint* m_psnd_hndlr; + + private: + config_type& m_config; + t_connection_context& m_conn_context; + std::string m_cache; + bool m_is_stop_handling; + }; + } +} +} + +#endif /* JSONRPC_PROTOCOL_HANDLER_H */ diff --git a/contrib/epee/include/net/jsonrpc_server_handlers_map.h b/contrib/epee/include/net/jsonrpc_server_handlers_map.h new file mode 100644 index 00000000..8c747d1a --- /dev/null +++ b/contrib/epee/include/net/jsonrpc_server_handlers_map.h @@ -0,0 +1,86 @@ +#ifndef JSONRPC_SERVER_HANDLERS_MAP_H +#define JSONRPC_SERVER_HANDLERS_MAP_H + +#include +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_template_helper.h" +#include "storages/portable_storage_base.h" +#include "jsonrpc_structs.h" +#include "jsonrpc_protocol_handler.h" + +#define BEGIN_JSONRPC2_MAP(t_connection_context) \ +bool handle_rpc_request(const std::string& req_data, \ + std::string& resp_data, \ + t_connection_context& m_conn_context) \ +{ \ + bool handled = false; \ + uint64_t ticks = epee::misc_utils::get_tick_count(); \ + epee::serialization::portable_storage ps; \ + if (!ps.load_from_json(req_data)) \ + { \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32700, "Parse error", resp_data); \ + return true; \ + } \ + epee::serialization::storage_entry id_; \ + id_ = epee::serialization::storage_entry(std::string()); \ + if (!ps.get_value("id", id_, nullptr)) \ + { \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32600, "Invalid Request", resp_data); \ + return true; \ + } \ + std::string callback_name; \ + if (!ps.get_value("method", callback_name, nullptr)) \ + { \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32600, "Invalid Request", resp_data, id_); \ + return true; \ + } \ + if (false) return true; //just a stub to have "else if" + + + +#define PREPARE_JSONRPC2_OBJECTS_FROM_JSON(command_type) \ + handled = true; \ + boost::value_initialized > req_; \ + epee::json_rpc::request& req = static_cast&>(req_);\ + if(!req.load(ps)) \ + { \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32602, "Invalid params", resp_data, req.id); \ + return true; \ + } \ + uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ + boost::value_initialized > resp_; \ + epee::json_rpc::response& resp = static_cast &>(resp_); \ + resp.jsonrpc = "2.0"; \ + resp.id = req.id; + +#define FINALIZE_JSONRPC2_OBJECTS_TO_JSON(method_name) \ + uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ + epee::serialization::store_t_to_json(resp, resp_data, 0, false); \ + resp_data += "\n"; \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + LOG_PRINT("[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); + + +#define MAP_JSONRPC2_WE(method_name, callback_f, command_type) \ + else if (callback_name == method_name) \ + { \ + PREPARE_JSONRPC2_OBJECTS_FROM_JSON(command_type) \ + epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ + fail_resp.jsonrpc = "2.0"; \ + fail_resp.id = req.id; \ + if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context)) \ + { \ + epee::serialization::store_t_to_json(static_cast(fail_resp), resp_data, 0, false); \ + resp_data += "\n"; \ + return true; \ + } \ + FINALIZE_JSONRPC2_OBJECTS_TO_JSON(method_name) \ + return true; \ + } + +#define END_JSONRPC2_MAP() \ + epee::net_utils::jsonrpc2::make_error_resp_json(-32601, "Method not found", resp_data, id_); \ + return true; \ +} + +#endif /* JSONRPC_SERVER_HANDLERS_MAP_H */ diff --git a/contrib/epee/include/net/jsonrpc_server_impl_base.h b/contrib/epee/include/net/jsonrpc_server_impl_base.h new file mode 100644 index 00000000..8a5a9a5b --- /dev/null +++ b/contrib/epee/include/net/jsonrpc_server_impl_base.h @@ -0,0 +1,84 @@ +#ifndef JSONRPC_SERVER_IMPL_BASE_H +#define JSONRPC_SERVER_IMPL_BASE_H + +#include +#include + +#include "net/jsonrpc_protocol_handler.h" +#include "net/jsonrpc_server_handlers_map.h" +#include "net/abstract_tcp_server2.h" + +namespace epee +{ + +template + class jsonrpc_server_impl_base: public net_utils::jsonrpc2::i_jsonrpc2_server_handler + { + + public: + jsonrpc_server_impl_base() + : m_net_server() + {} + + explicit jsonrpc_server_impl_base(boost::asio::io_service& external_io_service) + : m_net_server(external_io_service) + {} + + bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0") + { + //set self as callback handler + m_net_server.get_config_object().m_phandler = static_cast(this); + + LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port); + bool res = m_net_server.init_server(bind_port, bind_ip); + if (!res) + { + LOG_ERROR("Failed to bind server"); + return false; + } + return true; + } + + bool run(size_t threads_count, bool wait = true) + { + //go to loop + LOG_PRINT("Run net_service loop( " << threads_count << " threads)...", LOG_LEVEL_0); + if(!m_net_server.run_server(threads_count, wait)) + { + LOG_ERROR("Failed to run net tcp server!"); + } + + if(wait) + LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0); + return true; + } + + bool deinit() + { + return m_net_server.deinit_server(); + } + + bool timed_wait_server_stop(uint64_t ms) + { + return m_net_server.timed_wait_server_stop(ms); + } + + bool send_stop_signal() + { + m_net_server.send_stop_signal(); + return true; + } + + int get_binded_port() + { + return m_net_server.get_binded_port(); + } + + protected: + net_utils::boosted_tcp_server > m_net_server; + }; + +} + +#endif /* JSONRPC_SERVER_IMPL_BASE_H */ + diff --git a/contrib/epee/include/net/jsonrpc_structs.h b/contrib/epee/include/net/jsonrpc_structs.h new file mode 100644 index 00000000..9df9e259 --- /dev/null +++ b/contrib/epee/include/net/jsonrpc_structs.h @@ -0,0 +1,96 @@ +#ifndef JSONRPC_STRUCTS_H +#define JSONRPC_STRUCTS_H + +#include +#include +#include "serialization/keyvalue_serialization.h" +#include "storages/portable_storage_base.h" + +namespace epee +{ + namespace json_rpc + { + template + struct request + { + std::string jsonrpc; + std::string method; + epee::serialization::storage_entry id; + t_param params; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(method) + KV_SERIALIZE(params) + END_KV_SERIALIZE_MAP() + }; + + struct error + { + int64_t code; + std::string message; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(code) + KV_SERIALIZE(message) + END_KV_SERIALIZE_MAP() + }; + + struct dummy_error + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct dummy_result + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_param result; + epee::serialization::storage_entry id; + t_error error; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(result) + KV_SERIALIZE(error) + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_param result; + epee::serialization::storage_entry id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(result) + END_KV_SERIALIZE_MAP() + }; + + template + struct response + { + std::string jsonrpc; + t_error error; + epee::serialization::storage_entry id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(jsonrpc) + KV_SERIALIZE(id) + KV_SERIALIZE(error) + END_KV_SERIALIZE_MAP() + }; + + typedef response error_response; + } +} + +#endif /* JSONRPC_STRUCTS_H */ diff --git a/tests/performance_tests/cn_slow_hash.h b/tests/performance_tests/cn_slow_hash.h new file mode 100644 index 00000000..ec001326 --- /dev/null +++ b/tests/performance_tests/cn_slow_hash.h @@ -0,0 +1,45 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "crypto/crypto.h" +#include "cryptonote_core/cryptonote_basic.h" + +class test_cn_slow_hash +{ +public: + static const size_t loop_count = 10; + +#pragma pack(push, 1) + struct data_t + { + char data[13]; + }; +#pragma pack(pop) + + static_assert(13 == sizeof(data_t), "Invalid structure size"); + + bool init() + { + if (!epee::string_tools::hex_to_pod("63617665617420656d70746f72", m_data)) + return false; + + if (!epee::string_tools::hex_to_pod("bbec2cacf69866a8e740380fe7b818fc78f8571221742d729d9d02d7f8989b87", m_expected_hash)) + return false; + + return true; + } + + bool test() + { + crypto::hash hash; + crypto::cn_slow_hash(&m_data, sizeof(m_data), hash); + return hash == m_expected_hash; + } + +private: + data_t m_data; + crypto::hash m_expected_hash; +};