// Copyright (c) 2014, The Monero Project // // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // 2. 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. // // 3. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS 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 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 */