diff --git a/CMakeLists.txt b/CMakeLists.txt index 1db93abc..9c51b646 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,12 +65,7 @@ else() set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") if(STATIC) - set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") - function(add_executable name) - _add_executable("${name}" ${ARGN}) - set_target_properties("${name}" PROPERTIES LINK_SEARCH_START_STATIC ON LINK_SEARCH_END_STATIC ON) - endfunction() + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") endif() endif() @@ -85,6 +80,8 @@ endif() include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) if(MINGW) set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock") +elseif(NOT MSVC) + set(Boost_LIBRARIES "${Boost_LIBRARIES};rt") endif() set(COMMIT_ID_IN_VERSION ON CACHE BOOL "Include commit ID in version") diff --git a/README b/README index cced0c2c..2908133e 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ On *nix: -Dependencies: GCC 4.7 or later, CMake 2.8.6 or later, and Boost 1.53 or later (except 1.54, more details here: http://goo.gl/RrCFmA). +Dependencies: GCC 4.7.3 or later, CMake 2.8.6 or later, and Boost 1.53 or later (except 1.54, more details here: http://goo.gl/RrCFmA). You may download them from: http://gcc.gnu.org/ http://www.cmake.org/ diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h index 238abc80..778679e7 100644 --- a/contrib/epee/include/console_handler.h +++ b/contrib/epee/include/console_handler.h @@ -1,6 +1,6 @@ // 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 @@ -11,7 +11,7 @@ // * 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 @@ -22,16 +22,187 @@ // 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. -// - - +// #pragma once +#include +#include +#include +#include +#include + namespace epee { + class async_stdin_reader + { + public: + async_stdin_reader() + : m_run(true) + , m_has_read_request(false) + , m_read_status(state_init) + { + m_reader_thread = std::thread(std::bind(&async_stdin_reader::reader_thread_func, this)); + } + ~async_stdin_reader() + { + stop(); + } + // Not thread safe. Only one thread can call this method at once. + bool get_line(std::string& line) + { + if (!start_read()) + return false; + + std::unique_lock lock(m_response_mutex); + while (state_init == m_read_status) + { + m_response_cv.wait(lock); + } + + bool res = false; + if (state_success == m_read_status) + { + line = m_line; + res = true; + } + + m_read_status = state_init; + + return res; + } + + void stop() + { + if (m_run) + { + m_run.store(false, std::memory_order_relaxed); + +#if defined(WIN32) + ::CloseHandle(::GetStdHandle(STD_INPUT_HANDLE)); +#endif + + m_request_cv.notify_one(); + m_reader_thread.join(); + } + } + + private: + bool start_read() + { + std::unique_lock lock(m_request_mutex); + if (!m_run.load(std::memory_order_relaxed) || m_has_read_request) + return false; + + m_has_read_request = true; + m_request_cv.notify_one(); + return true; + } + + bool wait_read() + { + std::unique_lock lock(m_request_mutex); + while (m_run.load(std::memory_order_relaxed) && !m_has_read_request) + { + m_request_cv.wait(lock); + } + + if (m_has_read_request) + { + m_has_read_request = false; + return true; + } + + return false; + } + + bool wait_stdin_data() + { +#if !defined(WIN32) + int stdin_fileno = ::fileno(stdin); + + while (m_run.load(std::memory_order_relaxed)) + { + fd_set read_set; + FD_ZERO(&read_set); + FD_SET(stdin_fileno, &read_set); + + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + + int retval = ::select(stdin_fileno + 1, &read_set, NULL, NULL, &tv); + if (retval < 0) + return false; + else if (0 < retval) + return true; + } +#endif + + return true; + } + + void reader_thread_func() + { + while (true) + { + if (!wait_read()) + break; + + std::string line; + bool read_ok = true; + if (wait_stdin_data()) + { + if (m_run.load(std::memory_order_relaxed)) + { + std::getline(std::cin, line); + read_ok = !std::cin.eof() && !std::cin.fail(); + } + } + else + { + read_ok = false; + } + + { + std::unique_lock lock(m_response_mutex); + if (m_run.load(std::memory_order_relaxed)) + { + m_line = std::move(line); + m_read_status = read_ok ? state_success : state_error; + } + else + { + m_read_status = state_cancelled; + } + m_response_cv.notify_one(); + } + } + } + + enum t_state + { + state_init, + state_success, + state_error, + state_cancelled + }; + + private: + std::thread m_reader_thread; + std::atomic m_run; + + std::string m_line; + bool m_has_read_request; + t_state m_read_status; + + std::mutex m_request_mutex; + std::mutex m_response_mutex; + std::condition_variable m_request_cv; + std::condition_variable m_response_cv; + }; template @@ -39,124 +210,113 @@ namespace epee { return true; } - - template - bool default_console_handler(t_server* psrv, chain_handler ch_handler, const std::string usage = "") + + class async_console_handler { - TRY_ENTRY(); - bool continue_handle = true; - while(continue_handle) + public: + async_console_handler() { - char command_buff[400] = {0}; - std::string command; - std::cin.getline(command_buff, 399); - if(std::cin.eof() || std::cin.fail()) - { - LOG_PRINT("std::cin.eof() or std::cin.fail(), stopping...", LOG_LEVEL_0); - continue_handle = false; - break; - } - command = command_buff; - - if(!command.compare("exit") || !command.compare("q") ) - { - psrv->send_stop_signal(); - continue_handle = false; - }else if ( !command.compare(0, 7, "set_log")) - { - //parse set_log command - if(command.size() != 9) - { - std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; - continue; - } - int n = 0; - if(!string_tools::get_xtype_from_string(n, command.substr(8, 1))) - { - std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; - continue; - } - log_space::get_set_log_detalisation_level(true, n); - LOG_PRINT_L0("New log level set " << n); - } - else if(ch_handler(psrv, command)) - continue; - else - { - std::cout << "unknown command: " << command << std::endl; - std::cout << usage; - } } - return true; - CATCH_ENTRY_L0("console_handler", false); - } - template - bool default_console_handler2(chain_handler ch_handler, const std::string usage) - { - TRY_ENTRY(); - bool continue_handle = true; - while(continue_handle) + template + bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "") { - char command_buff[400] = {0}; - std::string command; - std::cin.getline(command_buff, 399); - if(std::cin.eof() || std::cin.fail()) - { - - LOG_PRINT("std::cin.eof() or std::cin.fail(), stopping...", LOG_LEVEL_0); - continue_handle = false; - break; - } - command = command_buff; - - if(!command.compare("exit") || !command.compare("q") ) - { - continue_handle = false; - }else if ( !command.compare(0, 7, "set_log")) - { - //parse set_log command - if(command.size() != 9) - { - std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; - continue; - } - int n = 0; - if(!string_tools::get_xtype_from_string(n, command.substr(8, 1))) - { - std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; - continue; - } - log_space::get_set_log_detalisation_level(true, n); - LOG_PRINT_L0("New log level set " << n); - } - else if(ch_handler(command)) - continue; - else - { - std::cout << "unknown command: " << command << std::endl; - std::cout << usage; - } + return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); }); } - return true; - CATCH_ENTRY_L0("console_handler", false); - } - + template + bool run(chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "") + { + return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(cmd); }, [] { }); + } + + void stop() + { + m_stdin_reader.stop(); + } + + private: + template + bool run(const std::string& prompt, const std::string& usage, const t_cmd_handler& cmd_handler, const t_exit_handler& exit_handler) + { + TRY_ENTRY(); + bool continue_handle = true; + while(continue_handle) + { + if (!prompt.empty()) + { + epee::log_space::set_console_color(epee::log_space::console_color_yellow, true); + std::cout << prompt; + if (' ' != prompt.back()) + std::cout << ' '; + epee::log_space::reset_console_color(); + std::cout.flush(); + } + + std::string command; + if(!m_stdin_reader.get_line(command)) + { + LOG_PRINT("Failed to read line. Stopping...", LOG_LEVEL_0); + continue_handle = false; + break; + } + + LOG_PRINT_L2("Read command: " << command); + if(0 == command.compare("exit") || 0 == command.compare("q")) + { + continue_handle = false; + }else if (!command.compare(0, 7, "set_log")) + { + //parse set_log command + if(command.size() != 9) + { + std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; + continue; + } + uint16_t n = 0; + if(!string_tools::get_xtype_from_string(n, command.substr(8, 1))) + { + std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl; + continue; + } + log_space::get_set_log_detalisation_level(true, n); + LOG_PRINT_L0("New log level set " << n); + }else if (command.empty()) + { + continue; + } + else if(cmd_handler(command)) + { + continue; + } else + { + std::cout << "unknown command: " << command << std::endl; + std::cout << usage; + } + } + exit_handler(); + return true; + CATCH_ENTRY_L0("console_handler", false); + } + + private: + async_stdin_reader m_stdin_reader; + }; template - bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& usage = "") + bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") { - boost::thread( boost::bind(default_console_handler, ptsrv, handlr, usage) ); + std::shared_ptr console_handler = std::make_shared(); + boost::thread(boost::bind(&async_console_handler::run, console_handler, ptsrv, handlr, prompt, usage)).detach(); return true; } template - bool start_default_console(t_server* ptsrv, const std::string& usage = "") + bool start_default_console(t_server* ptsrv, const std::string& prompt, const std::string& usage = "") { - return start_default_console(ptsrv, empty_commands_handler, usage); + return start_default_console(ptsrv, empty_commands_handler, prompt, usage); } template @@ -166,15 +326,16 @@ namespace epee } template - bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& usage = "") + bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") { - return default_console_handler(ptsrv, boost::bind(no_srv_param_adapter, _1, _2, handlr), usage); + async_console_handler console_handler; + return console_handler.run(ptsrv, boost::bind(no_srv_param_adapter, _1, _2, handlr), prompt, usage); } template - bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& usage = "") + bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") { - boost::thread( boost::bind(run_default_console_handler_no_srv_param, ptsrv, handlr, usage) ); + boost::thread( boost::bind(run_default_console_handler_no_srv_param, ptsrv, handlr, prompt, usage) ); return true; } @@ -209,7 +370,8 @@ namespace epee typedef std::map > command_handlers_map; std::unique_ptr m_console_thread; command_handlers_map m_command_handlers; - public: + async_console_handler m_console_handler; + public: std::string get_usage() { std::stringstream ss; @@ -217,7 +379,7 @@ namespace epee for(auto& x:m_command_handlers) if(x.first.size() > max_command_len) max_command_len = x.first.size(); - + for(auto& x:m_command_handlers) { ss.width(max_command_len + 3); @@ -255,24 +417,22 @@ namespace epee start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1)); return true; }*/ - - bool start_handling(const std::string& usage_string = "") + + bool start_handling(const std::string& prompt, const std::string& usage_string = "") { - m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, usage_string) )); + m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string))); + m_console_thread->detach(); return true; } - bool stop_handling() + void stop_handling() { - if(m_console_thread.get()) - m_console_thread->interrupt(); - return true; + m_console_handler.stop(); } - - bool run_handling(const std::string usage_string) + bool run_handling(const std::string& prompt, const std::string& usage_string) { - return default_console_handler2(boost::bind(&console_handlers_binder::process_command_str, this, _1), usage_string); + return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string); } /*template @@ -280,7 +440,6 @@ namespace epee { return run_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1), usage_string); }*/ - }; /* work around because of broken boost bind */ @@ -292,19 +451,23 @@ namespace epee return console_handlers_binder::process_command_str(cmd); } public: - bool start_handling(t_server* psrv, const std::string& usage_string = "") + bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "") { - boost::thread(boost::bind(&srv_console_handlers_binder::run_handling, this, psrv, usage_string) ); + boost::thread(boost::bind(&srv_console_handlers_binder::run_handling, this, psrv, prompt, usage_string)).detach(); return true; } - bool run_handling(t_server* psrv, const std::string usage_string) + bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string) { - return default_console_handler(psrv, boost::bind(&srv_console_handlers_binder::process_command_str, this, _1, _2), usage_string); + return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder::process_command_str, this, _1, _2), prompt, usage_string); } + + void stop_handling() + { + m_console_handler.stop(); + } + + private: + async_console_handler m_console_handler; }; - - } - - diff --git a/contrib/epee/include/copyable_atomic.h b/contrib/epee/include/copyable_atomic.h new file mode 100644 index 00000000..6b5691ab --- /dev/null +++ b/contrib/epee/include/copyable_atomic.h @@ -0,0 +1,54 @@ +// 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. +// + +#pragma once + +#include + +namespace epee +{ + class copyable_atomic: public std::atomic + { + public: + copyable_atomic() + {}; + copyable_atomic(const copyable_atomic& a):std::atomic(a.load()) + {} + copyable_atomic& operator= (const copyable_atomic& a) + { + store(a.load()); + return *this; + } + uint32_t operator++() + { + return std::atomic::operator++(); + } + uint32_t operator++(int fake) + { + return std::atomic::operator++(fake); + } + }; +} \ No newline at end of file diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h index 44efd468..349d6d82 100644 --- a/contrib/epee/include/math_helper.h +++ b/contrib/epee/include/math_helper.h @@ -154,7 +154,7 @@ namespace math_helper #endif //#ifdef WINDOWS_PLATFORM_EX - template + template class speed { public: @@ -167,7 +167,7 @@ namespace math_helper bool chick() { #ifndef DEBUG_STUB - boost::uint64_t ticks = misc_utils::get_tick_count(); + uint64_t ticks = misc_utils::get_tick_count(); CRITICAL_REGION_BEGIN(m_lock); m_chicks.push_back(ticks); CRITICAL_REGION_END(); @@ -192,10 +192,10 @@ namespace math_helper } private: - bool flush(boost::uint64_t ticks) + bool flush(uint64_t ticks) { CRITICAL_REGION_BEGIN(m_lock); - std::list::iterator it = m_chicks.begin(); + std::list::iterator it = m_chicks.begin(); while(it != m_chicks.end()) { if(*it + m_time_window < ticks) @@ -207,8 +207,8 @@ namespace math_helper return true; } - std::list m_chicks; - boost::uint64_t m_time_window; + std::list m_chicks; + uint64_t m_time_window; size_t m_last_speed_value; critical_section m_lock; }; diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 446d4bd3..f2bd03b0 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -29,6 +29,7 @@ #define _MISC_LOG_EX_H_ //#include +#include #include #include #include @@ -43,17 +44,20 @@ #include #include +#if defined(WIN32) +#include +#else +#include +#endif + #include "static_initializer.h" #include "string_tools.h" #include "time_helper.h" #include "misc_os_dependent.h" - #include "syncobj.h" - - #define LOG_LEVEL_SILENT -1 #define LOG_LEVEL_0 0 #define LOG_LEVEL_1 1 @@ -64,8 +68,6 @@ #define LOG_LEVEL_MAX LOG_LEVEL_4 - - #define LOGGER_NULL 0 #define LOGGER_FILE 1 #define LOGGER_DEBUGGER 2 @@ -124,7 +126,7 @@ namespace log_space virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL)=0; virtual int get_type(){return 0;} - virtual bool set_max_logfile_size(boost::uint64_t max_size){return true;}; + virtual bool set_max_logfile_size(uint64_t max_size){return true;}; virtual bool set_log_rotate_cmd(const std::string& cmd){return true;}; }; @@ -198,8 +200,29 @@ namespace log_space }; #endif + inline bool is_stdout_a_tty() + { + static std::atomic initialized(false); + static std::atomic is_a_tty(false); + + if (!initialized.load(std::memory_order_acquire)) + { +#if defined(WIN32) + is_a_tty.store(0 != _isatty(_fileno(stdout)), std::memory_order_relaxed); +#else + is_a_tty.store(0 != isatty(fileno(stdout)), std::memory_order_relaxed); +#endif + initialized.store(true, std::memory_order_release); + } + + return is_a_tty.load(std::memory_order_relaxed); + } + inline void set_console_color(int color, bool bright) { + if (!is_stdout_a_tty()) + return; + switch(color) { case console_color_default: @@ -315,11 +338,15 @@ namespace log_space } inline void reset_console_color() { + if (!is_stdout_a_tty()) + return; + #ifdef WIN32 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); #else std::cout << "\033[0m"; + std::cout.flush(); #endif } @@ -384,7 +411,7 @@ namespace log_space } } - //boost::uint32_t b = 0; + //uint32_t b = 0; //::WriteConsoleA(::GetStdHandle(STD_OUTPUT_HANDLE), ptarget_buf, buffer_len, (DWORD*)&b, 0); std::cout << ptarget_buf; if(pallocated_buf) delete [] pallocated_buf; @@ -459,7 +486,7 @@ namespace log_space std::ofstream* m_pdefault_file_stream; std::string m_log_rotate_cmd; std::string m_default_log_filename; - boost::uint64_t m_max_logfile_size; + uint64_t m_max_logfile_size; std::ofstream* add_new_stream_and_open(const char* pstream_name) @@ -474,7 +501,7 @@ namespace log_space return pstream; } - bool set_max_logfile_size(boost::uint64_t max_size) + bool set_max_logfile_size(uint64_t max_size) { m_max_logfile_size = max_size; return true; @@ -508,7 +535,7 @@ namespace log_space if(m_max_logfile_size) { std::ofstream::pos_type pt = m_target_file_stream->tellp(); - boost::uint64_t current_sz = pt; + uint64_t current_sz = pt; if(current_sz > m_max_logfile_size) { std::cout << "current_sz= " << current_sz << " m_max_logfile_size= " << m_max_logfile_size << std::endl; @@ -579,7 +606,7 @@ namespace log_space std::for_each(m_log_streams.begin(), m_log_streams.end(), delete_ptr()); } - bool set_max_logfile_size(boost::uint64_t max_size) + bool set_max_logfile_size(uint64_t max_size) { for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++) it->first->set_max_logfile_size(max_size); @@ -725,7 +752,7 @@ namespace log_space { } - bool set_max_logfile_size(boost::uint64_t max_size) + bool set_max_logfile_size(uint64_t max_size) { CRITICAL_REGION_BEGIN(m_critical_sec); m_log_target.set_max_logfile_size(max_size); @@ -895,7 +922,7 @@ namespace log_space return res; } - static bool set_max_logfile_size(boost::uint64_t file_size) + static bool set_max_logfile_size(uint64_t file_size) { logger* plogger = get_or_create_instance(); if(!plogger) return false; @@ -1004,9 +1031,9 @@ POP_WARNINGS return is_need; } - static boost::uint64_t get_set_err_count(bool is_need_set = false, boost::uint64_t err_val = false) + static uint64_t get_set_err_count(bool is_need_set = false, uint64_t err_val = false) { - static boost::uint64_t err_count = 0; + static uint64_t err_count = 0; if(is_need_set) err_count = err_val; diff --git a/contrib/epee/include/misc_os_dependent.h b/contrib/epee/include/misc_os_dependent.h index 0850c7c0..4d9c991e 100644 --- a/contrib/epee/include/misc_os_dependent.h +++ b/contrib/epee/include/misc_os_dependent.h @@ -48,7 +48,7 @@ namespace epee namespace misc_utils { - inline boost::uint64_t get_tick_count() + inline uint64_t get_tick_count() { #if defined(_MSC_VER) return ::GetTickCount64(); diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index d49b8f86..29bf59a5 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -57,7 +57,7 @@ namespace net_utils struct i_connection_filter { - virtual bool is_remote_ip_allowed(boost::uint32_t adress)=0; + virtual bool is_remote_ip_allowed(uint32_t adress)=0; protected: virtual ~i_connection_filter(){} }; @@ -76,7 +76,7 @@ namespace net_utils typedef typename t_protocol_handler::connection_context t_connection_context; /// Construct a connection with the given io_service. explicit connection(boost::asio::io_service& io_service, - typename t_protocol_handler::config_type& config, volatile boost::uint32_t& sock_count, i_connection_filter * &pfilter); + typename t_protocol_handler::config_type& config, volatile uint32_t& sock_count, i_connection_filter * &pfilter); virtual ~connection(); /// Get the socket associated with the connection. @@ -117,11 +117,11 @@ namespace net_utils boost::array buffer_; t_connection_context context; - volatile boost::uint32_t m_want_close_connection; + volatile uint32_t m_want_close_connection; std::atomic m_was_shutdown; critical_section m_send_que_lock; std::list m_send_que; - volatile boost::uint32_t& m_ref_sockets_count; + volatile uint32_t& m_ref_sockets_count; i_connection_filter* &m_pfilter; volatile bool m_is_multithreaded; @@ -156,7 +156,7 @@ namespace net_utils bool run_server(size_t threads_count, bool wait = true); /// wait for service workers stop - bool timed_wait_server_stop(boost::uint64_t wait_mseconds); + bool timed_wait_server_stop(uint64_t wait_mseconds); /// Stop the server. void send_stop_signal(); @@ -171,9 +171,9 @@ namespace net_utils void set_connection_filter(i_connection_filter* pfilter); - bool connect(const std::string& adr, const std::string& port, boost::uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0"); + 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"); template - bool connect_async(const std::string& adr, const std::string& port, boost::uint32_t conn_timeot, 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, t_callback cb, const std::string& bind_ip = "0.0.0.0"); typename t_protocol_handler::config_type& get_config_object(){return m_config;} @@ -191,13 +191,13 @@ namespace net_utils m_timer(io_serice) {} boost::asio::deadline_timer m_timer; - boost::uint64_t m_period; + uint64_t m_period; }; template struct idle_callback_conext: public idle_callback_conext_base { - idle_callback_conext(boost::asio::io_service& io_serice, t_handler& h, boost::uint64_t period): + idle_callback_conext(boost::asio::io_service& io_serice, t_handler& h, uint64_t period): idle_callback_conext_base(io_serice), m_handler(h) {this->m_period = period;} @@ -210,7 +210,7 @@ namespace net_utils }; template - bool add_idle_handler(t_handler t_callback, boost::uint64_t timeout_ms) + bool add_idle_handler(t_handler t_callback, uint64_t timeout_ms) { boost::shared_ptr ptr(new idle_callback_conext(io_service_, t_callback, timeout_ms)); //needed call handler here ?... @@ -258,7 +258,7 @@ namespace net_utils connection_ptr new_connection_; std::atomic m_stop_signal_sent; uint32_t m_port; - volatile boost::uint32_t m_sockets_count; + volatile uint32_t m_sockets_count; std::string m_address; std::string m_thread_name_prefix; size_t m_threads_count; diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 1d6a1662..236bc159 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -49,10 +49,9 @@ PRAGMA_WARNING_DISABLE_VS(4355) template connection::connection(boost::asio::io_service& io_service, - typename t_protocol_handler::config_type& config, volatile boost::uint32_t& sock_count, i_connection_filter* &pfilter) + typename t_protocol_handler::config_type& config, volatile uint32_t& sock_count, i_connection_filter* &pfilter) : strand_(io_service), socket_(io_service), - //context(typename boost::value_initialized()) m_protocol_handler(this, config, context), m_want_close_connection(0), m_was_shutdown(0), @@ -217,6 +216,8 @@ PRAGMA_WARNING_DISABLE_VS(4355) if (!e) { LOG_PRINT("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred, LOG_LEVEL_4); + context.m_last_recv = time(NULL); + context.m_recv_cnt += bytes_transferred; bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred); if(!recv_res) { @@ -294,6 +295,8 @@ PRAGMA_WARNING_DISABLE_VS(4355) return false; LOG_PRINT("[sock " << socket_.native_handle() << "] SEND " << cb, LOG_LEVEL_4); + context.m_last_send = time(NULL); + context.m_send_cnt += cb; //some data should be wrote to stream //request complete @@ -473,8 +476,8 @@ DISABLE_GCC_WARNING(maybe-uninitialized) uint32_t p = 0; if (port.size() && !string_tools::get_xtype_from_string(p, port)) { + LOG_ERROR("Failed to convert port no = " << port); return false; - LOG_ERROR("Failed to convert port no = port"); } return this->init_server(p, address); } @@ -586,7 +589,7 @@ POP_WARNINGS } //--------------------------------------------------------------------------------- template - bool boosted_tcp_server::timed_wait_server_stop(boost::uint64_t wait_mseconds) + bool boosted_tcp_server::timed_wait_server_stop(uint64_t wait_mseconds) { TRY_ENTRY(); boost::chrono::milliseconds ms(wait_mseconds); @@ -641,7 +644,7 @@ POP_WARNINGS } //--------------------------------------------------------------------------------- template - bool boosted_tcp_server::connect(const std::string& adr, const std::string& port, boost::uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip) + bool boosted_tcp_server::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip) { TRY_ENTRY(); @@ -732,7 +735,7 @@ POP_WARNINGS } //--------------------------------------------------------------------------------- template template - bool boosted_tcp_server::connect_async(const std::string& adr, const std::string& port, boost::uint32_t conn_timeout, t_callback cb, const std::string& bind_ip) + bool boosted_tcp_server::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_callback cb, const std::string& bind_ip) { TRY_ENTRY(); connection_ptr new_connection_l(new connection(io_service_, m_config, m_sockets_count, m_pfilter) ); diff --git a/contrib/epee/include/net/http_base.h b/contrib/epee/include/net/http_base.h index 6de537a4..49b0839b 100644 --- a/contrib/epee/include/net/http_base.h +++ b/contrib/epee/include/net/http_base.h @@ -127,7 +127,7 @@ namespace net_utils std::string schema; std::string host; std::string uri; - boost::uint64_t port; + uint64_t port; uri_content m_uri_content; }; diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h index 4aebcf2a..4bf48750 100644 --- a/contrib/epee/include/net/http_protocol_handler.h +++ b/contrib/epee/include/net/http_protocol_handler.h @@ -55,10 +55,11 @@ namespace net_utils /************************************************************************/ /* */ /************************************************************************/ + template class simple_http_connection_handler { public: - typedef net_utils::connection_context_base connection_context; + typedef t_connection_context connection_context;//t_connection_context net_utils::connection_context_base connection_context; typedef http_server_config config_type; simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config); @@ -141,30 +142,32 @@ namespace net_utils i_service_endpoint* m_psnd_hndlr; }; - + template struct i_http_server_handler { virtual ~i_http_server_handler(){} - virtual bool handle_http_request(const http_request_info& query_info, http_response_info& response, const net_utils::connection_context_base& m_conn_context)=0; + virtual bool handle_http_request(const http_request_info& query_info, http_response_info& response, t_connection_context& m_conn_context)=0; virtual bool init_server_thread(){return true;} virtual bool deinit_server_thread(){return true;} }; - + template struct custum_handler_config: public http_server_config { - i_http_server_handler* m_phandler; + i_http_server_handler* m_phandler; }; /************************************************************************/ /* */ /************************************************************************/ - class http_custom_handler: public simple_http_connection_handler + + template + class http_custom_handler: public simple_http_connection_handler { public: - typedef custum_handler_config config_type; + typedef custum_handler_config config_type; - http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, const net_utils::connection_context_base& conn_context):simple_http_connection_handler(psnd_hndlr, config), + http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context):simple_http_connection_handler(psnd_hndlr, config), m_config(config), m_conn_context(conn_context) {} @@ -198,7 +201,7 @@ namespace net_utils private: //simple_http_connection_handler::config_type m_stub_config; config_type& m_config; - const net_utils::connection_context_base& m_conn_context; + t_connection_context& m_conn_context; }; } } diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl index 810c46db..b8eeb599 100644 --- a/contrib/epee/include/net/http_protocol_handler.inl +++ b/contrib/epee/include/net/http_protocol_handler.inl @@ -191,8 +191,8 @@ namespace net_utils //-------------------------------------------------------------------------------------------- - inline - simple_http_connection_handler::simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config): + template + simple_http_connection_handler::simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config): m_state(http_state_retriving_comand_line), m_body_transfer_type(http_body_transfer_undefined), m_is_stop_handling(false), @@ -205,7 +205,8 @@ namespace net_utils } //-------------------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::set_ready_state() + template + bool simple_http_connection_handler::set_ready_state() { m_is_stop_handling = false; m_state = http_state_retriving_comand_line; @@ -215,7 +216,8 @@ namespace net_utils return true; } //-------------------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::handle_recv(const void* ptr, size_t cb) + template + bool simple_http_connection_handler::handle_recv(const void* ptr, size_t cb) { std::string buf((const char*)ptr, cb); //LOG_PRINT_L0("HTTP_RECV: " << ptr << "\r\n" << buf); @@ -227,7 +229,8 @@ namespace net_utils return res; } //-------------------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::handle_buff_in(std::string& buf) + template + bool simple_http_connection_handler::handle_buff_in(std::string& buf) { if(m_cache.size()) @@ -324,9 +327,10 @@ namespace net_utils } //-------------------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::handle_invoke_query_line() + template + bool simple_http_connection_handler::handle_invoke_query_line() { - LOG_FRAME("simple_http_connection_handler::handle_recognize_protocol_out(*)", LOG_LEVEL_3); + LOG_FRAME("simple_http_connection_handler::handle_recognize_protocol_out(*)", LOG_LEVEL_3); STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+).(\\d+))\r?\n", boost::regex::icase | boost::regex::normal); // 123 4 5 6 7 8 9 10 11 12 @@ -348,14 +352,15 @@ namespace net_utils }else { m_state = http_state_error; - LOG_ERROR("simple_http_connection_handler::handle_invoke_query_line(): Failed to match first line: " << m_cache); + LOG_ERROR("simple_http_connection_handler::handle_invoke_query_line(): Failed to match first line: " << m_cache); return false; } return false; } //-------------------------------------------------------------------------------------------- - inline std::string::size_type simple_http_connection_handler::match_end_of_header(const std::string& buf) + template + std::string::size_type simple_http_connection_handler::match_end_of_header(const std::string& buf) { //Here we returning head size, including terminating sequence (\r\n\r\n or \n\n) @@ -368,18 +373,19 @@ namespace net_utils return res; } //-------------------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::analize_cached_request_header_and_invoke_state(size_t pos) + template + bool simple_http_connection_handler::analize_cached_request_header_and_invoke_state(size_t pos) { //LOG_PRINT_L4("HTTP HEAD:\r\n" << m_cache.substr(0, pos)); - LOG_FRAME("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(*)", LOG_LEVEL_3); + LOG_FRAME("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(*)", LOG_LEVEL_3); m_query_info.m_full_request_buf_size = pos; m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos); if(!parse_cached_header(m_query_info.m_header_info, m_cache, pos)) { - LOG_ERROR("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache); + LOG_ERROR("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache); m_state = http_state_error; } @@ -394,7 +400,7 @@ namespace net_utils m_body_transfer_type = http_body_transfer_measure; if(!get_len_from_content_lenght(m_query_info.m_header_info.m_content_length, m_len_summary)) { - LOG_ERROR("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="< + bool simple_http_connection_handler::handle_retriving_query_body() { switch(m_body_transfer_type) { @@ -426,7 +433,7 @@ namespace net_utils case http_body_transfer_multipart: case http_body_transfer_undefined: default: - LOG_ERROR("simple_http_connection_handler::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type); + LOG_ERROR("simple_http_connection_handler::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type); m_state = http_state_error; return false; } @@ -434,7 +441,8 @@ namespace net_utils return true; } //----------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::handle_query_measure() + template + bool simple_http_connection_handler::handle_query_measure() { if(m_len_remain >= m_cache.size()) @@ -459,7 +467,8 @@ namespace net_utils return true; } //-------------------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos) + template + bool simple_http_connection_handler::parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos) { LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_3); @@ -503,7 +512,7 @@ namespace net_utils body_info.m_etc_fields.push_back(std::pair(result[field_etc_name], result[field_val])); else { - LOG_ERROR("simple_http_connection_handler::parse_cached_header() not matched last entry in:"<::parse_cached_header() not matched last entry in:"< + bool simple_http_connection_handler::get_len_from_content_lenght(const std::string& str, size_t& OUT len) { STATIC_REGEXP_EXPR_1(rexp_mach_field, "\\d+", boost::regex::normal); std::string res; @@ -523,7 +533,8 @@ namespace net_utils return true; } //----------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::handle_request_and_send_response(const http::http_request_info& query_info) + template + bool simple_http_connection_handler::handle_request_and_send_response(const http::http_request_info& query_info) { http_response_info response; bool res = handle_request(query_info, response); @@ -540,7 +551,8 @@ namespace net_utils return res; } //----------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::handle_request(const http::http_request_info& query_info, http_response_info& response) + template + bool simple_http_connection_handler::handle_request(const http::http_request_info& query_info, http_response_info& response) { std::string uri_to_path = query_info.m_uri_content.m_path; @@ -570,7 +582,8 @@ namespace net_utils return true; } //----------------------------------------------------------------------------------- - inline std::string simple_http_connection_handler::get_response_header(const http_response_info& response) + template + std::string simple_http_connection_handler::get_response_header(const http_response_info& response) { std::string buf = "HTTP/1.1 "; buf += boost::lexical_cast(response.m_response_code) + " " + response.m_response_comment + "\r\n" + @@ -607,7 +620,8 @@ namespace net_utils return buf; } //----------------------------------------------------------------------------------- - inline std::string simple_http_connection_handler::get_file_mime_tipe(const std::string& path) + template + std::string simple_http_connection_handler::get_file_mime_tipe(const std::string& path) { std::string result; std::string ext = string_tools::get_extension(path); @@ -632,7 +646,8 @@ namespace net_utils return result; } //----------------------------------------------------------------------------------- - inline std::string simple_http_connection_handler::get_not_found_response_body(const std::string& URI) + template + std::string simple_http_connection_handler::get_not_found_response_body(const std::string& URI) { std::string body = "\r\n" @@ -648,7 +663,8 @@ namespace net_utils return body; } //-------------------------------------------------------------------------------------------- - inline bool simple_http_connection_handler::slash_to_back_slash(std::string& str) + template + bool simple_http_connection_handler::slash_to_back_slash(std::string& str) { for(std::string::iterator it = str.begin(); it!=str.end(); it++) if('/' == *it) diff --git a/contrib/epee/include/net/http_server_cp2.h b/contrib/epee/include/net/http_server_cp2.h index dd76d06f..1a503a4d 100644 --- a/contrib/epee/include/net/http_server_cp2.h +++ b/contrib/epee/include/net/http_server_cp2.h @@ -36,8 +36,8 @@ namespace epee { namespace net_utils { - typedef boosted_tcp_server boosted_http_server_file_system; - typedef boosted_tcp_server boosted_http_server_custum_handling; + typedef boosted_tcp_server > boosted_http_server_file_system; + typedef boosted_tcp_server > boosted_http_server_custum_handling; } } diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index 7a8bdd4a..80c32e3c 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -31,9 +31,9 @@ #include "http_base.h" -#define CHAIN_HTTP_TO_MAP2() bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \ +#define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \ epee::net_utils::http::http_response_info& response, \ - const epee::net_utils::connection_context_base& m_conn_context) \ + context_type& m_conn_context) \ {\ LOG_PRINT_L2("HTTP [" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "] " << query_info.m_http_method_str << " " << query_info.m_URI); \ response.m_response_code = 200; \ @@ -44,9 +44,9 @@ } -#define BEGIN_URI_MAP2() bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \ +#define BEGIN_URI_MAP2() template bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \ epee::net_utils::http::http_response_info& response_info, \ - const epee::net_utils::connection_context_base& m_conn_context) { \ + t_context& m_conn_context) { \ bool handled = false; \ if(false) return true; //just a stub to have "else if" @@ -58,22 +58,22 @@ else if(query_info.m_URI == s_pattern) \ { \ handled = true; \ - boost::uint64_t ticks = misc_utils::get_tick_count(); \ + uint64_t ticks = misc_utils::get_tick_count(); \ boost::value_initialized req; \ bool parse_res = epee::serialization::load_t_from_json(static_cast(req), query_info.m_body); \ CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse json: \r\n" << query_info.m_body); \ - boost::uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ boost::value_initialized resp;\ - if(!callback_f(static_cast(req), static_cast(resp))) \ + if(!callback_f(static_cast(req), static_cast(resp), m_conn_context)) \ { \ LOG_ERROR("Failed to " << #callback_f << "()"); \ response_info.m_response_code = 500; \ response_info.m_response_comment = "Internal Server Error"; \ return true; \ } \ - boost::uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ epee::serialization::store_t_to_json(static_cast(resp), response_info.m_body); \ - boost::uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ response_info.m_mime_tipe = "application/json"; \ response_info.m_header_info.m_content_type = " application/json"; \ LOG_PRINT( s_pattern << " processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \ @@ -83,22 +83,22 @@ else if(query_info.m_URI == s_pattern) \ { \ handled = true; \ - boost::uint64_t ticks = misc_utils::get_tick_count(); \ + uint64_t ticks = misc_utils::get_tick_count(); \ boost::value_initialized req; \ bool parse_res = epee::serialization::load_t_from_binary(static_cast(req), query_info.m_body); \ CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse bin body data, body size=" << query_info.m_body.size()); \ - boost::uint64_t ticks1 = misc_utils::get_tick_count(); \ + uint64_t ticks1 = misc_utils::get_tick_count(); \ boost::value_initialized resp;\ - if(!callback_f(static_cast(req), static_cast(resp))) \ + if(!callback_f(static_cast(req), static_cast(resp), m_conn_context)) \ { \ LOG_ERROR("Failed to " << #callback_f << "()"); \ response_info.m_response_code = 500; \ response_info.m_response_comment = "Internal Server Error"; \ return true; \ } \ - boost::uint64_t ticks2 = misc_utils::get_tick_count(); \ + uint64_t ticks2 = misc_utils::get_tick_count(); \ epee::serialization::store_t_to_binary(static_cast(resp), response_info.m_body); \ - boost::uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ response_info.m_mime_tipe = " application/octet-stream"; \ response_info.m_header_info.m_content_type = " application/octet-stream"; \ LOG_PRINT( s_pattern << "() processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \ @@ -170,7 +170,7 @@ namespace epee #define BEGIN_JSON_RPC_MAP(uri) else if(query_info.m_URI == uri) \ { \ - boost::uint64_t ticks = epee::misc_utils::get_tick_count(); \ + uint64_t ticks = epee::misc_utils::get_tick_count(); \ epee::serialization::portable_storage ps; \ if(!ps.load_from_json(query_info.m_body)) \ { \ @@ -198,20 +198,20 @@ namespace epee boost::value_initialized > req_; \ epee::json_rpc::request& req = static_cast&>(req_);\ req.load(ps); \ - boost::uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ boost::value_initialized > resp_; \ epee::json_rpc::response& resp = static_cast &>(resp_); \ resp.id = req.id; \ epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ fail_resp.id = req.id; \ - if(!callback_f(req.params, resp.result, fail_resp.error)) \ + if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context)) \ { \ epee::serialization::store_t_to_json(static_cast(fail_resp), response_info.m_body); \ return true; \ } \ - boost::uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ epee::serialization::store_t_to_json(resp, response_info.m_body); \ - boost::uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ response_info.m_mime_tipe = "application/json"; \ response_info.m_header_info.m_content_type = " application/json"; \ LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \ @@ -226,11 +226,11 @@ namespace epee boost::value_initialized > req_; \ epee::json_rpc::request& req = static_cast&>(req_);\ req.load(ps); \ - boost::uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks1 = epee::misc_utils::get_tick_count(); \ boost::value_initialized > resp_; \ epee::json_rpc::response& resp = static_cast &>(resp_); \ resp.id = req.id; \ - if(!callback_f(req.params, resp.result)) \ + if(!callback_f(req.params, resp.result, m_conn_context)) \ { \ epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ fail_resp.id = req.id; \ @@ -239,9 +239,9 @@ namespace epee epee::serialization::store_t_to_json(static_cast(fail_resp), response_info.m_body); \ return true; \ } \ - boost::uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks2 = epee::misc_utils::get_tick_count(); \ epee::serialization::store_t_to_json(resp, response_info.m_body); \ - boost::uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ + uint64_t ticks3 = epee::misc_utils::get_tick_count(); \ response_info.m_mime_tipe = "application/json"; \ response_info.m_header_info.m_content_type = " application/json"; \ LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \ diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h index f81b4f60..c02475c3 100644 --- a/contrib/epee/include/net/http_server_impl_base.h +++ b/contrib/epee/include/net/http_server_impl_base.h @@ -39,8 +39,8 @@ namespace epee { - template - class http_server_impl_base: public net_utils::http::i_http_server_handler + template + class http_server_impl_base: public net_utils::http::i_http_server_handler { public: @@ -107,6 +107,6 @@ namespace epee } protected: - net_utils::boosted_http_server_custum_handling m_net_server; + net_utils::boosted_tcp_server > m_net_server; }; } \ No newline at end of file diff --git a/contrib/epee/include/net/levin_base.h b/contrib/epee/include/net/levin_base.h index 503a9e5d..d630bff1 100644 --- a/contrib/epee/include/net/levin_base.h +++ b/contrib/epee/include/net/levin_base.h @@ -41,13 +41,13 @@ namespace levin #pragma pack(1) struct bucket_head { - boost::uint64_t m_signature; - boost::uint64_t m_cb; - bool m_have_to_return_data; - boost::uint32_t m_command; - boost::int32_t m_return_code; - boost::uint32_t m_reservedA; //probably some flags in future - boost::uint32_t m_reservedB; //probably some check sum in future + uint64_t m_signature; + uint64_t m_cb; + bool m_have_to_return_data; + uint32_t m_command; + int32_t m_return_code; + uint32_t m_reservedA; //probably some flags in future + uint32_t m_reservedB; //probably some check sum in future }; #pragma pack(pop) @@ -56,13 +56,13 @@ namespace levin #pragma pack(1) struct bucket_head2 { - boost::uint64_t m_signature; - boost::uint64_t m_cb; - bool m_have_to_return_data; - boost::uint32_t m_command; - boost::int32_t m_return_code; - boost::uint32_t m_flags; - boost::uint32_t m_protocol_version; + uint64_t m_signature; + uint64_t m_cb; + bool m_have_to_return_data; + uint32_t m_command; + int32_t m_return_code; + uint32_t m_flags; + uint32_t m_protocol_version; }; #pragma pack(pop) diff --git a/contrib/epee/include/net/levin_client_async.h b/contrib/epee/include/net/levin_client_async.h index b02fa7ee..9e76cd50 100644 --- a/contrib/epee/include/net/levin_client_async.h +++ b/contrib/epee/include/net/levin_client_async.h @@ -49,16 +49,16 @@ namespace levin class levin_client_async { levin_commands_handler* m_pcommands_handler; - volatile boost::uint32_t m_is_stop; - volatile boost::uint32_t m_threads_count; + volatile uint32_t m_is_stop; + volatile uint32_t m_threads_count; ::critical_section m_send_lock; std::string m_local_invoke_buff; ::critical_section m_local_invoke_buff_lock; volatile int m_invoke_res; - volatile boost::uint32_t m_invoke_data_ready; - volatile boost::uint32_t m_invoke_is_active; + volatile uint32_t m_invoke_data_ready; + volatile uint32_t m_invoke_is_active; boost::mutex m_invoke_event; boost::condition_variable m_invoke_cond; @@ -69,14 +69,14 @@ namespace levin { bucket_head m_hd; std::string m_body; - boost::uint32_t m_connection_index; + uint32_t m_connection_index; }; std::list m_recieved_packets; /* m_current_connection_index needed when some connection was broken and reconnected - in this case we could have some received packets in que, which shoud not be handled */ - volatile boost::uint32_t m_current_connection_index; + volatile uint32_t m_current_connection_index; ::critical_section m_invoke_lock; ::critical_section m_reciev_packet_lock; ::critical_section m_connection_lock; @@ -101,7 +101,7 @@ namespace levin m_pcommands_handler = phandler; } - bool connect(boost::uint32_t ip, boost::uint32_t port, boost::uint32_t timeout) + bool connect(uint32_t ip, uint32_t port, uint32_t timeout) { loop_call_guard(); critical_region cr(m_connection_lock); @@ -388,7 +388,7 @@ namespace levin bool reciev_and_process_incoming_data() { bucket_head head = {0}; - boost::uint32_t conn_index = 0; + uint32_t conn_index = 0; bool is_request = false; std::string local_buff; CRITICAL_REGION_BEGIN(m_reciev_packet_lock);//to protect from socket reconnect between head and body @@ -485,7 +485,7 @@ namespace levin return true; } - bool process_recieved_packet(bucket_head& head, const std::string& local_buff, boost::uint32_t conn_index) + bool process_recieved_packet(bucket_head& head, const std::string& local_buff, uint32_t conn_index) { net_utils::connection_context_base conn_context; @@ -544,7 +544,7 @@ namespace levin bool have_some_work = false; std::string local_buff; bucket_head bh = {0}; - boost::uint32_t conn_index = 0; + uint32_t conn_index = 0; CRITICAL_REGION_BEGIN(m_recieved_packets_lock); if(m_recieved_packets.size()) diff --git a/contrib/epee/include/net/levin_protocol_handler.h b/contrib/epee/include/net/levin_protocol_handler.h index adc6e95d..512ba1c3 100644 --- a/contrib/epee/include/net/levin_protocol_handler.h +++ b/contrib/epee/include/net/levin_protocol_handler.h @@ -98,7 +98,7 @@ namespace levin case conn_state_reading_head: if(m_cach_in_buffer.size() < sizeof(bucket_head)) { - if(m_cach_in_buffer.size() >= sizeof(boost::uint64_t) && *((boost::uint64_t*)m_cach_in_buffer.data()) != LEVIN_SIGNATURE) + if(m_cach_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cach_in_buffer.data()) != LEVIN_SIGNATURE) { LOG_ERROR("Signature missmatch on accepted connection"); return false; diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h index dc4f4114..e7fb32fe 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -64,8 +64,8 @@ class async_protocol_handler_config public: typedef t_connection_context connection_context; levin_commands_handler* m_pcommands_handler; - boost::uint64_t m_max_packet_size; - boost::uint64_t m_invoke_timeout; + uint64_t m_max_packet_size; + uint64_t m_invoke_timeout; int invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id); template @@ -122,7 +122,7 @@ public: std::string m_cache_in_buffer; stream_state m_state; - boost::int32_t m_oponent_protocol_ver; + int32_t m_oponent_protocol_ver; bool m_connection_initialized; struct invoke_response_handler_base @@ -424,7 +424,7 @@ public: { if(m_cache_in_buffer.size() < sizeof(bucket_head2)) { - if(m_cache_in_buffer.size() >= sizeof(boost::uint64_t) && *((boost::uint64_t*)m_cache_in_buffer.data()) != LEVIN_SIGNATURE) + if(m_cache_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cache_in_buffer.data()) != LEVIN_SIGNATURE) { LOG_ERROR_CC(m_connection_context, "Signature mismatch, connection will be closed"); return false; diff --git a/contrib/epee/include/net/local_ip.h b/contrib/epee/include/net/local_ip.h index 028ad73e..0d458963 100644 --- a/contrib/epee/include/net/local_ip.h +++ b/contrib/epee/include/net/local_ip.h @@ -32,7 +32,7 @@ namespace epee namespace net_utils { inline - bool is_ip_local(boost::uint32_t ip) + bool is_ip_local(uint32_t ip) { /* local ip area @@ -55,7 +55,7 @@ namespace epee return false; } inline - bool is_ip_loopback(boost::uint32_t ip) + bool is_ip_loopback(uint32_t ip) { if( (ip | 0xffffff00) == 0xffffff7f) return true; diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index d2a4cfec..4f7ebfa0 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -429,7 +429,7 @@ namespace net_utils } - inline bool recv_n(std::string& buff, boost::int64_t sz) + inline bool recv_n(std::string& buff, int64_t sz) { try @@ -564,7 +564,7 @@ namespace net_utils bool m_initialized; bool m_connected; boost::asio::deadline_timer m_deadline; - volatile boost::uint32_t m_shutdowned; + volatile uint32_t m_shutdowned; }; diff --git a/contrib/epee/include/net/net_parse_helpers.h b/contrib/epee/include/net/net_parse_helpers.h index 16641a97..586dac98 100644 --- a/contrib/epee/include/net/net_parse_helpers.h +++ b/contrib/epee/include/net/net_parse_helpers.h @@ -153,7 +153,7 @@ namespace net_utils } if(result[6].matched) { - content.port = boost::lexical_cast(result[6]); + content.port = boost::lexical_cast(result[6]); } if(result[7].matched) { diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index 86797bb8..3afbbb11 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -47,23 +47,36 @@ namespace net_utils struct connection_context_base { const boost::uuids::uuid m_connection_id; - const boost::uint32_t m_remote_ip; - const boost::uint32_t m_remote_port; - const bool m_is_income; + const uint32_t m_remote_ip; + const uint32_t m_remote_port; + const bool m_is_income; + const time_t m_started; + time_t m_last_recv; + time_t m_last_send; + uint64_t m_recv_cnt; + uint64_t m_send_cnt; - connection_context_base(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income): + connection_context_base(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income, 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_ip(remote_ip), m_remote_port(remote_port), - m_is_income(is_income) - - + m_is_income(is_income), + m_last_recv(last_recv), + m_last_send(last_send), + m_recv_cnt(recv_cnt), + m_send_cnt(send_cnt), + m_started(time(NULL)) {} connection_context_base(): m_connection_id(), m_remote_ip(0), m_remote_port(0), - m_is_income(false) + m_is_income(false), + m_last_recv(0), + m_last_send(0), + m_recv_cnt(0), + m_send_cnt(0), + m_started(time(NULL)) {} connection_context_base& operator=(const connection_context_base& a) diff --git a/contrib/epee/include/net/protocol_switcher.h b/contrib/epee/include/net/protocol_switcher.h index f9a6dbe6..ca0ce6f9 100644 --- a/contrib/epee/include/net/protocol_switcher.h +++ b/contrib/epee/include/net/protocol_switcher.h @@ -95,10 +95,10 @@ namespace net_utils else { m_cached_buff.append((const char*)ptr, cb); - if(m_cached_buff.size() < sizeof(boost::uint64_t)) + if(m_cached_buff.size() < sizeof(uint64_t)) return true; - if(*((boost::uint64_t*)&m_cached_buff[0]) == LEVIN_SIGNATURE) + if(*((uint64_t*)&m_cached_buff[0]) == LEVIN_SIGNATURE) { pcurrent_handler = &m_levin_handler; return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size()); diff --git a/contrib/epee/include/profile_tools.h b/contrib/epee/include/profile_tools.h index ff925ea8..be45feaf 100644 --- a/contrib/epee/include/profile_tools.h +++ b/contrib/epee/include/profile_tools.h @@ -51,12 +51,12 @@ namespace epee #define PROFILE_FUNC_THIRD(immortal_ptr_str) #endif -#define START_WAY_POINTS() boost::uint64_t _____way_point_time = misc_utils::get_tick_count(); -#define WAY_POINT(name) {boost::uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} -#define WAY_POINT2(name, avrg_obj) {boost::uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; avrg_obj.push(delta); LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} +#define START_WAY_POINTS() uint64_t _____way_point_time = misc_utils::get_tick_count(); +#define WAY_POINT(name) {uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} +#define WAY_POINT2(name, avrg_obj) {uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; avrg_obj.push(delta); LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();} -#define TIME_MEASURE_START(var_name) boost::uint64_t var_name = misc_utils::get_tick_count(); +#define TIME_MEASURE_START(var_name) uint64_t var_name = misc_utils::get_tick_count(); #define TIME_MEASURE_FINISH(var_name) var_name = misc_utils::get_tick_count() - var_name; namespace profile_tools @@ -71,7 +71,7 @@ namespace profile_tools } size_t m_count_of_call; - boost::uint64_t m_summary_time_used; + uint64_t m_summary_time_used; const char* m_pname; }; @@ -91,7 +91,7 @@ namespace profile_tools boost::posix_time::ptime now_t(boost::posix_time::microsec_clock::local_time()); boost::posix_time::time_duration delta_microsec = now_t - m_call_time; - boost::uint64_t miliseconds_used = delta_microsec.total_microseconds(); + uint64_t miliseconds_used = delta_microsec.total_microseconds(); //::QueryPerformanceCounter((LARGE_INTEGER *)&ret_time); //m_call_time = (ret_time-m_call_time)/1000; diff --git a/contrib/epee/include/reg_exp_definer.h b/contrib/epee/include/reg_exp_definer.h index b05e1a9a..e2bed5c3 100644 --- a/contrib/epee/include/reg_exp_definer.h +++ b/contrib/epee/include/reg_exp_definer.h @@ -45,8 +45,8 @@ namespace epee const static global_regexp_critical_section gregexplock; #define STATIC_REGEXP_EXPR_1(var_name, xpr_text, reg_exp_flags) \ - static volatile boost::uint32_t regexp_initialized_1 = 0;\ - volatile boost::uint32_t local_is_initialized_1 = regexp_initialized_1;\ + static volatile uint32_t regexp_initialized_1 = 0;\ + volatile uint32_t local_is_initialized_1 = regexp_initialized_1;\ if(!local_is_initialized_1)\ gregexplock.get_lock().lock();\ static const boost::regex var_name(xpr_text , reg_exp_flags);\ @@ -57,8 +57,8 @@ namespace epee } #define STATIC_REGEXP_EXPR_2(var_name, xpr_text, reg_exp_flags) \ - static volatile boost::uint32_t regexp_initialized_2 = 0;\ - volatile boost::uint32_t local_is_initialized_2 = regexp_initialized_2;\ + static volatile uint32_t regexp_initialized_2 = 0;\ + volatile uint32_t local_is_initialized_2 = regexp_initialized_2;\ if(!local_is_initialized_2)\ gregexplock.get_lock().lock().lock();\ static const boost::regex var_name(xpr_text , reg_exp_flags);\ @@ -69,8 +69,8 @@ namespace epee } #define STATIC_REGEXP_EXPR_3(var_name, xpr_text, reg_exp_flags) \ - static volatile boost::uint32_t regexp_initialized_3 = 0;\ - volatile boost::uint32_t local_is_initialized_3 = regexp_initialized_3;\ + static volatile uint32_t regexp_initialized_3 = 0;\ + volatile uint32_t local_is_initialized_3 = regexp_initialized_3;\ if(!local_is_initialized_3)\ gregexplock.get_lock().lock().lock();\ static const boost::regex var_name(xpr_text , reg_exp_flags);\ diff --git a/contrib/epee/include/soci_helper.h b/contrib/epee/include/soci_helper.h index a154f97f..813edc1f 100644 --- a/contrib/epee/include/soci_helper.h +++ b/contrib/epee/include/soci_helper.h @@ -34,22 +34,22 @@ namespace soci { template <> - struct type_conversion + struct type_conversion { typedef long long base_type; - static void from_base(base_type a_, indicator ind, boost::uint64_t & mi) + static void from_base(base_type a_, indicator ind, uint64_t & mi) { if (ind == i_null) { mi = 0; //throw soci_error("Null value not allowed for this type"); } - mi = (boost::uint64_t)a_; + mi = (uint64_t)a_; //mi.set(i); } - static void to_base(const boost::uint64_t & mi, base_type & i, indicator & ind) + static void to_base(const uint64_t & mi, base_type & i, indicator & ind) { i = (base_type)mi; ind = i_ok; diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h index 557db3da..4e74fb7a 100644 --- a/contrib/epee/include/storages/portable_storage_from_json.h +++ b/contrib/epee/include/storages/portable_storage_from_json.h @@ -281,7 +281,7 @@ namespace epee bool insert_res = false; if(!is_v_float) { - boost::int64_t nval = boost::lexical_cast(val); //bool res = string_tools::string_to_num_fast(val, nval); + int64_t nval = boost::lexical_cast(val); //bool res = string_tools::string_to_num_fast(val, nval); insert_res = stg.insert_next_value(h_array, nval); }else diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index 53be7c3a..4cc88418 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -183,27 +183,35 @@ namespace string_tools //---------------------------------------------------------------------------- PUSH_WARNINGS DISABLE_GCC_WARNING(maybe-uninitialized) - template - inline bool get_xtype_from_string(OUT XType& val, const std::string& str_id) - { - try - { - val = boost::lexical_cast(str_id); + template + inline bool get_xtype_from_string(OUT XType& val, const std::string& str_id) + { + if (std::is_integral::value && !std::numeric_limits::is_signed && !std::is_same::value) + { + for (char c : str_id) + { + if (!std::isdigit(c)) + return false; + } + } + + try + { + val = boost::lexical_cast(str_id); return true; - } - catch(std::exception& /*e*/) - { - //const char* pmsg = e.what(); - return false; - } + } + catch(std::exception& /*e*/) + { + //const char* pmsg = e.what(); + return false; + } + catch(...) + { + return false; + } - catch(...) - { - return false; - } - - return true; - } + return true; + } POP_WARNINGS //--------------------------------------------------- template @@ -315,7 +323,7 @@ POP_WARNINGS //---------------------------------------------------------------------------- //#ifdef _WINSOCK2API_ - inline std::string get_ip_string_from_int32(boost::uint32_t ip) + inline std::string get_ip_string_from_int32(uint32_t ip) { in_addr adr; adr.s_addr = ip; @@ -326,7 +334,7 @@ POP_WARNINGS return "[failed]"; } //---------------------------------------------------------------------------- - inline bool get_ip_int32_from_string(boost::uint32_t& ip, const std::string& ip_str) + inline bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str) { ip = inet_addr(ip_str.c_str()); if(INADDR_NONE == ip) @@ -369,7 +377,7 @@ POP_WARNINGS return ss.str(); } - inline std::string num_to_string_fast(boost::int64_t val) + inline std::string num_to_string_fast(int64_t val) { /* char buff[30] = {0}; @@ -378,7 +386,7 @@ POP_WARNINGS return boost::lexical_cast(val); } //---------------------------------------------------------------------------- - inline bool string_to_num_fast(const std::string& buff, boost::int64_t& val) + inline bool string_to_num_fast(const std::string& buff, int64_t& val) { //return get_xtype_from_string(val, buff); #if (defined _MSC_VER) diff --git a/contrib/epee/include/syncobj.h b/contrib/epee/include/syncobj.h index ca7514ed..b7273da8 100644 --- a/contrib/epee/include/syncobj.h +++ b/contrib/epee/include/syncobj.h @@ -41,27 +41,29 @@ namespace epee struct simple_event { - simple_event() + simple_event() : m_rised(false) { - rised = false; } - std::mutex m_mx; - std::condition_variable m_cond_var; - bool rised; - void rise() + void raise() { std::unique_lock lock(m_mx); - rised = true; + m_rised = true; m_cond_var.notify_one(); } void wait() { std::unique_lock lock(m_mx); - while (!rised) + while (!m_rised) m_cond_var.wait(lock); + m_rised = false; } + + private: + std::mutex m_mx; + std::condition_variable m_cond_var; + bool m_rised; }; class critical_region; diff --git a/contrib/epee/tests/src/net/test_net.h b/contrib/epee/tests/src/net/test_net.h index 8d73c1f0..0b6dc1f7 100644 --- a/contrib/epee/tests/src/net/test_net.h +++ b/contrib/epee/tests/src/net/test_net.h @@ -44,7 +44,7 @@ namespace tests { std::string str1; - std::list array_of_id; + std::list array_of_id; BEGIN_NAMED_SERIALIZE_MAP() SERIALIZE_STL_ANSI_STRING(str1) @@ -64,7 +64,7 @@ namespace tests { std::string example_string_data; - boost::uint64_t example_id_data; + uint64_t example_id_data; some_subdata sub; BEGIN_NAMED_SERIALIZE_MAP() @@ -78,7 +78,7 @@ namespace tests struct response { bool m_success; - boost::uint64_t example_id_data; + uint64_t example_id_data; std::list subs; BEGIN_NAMED_SERIALIZE_MAP() @@ -96,7 +96,7 @@ namespace tests struct request { std::string example_string_data2; - boost::uint64_t example_id_data; + uint64_t example_id_data; BEGIN_NAMED_SERIALIZE_MAP() SERIALIZE_POD(example_id_data) @@ -106,8 +106,8 @@ namespace tests struct response { - bool m_success; - boost::uint64_t example_id_data; + bool m_success; + uint64_t example_id_data; BEGIN_NAMED_SERIALIZE_MAP() SERIALIZE_POD(example_id_data) @@ -127,12 +127,12 @@ namespace tests m_net_server.set_threads_prefix(pref); } template - bool connect_async(const std::string adr, const std::string& port, boost::uint32_t conn_timeot, calback_t 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, calback_t cb, const std::string& bind_ip = "0.0.0.0") { return m_net_server.connect_async(adr, port, conn_timeot, cb, bind_ip); } - bool connect(const std::string adr, const std::string& port, boost::uint32_t conn_timeot, net_utils::connection_context_base& cn, const std::string& bind_ip = "0.0.0.0") + bool connect(const std::string adr, const std::string& port, uint32_t conn_timeot, net_utils::connection_context_base& cn, const std::string& bind_ip = "0.0.0.0") { return m_net_server.connect(adr, port, conn_timeot, cn, bind_ip); } diff --git a/src/common/base58.cpp b/src/common/base58.cpp index 30042eeb..454c0db6 100644 --- a/src/common/base58.cpp +++ b/src/common/base58.cpp @@ -227,6 +227,7 @@ namespace tools std::string addr_data; bool r = decode(addr, addr_data); if (!r) return false; + if (addr_data.size() <= addr_checksum_size) return false; std::string checksum(addr_checksum_size, '\0'); checksum = addr_data.substr(addr_data.size() - addr_checksum_size); diff --git a/src/common/int-util.h b/src/common/int-util.h index ad0ef60e..db9e9bea 100644 --- a/src/common/int-util.h +++ b/src/common/int-util.h @@ -34,15 +34,15 @@ static inline uint64_t rol64(uint64_t x, int r) { #endif -inline uint64_t hi_dword(uint64_t val) { +static inline uint64_t hi_dword(uint64_t val) { return val >> 32; } -inline uint64_t lo_dword(uint64_t val) { +static inline uint64_t lo_dword(uint64_t val) { return val & 0xFFFFFFFF; } -inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { +static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) { // multiplier = ab = a * 2^32 + b // multiplicand = cd = c * 2^32 + d // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d @@ -68,14 +68,14 @@ inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* pro return product_lo; } -inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) { +static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) { dividend |= ((uint64_t)*remainder) << 32; *remainder = dividend % divisor; return dividend / divisor; } // Long division with 2^32 base -inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) { +static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) { uint64_t dividend_dwords[4]; uint32_t remainder = 0; diff --git a/src/common/util.cpp b/src/common/util.cpp index b24016cc..c9c47085 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -21,6 +21,7 @@ using namespace epee; namespace tools { + std::function signal_handler::m_handler; #ifdef WIN32 std::string get_windows_version_display_string() diff --git a/src/common/util.h b/src/common/util.h index a29a30ff..af92adf9 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -26,4 +27,60 @@ namespace tools s.append(reinterpret_cast(&pot.time), sizeof(pot.time)); return crypto::cn_fast_hash(s.data(), s.size()); } + + + class signal_handler + { + public: + template + static bool install(T t) + { +#if defined(WIN32) + bool r = TRUE == ::SetConsoleCtrlHandler(&win_handler, TRUE); + if (r) + { + m_handler = t; + } + return r; +#else + signal(SIGINT, posix_handler); + signal(SIGTERM, posix_handler); + m_handler = t; + return true; +#endif + } + + private: +#if defined(WIN32) + static BOOL win_handler(DWORD type) + { + if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type) + { + handle_signal(); + return TRUE; + } + else + { + LOG_PRINT_RED_L0("Got control signal " << type << ". Exiting without saving..."); + return FALSE; + } + return TRUE; + } +#else + static void posix_handler(int /*type*/) + { + handle_signal(); + } +#endif + + static void handle_signal() + { + static std::mutex m_mutex; + std::unique_lock lock(m_mutex); + m_handler(); + } + + private: + static std::function m_handler; + }; } diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp index 4b83b4f4..6743b4ae 100644 --- a/src/connectivity_tool/conn_tool.cpp +++ b/src/connectivity_tool/conn_tool.cpp @@ -27,12 +27,12 @@ using namespace nodetool; namespace { - const command_line::arg_descriptor arg_ip = {"ip", "set ip"}; + const command_line::arg_descriptor arg_ip = {"ip", "set ip"}; const command_line::arg_descriptor arg_port = {"port", "set port"}; const command_line::arg_descriptor arg_rpc_port = {"rpc_port", "set rpc port"}; - const command_line::arg_descriptor arg_timeout = {"timeout", "set timeout"}; + const command_line::arg_descriptor arg_timeout = {"timeout", "set timeout"}; const command_line::arg_descriptor arg_priv_key = {"private_key", "private key to subscribe debug command", "", true}; - const command_line::arg_descriptor arg_peer_id = {"peer_id", "peer_id if known(if not - will be requested)", 0}; + const command_line::arg_descriptor arg_peer_id = {"peer_id", "peer_id if known(if not - will be requested)", 0}; const command_line::arg_descriptor arg_generate_keys = {"generate_keys_pair", "generate private and public keys pair"}; const command_line::arg_descriptor arg_request_stat_info = {"request_stat_info", "request statistics information"}; const command_line::arg_descriptor arg_request_net_state = {"request_net_state", "request network state information (peer list, connections count)"}; diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp index 1ec18665..3eb7f86c 100644 --- a/src/cryptonote_core/blockchain_storage.cpp +++ b/src/cryptonote_core/blockchain_storage.cpp @@ -104,6 +104,9 @@ bool blockchain_storage::init(const std::string& config_folder) //------------------------------------------------------------------ bool blockchain_storage::store_blockchain() { + m_is_blockchain_storing = true; + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){m_is_blockchain_storing=false;}); + LOG_PRINT_L0("Storing blockchain..."); if (!tools::create_directories_if_necessary(m_config_folder)) { @@ -1029,7 +1032,7 @@ void blockchain_storage::print_blockchain(uint64_t start_index, uint64_t end_ind for(size_t i = start_index; i != m_blocks.size() && i != end_index; i++) { - ss << "height " << i << ", timastamp " << m_blocks[i].bl.timestamp << ", cumul_dif " << m_blocks[i].cumulative_difficulty << ", cumul_size " << m_blocks[i].block_cumulative_size + ss << "height " << i << ", timestamp " << m_blocks[i].bl.timestamp << ", cumul_dif " << m_blocks[i].cumulative_difficulty << ", cumul_size " << m_blocks[i].block_cumulative_size << "\nid\t\t" << get_block_hash(m_blocks[i].bl) << "\ndifficulty\t\t" << block_difficulty(i) << ", nonce " << m_blocks[i].bl.nonce << ", tx_count " << m_blocks[i].bl.tx_hashes.size() << ENDL; } diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h index 4ff5e83f..c263f750 100644 --- a/src/cryptonote_core/blockchain_storage.h +++ b/src/cryptonote_core/blockchain_storage.h @@ -110,6 +110,7 @@ namespace cryptonote bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL); bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id); uint64_t get_current_comulative_blocksize_limit(); + bool is_storing_blockchain(){return m_is_blockchain_storing;} template bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) @@ -188,6 +189,7 @@ namespace cryptonote std::string m_config_folder; checkpoints m_checkpoints; std::atomic m_is_in_checkpoint_zone; + std::atomic m_is_blockchain_storing; diff --git a/src/cryptonote_core/connection_context.h b/src/cryptonote_core/connection_context.h index bf13449b..53cac992 100644 --- a/src/cryptonote_core/connection_context.h +++ b/src/cryptonote_core/connection_context.h @@ -6,32 +6,10 @@ #include #include #include "net/net_utils_base.h" - +#include "copyable_atomic.h" namespace cryptonote { - class my_atomic: public std::atomic - { - public: - my_atomic() - {}; - my_atomic(const my_atomic& a):std::atomic(a.load()) - {} - my_atomic& operator= (const my_atomic& a) - { - store(a.load()); - return *this; - } - uint32_t operator++() - { - return std::atomic::operator++(); - } - uint32_t operator++(int fake) - { - return std::atomic::operator++(fake); - } - }; - struct cryptonote_connection_context: public epee::net_utils::connection_context_base { @@ -40,6 +18,7 @@ namespace cryptonote { state_befor_handshake = 0, //default state state_synchronizing, + state_idle, state_normal }; @@ -48,7 +27,25 @@ namespace cryptonote std::unordered_set m_requested_objects; uint64_t m_remote_blockchain_height; uint64_t m_last_response_height; - my_atomic m_callback_request_count; //in debug purpose: problem with double callback rise + epee::copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise //size_t m_score; TODO: add score calculations }; + + inline std::string get_protocol_state_string(cryptonote_connection_context::state s) + { + switch (s) + { + case cryptonote_connection_context::state_befor_handshake: + return "state_befor_handshake"; + case cryptonote_connection_context::state_synchronizing: + return "state_synchronizing"; + case cryptonote_connection_context::state_idle: + return "state_idle"; + case cryptonote_connection_context::state_normal: + return "state_normal"; + default: + return "unknown"; + } + } + } diff --git a/src/cryptonote_core/cryptonote_basic_impl.cpp b/src/cryptonote_core/cryptonote_basic_impl.cpp index b320a346..194b8905 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.cpp +++ b/src/cryptonote_core/cryptonote_basic_impl.cpp @@ -109,25 +109,25 @@ namespace cryptonote { uint64_t prefix; if (!tools::base58::decode_addr(str, prefix, data)) { - LOG_PRINT_L0("Invalid address format"); + LOG_PRINT_L1("Invalid address format"); return false; } if (CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX != prefix) { - LOG_PRINT_L0("Wrong address prefix: " << prefix << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX); + LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX); return false; } if (!::serialization::parse_binary(data, adr)) { - LOG_PRINT_L0("Account public address keys can't be parsed"); + LOG_PRINT_L1("Account public address keys can't be parsed"); return false; } if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key)) { - LOG_PRINT_L0("Failed to validate address keys"); + LOG_PRINT_L1("Failed to validate address keys"); return false; } } @@ -140,7 +140,7 @@ namespace cryptonote { if(buff.size()!=sizeof(public_address_outer_blob)) { - LOG_PRINT_L0("Wrong public address size: " << buff.size() << ", expected size: " << sizeof(public_address_outer_blob)); + LOG_PRINT_L1("Wrong public address size: " << buff.size() << ", expected size: " << sizeof(public_address_outer_blob)); return false; } @@ -149,13 +149,13 @@ namespace cryptonote { if(blob.m_ver > CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER) { - LOG_PRINT_L0("Unknown version of public address: " << blob.m_ver << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER); + LOG_PRINT_L1("Unknown version of public address: " << blob.m_ver << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER); return false; } if(blob.check_sum != get_account_address_checksum(blob)) { - LOG_PRINT_L0("Wrong public address checksum"); + LOG_PRINT_L1("Wrong public address checksum"); return false; } diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index d5ab8d65..a09f25d3 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -230,9 +230,9 @@ namespace cryptonote return false; } - boost::uint64_t amount_in = 0; + uint64_t amount_in = 0; get_inputs_money_amount(tx, amount_in); - boost::uint64_t amount_out = get_outs_money_amount(tx); + uint64_t amount_out = get_outs_money_amount(tx); if(amount_in <= amount_out) { diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 1c50832b..1bc180f8 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -139,7 +139,6 @@ namespace cryptonote { if (0 == amount) { - chunk_handler(0); return; } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index f599cf40..178ec2eb 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -22,7 +22,7 @@ namespace cryptonote template class t_cryptonote_protocol_handler: public i_cryptonote_protocol - { + { public: typedef cryptonote_connection_context connection_context; typedef core_stat_info stat_info; @@ -51,8 +51,8 @@ namespace cryptonote bool get_stat_info(core_stat_info& stat_inf); bool on_callback(cryptonote_connection_context& context); t_core& get_core(){return m_core;} - - + bool is_synchronized(){return m_synchronized;} + void log_connections(); private: //----------------- commands handlers ---------------------------------------------- int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context); @@ -60,7 +60,6 @@ namespace cryptonote int handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context); int handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context); int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context); -// int handle_request_chain_entry(int command, NOTIFY_REQUEST_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context); int handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context); @@ -77,9 +76,7 @@ namespace cryptonote nodetool::p2p_endpoint_stub m_p2p_stub; nodetool::i_p2p_endpoint* m_p2p; std::atomic m_syncronized_connections_count; - //std::atomic m_syncronizing_connections_count; - std::atomic m_welcome_showed; - + std::atomic m_synchronized; template bool post_notify(typename t_parametr::request& arg, cryptonote_connection_context& context) diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 9c966807..287461ca 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -13,7 +13,7 @@ namespace cryptonote t_cryptonote_protocol_handler::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint* p_net_layout):m_core(rcore), m_p2p(p_net_layout), m_syncronized_connections_count(0), - m_welcome_showed(false) + m_synchronized(false) { if(!m_p2p) @@ -68,6 +68,30 @@ namespace cryptonote } //------------------------------------------------------------------------------------------------------------------------ template + void t_cryptonote_protocol_handler::log_connections() + { + std::stringstream ss; + + ss << std::setw(25) << std::left << "Remote Host" + << std::setw(20) << "Peer id" + << std::setw(25) << "Recv/Sent (inactive,sec)" + << std::setw(25) << "State" + << std::setw(20) << "Livetime(seconds)" << ENDL; + + m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id) + { + ss << std::setw(25) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") + + string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port) + << std::setw(20) << std::hex << peer_id + << std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")" + << std::setw(25) << get_protocol_state_string(cntxt.m_state) + << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started) << ENDL; + return true; + }); + LOG_PRINT_L0("Connections: " << ENDL << ss.str()); + } + //------------------------------------------------------------------------------------------------------------------------ + template bool t_cryptonote_protocol_handler::process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital) { if(context.m_state == cryptonote_connection_context::state_befor_handshake && !is_inital) @@ -84,7 +108,7 @@ namespace cryptonote return true; } - LOG_PRINT_CCONTEXT_BLUE("Sync data returned unknown top block " << "["<< m_core.get_current_blockchain_height() << "->" << hshd.current_height << "] " << hshd.top_id << ", set SYNCHRONIZATION mode", LOG_LEVEL_0); + LOG_PRINT_CCONTEXT_BLUE("Sync data returned unknown top block " << "["<< m_core.get_current_blockchain_height() << "->" << hshd.current_height << "] " << hshd.top_id << ", set SYNCHRONIZATION mode", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1)); context.m_state = cryptonote_connection_context::state_synchronizing; context.m_remote_blockchain_height = hshd.current_height; //let the socket to send response to handshake, but request callback, to let send request data after response @@ -93,14 +117,6 @@ namespace cryptonote m_p2p->request_callback(context); return true; } - //------------------------------------------------------------------------------------------------------------------------ - /* template - bool t_cryptonote_protocol_handler::process_handshake_data(const blobdata& data, cryptonote_connection_context& context) - { - CORE_SYNC_DATA hsd = boost::value_initialized(); - StorageNamed::load_struct_from_storage_buff(hsd, data); - return process_handshake_data(hsd, context); - }*/ //------------------------------------------------------------------------------------------------------------------------ template bool t_cryptonote_protocol_handler::get_payload_sync_data(CORE_SYNC_DATA& hshd) @@ -228,8 +244,10 @@ namespace cryptonote context.m_remote_blockchain_height = arg.current_blockchain_height; + size_t count = 0; BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks) { + ++count; block b; if(!parse_and_validate_block_from_blob(block_entry.block, b)) { @@ -237,6 +255,18 @@ namespace cryptonote << string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection"); m_p2p->drop_connection(context); return 1; + } + //to avoid concurrency in core between connections, suspend connections which delivered block later then first one + if(count == 2) + { + if(m_core.have_block(get_block_hash(b))) + { + context.m_state = cryptonote_connection_context::state_idle; + context.m_needed_objects.clear(); + context.m_requested_objects.clear(); + LOG_PRINT_CCONTEXT_L1("Connection set to idle state."); + return 1; + } } auto req_it = context.m_requested_objects.find(get_block_hash(b)); @@ -380,10 +410,7 @@ namespace cryptonote context.m_state = cryptonote_connection_context::state_normal; LOG_PRINT_CCONTEXT_GREEN(" SYNCHRONIZED OK", LOG_LEVEL_0); - if( true/*get_synchronizing_connections_count() == 0 && !m_welcome_showed*/) - { - on_connection_synchronized(); - } + on_connection_synchronized(); } return true; } @@ -392,7 +419,7 @@ namespace cryptonote bool t_cryptonote_protocol_handler::on_connection_synchronized() { bool val_expected = false; - if(m_welcome_showed.compare_exchange_strong(val_expected, true)) + if(m_synchronized.compare_exchange_strong(val_expected, true)) { LOG_PRINT_L0(ENDL << "**********************************************************************" << ENDL << "You are now synchronized with the network. You may now start simplewallet." << ENDL @@ -411,7 +438,7 @@ namespace cryptonote size_t t_cryptonote_protocol_handler::get_synchronizing_connections_count() { size_t count = 0; - m_p2p->for_each_connection([&](cryptonote_connection_context& context)->bool{ + m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id)->bool{ if(context.m_state == cryptonote_connection_context::state_synchronizing) ++count; return true; diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index d1ac3714..528c024b 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -38,6 +38,7 @@ namespace const command_line::arg_descriptor arg_os_version = {"os-version", ""}; const command_line::arg_descriptor arg_log_file = {"log-file", "", ""}; const command_line::arg_descriptor arg_log_level = {"log-level", "", LOG_LEVEL_0}; + const command_line::arg_descriptor arg_console = {"no-console", "Disable daemon console commands"}; } bool command_line_preprocessor(const boost::program_options::variables_map& vm); @@ -67,6 +68,8 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_cmd_sett, arg_log_file); command_line::add_arg(desc_cmd_sett, arg_log_level); + command_line::add_arg(desc_cmd_sett, arg_console); + cryptonote::core::init_options(desc_cmd_sett); cryptonote::core_rpc_server::init_options(desc_cmd_sett); @@ -118,6 +121,7 @@ int main(int argc, char* argv[]) log_dir = log_file_path.has_parent_path() ? log_file_path.parent_path().string() : log_space::log_singletone::get_default_log_folder(); log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str()); + LOG_PRINT_L0(CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG); if (command_line_preprocessor(vm)) { @@ -162,15 +166,23 @@ int main(int argc, char* argv[]) res = ccore.init(vm); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); LOG_PRINT_L0("Core initialized OK"); - + // start components - dch.start_handling(); + if(!command_line::has_arg(vm, arg_console)) + { + dch.start_handling(); + } LOG_PRINT_L0("Starting core rpc server..."); res = rpc_server.run(2, false); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server."); LOG_PRINT_L0("Core rpc server started ok"); + tools::signal_handler::install([&dch, &p2psrv] { + dch.stop_handling(); + p2psrv.send_stop_signal(); + }); + LOG_PRINT_L0("Starting p2p net loop..."); p2psrv.run(); LOG_PRINT_L0("p2p net loop stopped"); @@ -205,7 +217,7 @@ bool command_line_preprocessor(const boost::program_options::variables_map& vm) bool exit = false; if (command_line::get_arg(vm, command_line::arg_version)) { - std::cout << CRYPTONOTE_NAME << PROJECT_VERSION_LONG << ENDL; + std::cout << CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL; exit = true; } if (command_line::get_arg(vm, arg_os_version)) diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index 2edd5d41..7695508c 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -38,10 +38,15 @@ public: bool start_handling() { - m_cmd_binder.start_handling(&m_srv, ""); + m_cmd_binder.start_handling(&m_srv, "", ""); return true; } + void stop_handling() + { + m_cmd_binder.stop_handling(); + } + private: epee::srv_console_handlers_binder > > m_cmd_binder; @@ -77,7 +82,13 @@ private: //-------------------------------------------------------------------------------- bool show_hr(const std::vector& args) { - m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true); + if(!m_srv.get_payload_object().get_core().get_miner().is_mining()) + { + std::cout << "Mining is not started. You need start mining before you can see hash rate." << ENDL; + } else + { + m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true); + } return true; } //-------------------------------------------------------------------------------- @@ -100,7 +111,7 @@ private: //-------------------------------------------------------------------------------- bool print_cn(const std::vector& args) { - m_srv.log_connections(); + m_srv.get_payload_object().log_connections(); return true; } //-------------------------------------------------------------------------------- @@ -263,7 +274,7 @@ private: { if(!args.size()) { - std::cout << "target account address for mining is not set" << std::endl; + std::cout << "Please, specify wallet address to mine for: start_mining [threads=1]" << std::endl; return true; } @@ -273,10 +284,11 @@ private: std::cout << "target account address has wrong format" << std::endl; return true; } - size_t threads_count = 1; + size_t threads_count = 1; if(args.size() > 1) { - string_tools::get_xtype_from_string(threads_count, args[1]); + bool ok = string_tools::get_xtype_from_string(threads_count, args[1]); + threads_count = (ok && 0 < threads_count) ? threads_count : 1; } m_srv.get_payload_object().get_core().get_miner().start(adr, threads_count); diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 32249a6d..794b9742 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -121,7 +121,7 @@ namespace nodetool virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context); virtual bool drop_connection(const epee::net_utils::connection_context_base& context); virtual void request_callback(const epee::net_utils::connection_context_base& context); - virtual void for_each_connection(std::function f); + virtual void for_each_connection(std::function f); //----------------------------------------------------------------------------------------------- bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr); bool handle_command_line(const boost::program_options::variables_map& vm); diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index a5e534f8..2b46470d 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -76,10 +76,10 @@ namespace nodetool } //----------------------------------------------------------------------------------- template - void node_server::for_each_connection(std::function f) + void node_server::for_each_connection(std::function f) { m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){ - return f(cntx); + return f(cntx, cntx.peer_id); }); } //----------------------------------------------------------------------------------- @@ -143,20 +143,59 @@ namespace nodetool m_hide_my_port = true; return true; } //----------------------------------------------------------------------------------- -#define ADD_HARDCODED_SEED_NODE(addr_str) { nodetool::net_address na = AUTO_VAL_INIT(na);bool r = parse_peer_from_string(na, addr_str); \ - CHECK_AND_ASSERT_MES(r, false, "Failed to parse seed address from string: " << addr_str); m_seed_nodes.push_back(na); } + namespace + { + template + bool append_net_address(T& nodes, const std::string& addr) + { + using namespace boost::asio; + size_t pos = addr.find_last_of(':'); + CHECK_AND_ASSERT_MES(std::string::npos != pos && addr.length() - 1 != pos && 0 != pos, false, "Failed to parse seed address from string: '" << addr << '\''); + std::string host = addr.substr(0, pos); + std::string port = addr.substr(pos + 1); + io_service io_srv; + ip::tcp::resolver resolver(io_srv); + ip::tcp::resolver::query query(host, port); + boost::system::error_code ec; + ip::tcp::resolver::iterator i = resolver.resolve(query, ec); + CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to resolve host name '" << host << "': " << ec.message() << ':' << ec.value()); + + ip::tcp::resolver::iterator iend; + for (; i != iend; ++i) + { + ip::tcp::endpoint endpoint = *i; + if (endpoint.address().is_v4()) + { + nodetool::net_address na; + na.ip = boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()); + na.port = endpoint.port(); + nodes.push_back(na); + LOG_PRINT_L4("Added seed node: " << endpoint.address().to_v4().to_string(ec) << ':' << na.port); + } + else + { + LOG_PRINT_L2("IPv6 doesn't supported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec)); + } + } + + return true; + } + } + + #define ADD_HARDCODED_SEED_NODE(addr) append_net_address(m_seed_nodes, addr); + //----------------------------------------------------------------------------------- template bool node_server::init(const boost::program_options::variables_map& vm) { - + ADD_HARDCODED_SEED_NODE("seed.bytecoin.org:8080"); ADD_HARDCODED_SEED_NODE("85.25.201.95:8080"); ADD_HARDCODED_SEED_NODE("85.25.196.145:8080"); ADD_HARDCODED_SEED_NODE("85.25.196.146:8080"); ADD_HARDCODED_SEED_NODE("85.25.196.144:8080"); ADD_HARDCODED_SEED_NODE("5.199.168.138:8080"); - ADD_HARDCODED_SEED_NODE("62.75.236.152:8080"); + ADD_HARDCODED_SEED_NODE("62.75.236.152:8080"); ADD_HARDCODED_SEED_NODE("85.25.194.245:8080"); ADD_HARDCODED_SEED_NODE("95.211.224.160:8080"); ADD_HARDCODED_SEED_NODE("144.76.200.44:8080"); @@ -290,7 +329,7 @@ namespace nodetool bool r = net_utils::async_invoke_remote_command2(context_.m_connection_id, COMMAND_HANDSHAKE::ID, arg, m_net_server.get_config_object(), [this, &pi, &ev, &hsh_result, &just_take_peerlist](int code, const typename COMMAND_HANDSHAKE::response& rsp, p2p_connection_context& context) { - misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){ev.rise();}); + misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){ev.raise();}); if(code < 0) { @@ -542,7 +581,7 @@ namespace nodetool LOG_PRINT_RED_L0("Failed to connect to any of seed peers, continuing without seeds"); break; } - if(++current_index > m_seed_nodes.size()) + if(++current_index >= m_seed_nodes.size()) current_index = 0; } } @@ -939,7 +978,7 @@ namespace nodetool if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port) { peerid_type peer_id_l = arg.node_data.peer_id; - boost::uint32_t port_l = arg.node_data.my_port; + uint32_t port_l = arg.node_data.my_port; //try ping to be sure that we can add this peer to peer_list try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]() { diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index db8b6309..17ae20cb 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -6,7 +6,7 @@ #include #include "net/net_utils_base.h" - +#include "p2p_protocol_defs.h" namespace nodetool { @@ -23,7 +23,7 @@ namespace nodetool virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0; virtual void request_callback(const epee::net_utils::connection_context_base& context)=0; virtual uint64_t get_connections_count()=0; - virtual void for_each_connection(std::function f)=0; + virtual void for_each_connection(std::function f)=0; }; template @@ -49,7 +49,7 @@ namespace nodetool { } - virtual void for_each_connection(std::function f) + virtual void for_each_connection(std::function f) { } diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index 65dfd011..ea541fcb 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -49,7 +49,7 @@ namespace nodetool bool get_gray_peer_by_index(peerlist_entry& p, size_t i); bool append_with_peer_white(const peerlist_entry& pr); bool append_with_peer_gray(const peerlist_entry& pr); - bool set_peer_just_seen(peerid_type peer, boost::uint32_t ip, boost::uint32_t port); + bool set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port); bool set_peer_just_seen(peerid_type peer, const net_address& addr); bool set_peer_unreachable(const peerlist_entry& pr); bool is_ip_allowed(uint32_t ip); @@ -284,7 +284,7 @@ namespace nodetool } //-------------------------------------------------------------------------------------------------- inline - bool peerlist_manager::set_peer_just_seen(peerid_type peer, boost::uint32_t ip, boost::uint32_t port) + bool peerlist_manager::set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port) { net_address addr; addr.ip = ip; @@ -343,10 +343,6 @@ namespace nodetool if(!is_ip_allowed(ple.adr.ip)) return true; - if(ple.adr.port != 8080) - assert(false); - - CRITICAL_REGION_LOCAL(m_peerlist_lock); //find in white list auto by_addr_it_wt = m_peers_white.get().find(ple.adr); diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index 7ae6d08f..9994dca4 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -19,8 +19,8 @@ namespace nodetool struct net_address { - boost::uint32_t ip; - boost::uint32_t port; + uint32_t ip; + uint32_t port; }; struct peerlist_entry @@ -74,13 +74,13 @@ namespace nodetool KV_SERIALIZE(config_id) END_KV_SERIALIZE_MAP() - boost::uint32_t connections_count; - boost::uint32_t connection_timeout; - boost::uint32_t ping_connection_timeout; - boost::uint32_t handshake_interval; - boost::uint32_t packet_max_size; - boost::uint32_t config_id; - boost::uint32_t send_peerlist_sz; + uint32_t connections_count; + uint32_t connection_timeout; + uint32_t ping_connection_timeout; + uint32_t handshake_interval; + uint32_t packet_max_size; + uint32_t config_id; + uint32_t send_peerlist_sz; }; struct basic_node_data diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 984d9d8c..68df17b9 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -45,17 +45,35 @@ namespace cryptonote m_net_server.set_threads_prefix("RPC"); bool r = handle_command_line(vm); CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server"); - return epee::http_server_impl_base::init(m_port, m_bind_ip); + return epee::http_server_impl_base::init(m_port, m_bind_ip); } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res) + bool core_rpc_server::check_core_ready() { + if(!m_p2p.get_payload_object().is_synchronized()) + { + return false; + } + if(m_p2p.get_payload_object().get_core().get_blockchain_storage().is_storing_blockchain()) + { + return false; + } + return true; + } +#define CHECK_CORE_READY() if(!check_core_ready()){res.status = CORE_RPC_STATUS_BUSY;return true;} + + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); res.height = m_core.get_current_blockchain_height(); + res.status = CORE_RPC_STATUS_OK; return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res) + bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx) { + CHECK_CORE_READY(); res.height = m_core.get_current_blockchain_height(); res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block(); res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase @@ -66,21 +84,13 @@ namespace cryptonote res.incoming_connections_count = total_conn - res.outgoing_connections_count; res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count(); res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count(); + res.status = CORE_RPC_STATUS_OK; return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_known_block_ids(const COMMAND_RPC_GET_KNOWN_BLOCK_IDS::request& req, COMMAND_RPC_GET_KNOWN_BLOCK_IDS::response& res) - { - std::list main, alt, invalid; - m_core.get_all_known_block_ids(main, alt, invalid); - BOOST_FOREACH(crypto::hash &h, main) - res.main.push_back(string_tools::pod_to_hex(h)); - - return true; - } - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res) + bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, connection_context& cntx) { + CHECK_CORE_READY(); std::list > > bs; if(!m_core.find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT)) { @@ -102,8 +112,9 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) + bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx) { + CHECK_CORE_READY(); res.status = "Failed"; if(!m_core.get_random_outs_for_amounts(req, res)) { @@ -115,23 +126,24 @@ namespace cryptonote typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount; typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; std::for_each(res.outs.begin(), res.outs.end(), [&](outs_for_amount& ofa) - { - ss << "[" << ofa.amount << "]:"; - CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << ofa.amount); - std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe) - { - ss << oe.global_amount_index << " "; - }); - ss << ENDL; - }); + { + ss << "[" << ofa.amount << "]:"; + CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << ofa.amount); + std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe) + { + ss << oe.global_amount_index << " "; + }); + ss << ENDL; + }); std::string s = ss.str(); LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s); res.status = CORE_RPC_STATUS_OK; return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res) + bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx) { + CHECK_CORE_READY(); bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes); if(!r) { @@ -143,8 +155,9 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res) + bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, connection_context& cntx) { + CHECK_CORE_READY(); std::vector vh; BOOST_FOREACH(const auto& tx_hex_str, req.txs_hashes) { @@ -184,12 +197,7 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - /*bool core_rpc_server::on_get_outputs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res) - { - return true; - }*/ - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res) + bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx) { std::string tx_blob; if(!string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob)) @@ -231,8 +239,9 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res) + bool core_rpc_server::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx) { + CHECK_CORE_READY(); account_public_address adr; if(!get_account_address_from_str(adr, req.miner_address)) { @@ -249,9 +258,9 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res) + bool core_rpc_server::on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx) { - + CHECK_CORE_READY(); if(!m_core.get_miner().stop()) { res.status = "Failed, mining not stopped"; @@ -261,14 +270,22 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res) + bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx) { - res = m_core.get_current_blockchain_height(); + CHECK_CORE_READY(); + res.count = m_core.get_current_blockchain_height(); + res.status = CORE_RPC_STATUS_OK; return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp) + bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy"; + return false; + } if(req.size() != 1) { error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; @@ -300,8 +317,15 @@ namespace cryptonote return 0; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp) + bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy"; + return false; + } + if(req.reserve_size > 255) { error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE; @@ -359,8 +383,9 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp) + bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) { + CHECK_CORE_READY(); if(req.size()!=1) { error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 4425a1ce..fb3e9221 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -21,17 +21,18 @@ namespace cryptonote class core_rpc_server: public epee::http_server_impl_base { public: + typedef epee::net_utils::connection_context_base connection_context; + core_rpc_server(core& cr, nodetool::node_server >& p2p); static void init_options(boost::program_options::options_description& desc); bool init(const boost::program_options::variables_map& vm); private: - CHAIN_HTTP_TO_MAP2(); //forward http requests to uri map + CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map BEGIN_URI_MAP2() MAP_URI_AUTO_JON2("/getheight", on_get_height, COMMAND_RPC_GET_HEIGHT) - MAP_URI_AUTO_JON2("/getknownblockids", on_get_known_block_ids, COMMAND_RPC_GET_KNOWN_BLOCK_IDS) MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST) MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES) MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) @@ -48,24 +49,24 @@ namespace cryptonote END_JSON_RPC_MAP() END_URI_MAP2() - bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res); - bool on_get_known_block_ids(const COMMAND_RPC_GET_KNOWN_BLOCK_IDS::request& req, COMMAND_RPC_GET_KNOWN_BLOCK_IDS::response& res); - bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res); - bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res); - bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res); - bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res); - bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res); - bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res); - bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res); - bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res); + bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, connection_context& cntx); + bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, connection_context& cntx); + bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, connection_context& cntx); + bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx); + bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx); + bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx); + bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx); + bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx); + bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx); //json_rpc - bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res); - bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp); - bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp); - bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp); + bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx); + bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); //----------------------- bool handle_command_line(const boost::program_options::variables_map& vm); + bool check_core_ready(); core& m_core; nodetool::node_server >& m_p2p; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index fbb7171a..5e821077 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -11,6 +11,7 @@ namespace cryptonote { //----------------------------------------------- #define CORE_RPC_STATUS_OK "OK" +#define CORE_RPC_STATUS_BUSY "BUSY" struct COMMAND_RPC_GET_HEIGHT { @@ -23,35 +24,15 @@ namespace cryptonote struct response { uint64_t height; + std::string status; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(height) + KV_SERIALIZE(status) END_KV_SERIALIZE_MAP() }; }; - struct COMMAND_RPC_GET_KNOWN_BLOCK_IDS - { - struct request - { - BEGIN_KV_SERIALIZE_MAP() - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::list main; - std::list alt; - std::list invalid; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(main) - KV_SERIALIZE(alt) - KV_SERIALIZE(invalid) - END_KV_SERIALIZE_MAP() - }; - }; - struct COMMAND_RPC_GET_BLOCKS_FAST { @@ -153,6 +134,7 @@ namespace cryptonote { uint64_t amount; std::list outs; + BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs) @@ -283,7 +265,17 @@ namespace cryptonote { typedef std::list request; - typedef uint64_t response; + struct response + { + uint64_t count; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(count) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; struct COMMAND_RPC_GETBLOCKHASH @@ -313,12 +305,14 @@ namespace cryptonote uint64_t height; uint64_t reserved_offset; blobdata blocktemplate_blob; + std::string status; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(difficulty) KV_SERIALIZE(height) KV_SERIALIZE(reserved_offset) KV_SERIALIZE(blocktemplate_blob) + KV_SERIALIZE(status) END_KV_SERIALIZE_MAP() }; }; diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h index 5e3296d0..10785f8a 100644 --- a/src/rpc/core_rpc_server_error_codes.h +++ b/src/rpc/core_rpc_server_error_codes.h @@ -12,3 +12,8 @@ #define CORE_RPC_ERROR_CODE_INTERNAL_ERROR -5 #define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB -6 #define CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED -7 +#define CORE_RPC_ERROR_CODE_CORE_BUSY -9 + + + + diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index bda47019..2ba03132 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -8,6 +8,7 @@ #include #include "include_base_utils.h" #include "common/command_line.h" +#include "common/util.h" #include "p2p/net_node.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "simplewallet.h" @@ -40,22 +41,26 @@ namespace const command_line::arg_descriptor arg_log_level = {"set_log", "", 0, true}; const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; + + void print_success_msg(const std::string& msg, bool color = false) + { + LOG_PRINT_L4(msg); + if (color) epee::log_space::set_console_color(epee::log_space::console_color_green, false); + std::cout << msg; + if (color) epee::log_space::reset_console_color(); + std::cout << std::endl; + } + + void print_fail_msg(const std::string& msg) + { + LOG_PRINT_L1("Error:" << msg); + epee::log_space::set_console_color(epee::log_space::console_color_red, true); + std::cout << "Error: " << msg; + epee::log_space::reset_console_color(); + std::cout << std::endl; + } } -/*const char *commands_help = - "Commands:\n" - " help Show this help\n" - " address Show current account public address\n" - " exit\n" - " refresh\n" - " start_mining Start mining\n" - " set_log\n" - " show_balance Show current account balance\n" - " show_bc_height Show blockchain height\n" - " show_incoming_transfers Show coins\n" - " transfer ( )... Transfer to \n";*/ - - std::string simple_wallet::get_commands_str() { @@ -68,7 +73,7 @@ std::string simple_wallet::get_commands_str() return ss.str(); } -bool simple_wallet::help(const std::vector &args) +bool simple_wallet::help(const std::vector &args/* = std::vector()*/) { std::cout << get_commands_str(); return true; @@ -76,15 +81,14 @@ bool simple_wallet::help(const std::vector &args) simple_wallet::simple_wallet() : m_daemon_port(0) - , m_tried_to_connect(false) { - m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "Start mining in daemon"); + m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "Start mining in daemon, start_mining "); m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon"); m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance"); m_cmd_binder.set_handler("show_balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance"); m_cmd_binder.set_handler("show_incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "Show incoming transfers"); m_cmd_binder.set_handler("show_bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height"); - m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer < > Transfer to
. is the number of transactions yours is indistinguishable from (from 0 to maximum available)"); + m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer { } Transfer to
. is the number of transactions yours is indistinguishable from (from 0 to maximum available)"); m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "Change current log detalization level, is a number 0-4"); m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address"); m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data"); @@ -98,13 +102,13 @@ bool simple_wallet::set_log(const std::vector &args) std::cout << "use: set_log " << ENDL; return true; } - int l = 0; + uint16_t l = 0; if(!string_tools::get_xtype_from_string(l, args[0])) { std::cout << "wrong number format, use: set_log " << ENDL; return true; } - if(l < 0 || l > LOG_LEVEL_4) + if(LOG_LEVEL_4 < l) { std::cout << "wrong number range, use: set_log " << ENDL; return true; @@ -176,20 +180,17 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ return true; } //---------------------------------------------------------------------------------------------------- -void simple_wallet::try_connect_to_daemon() +bool simple_wallet::try_connect_to_daemon() { - if (!m_tried_to_connect) + if (!m_wallet->check_connection()) { - m_tried_to_connect = true; - - if(!m_wallet->check_connection()) - { - std::cout << - "**********************************************************************" << ENDL << - "Wallet failed to connect to daemon. Daemon either is not started or passed wrong port. Please, make sure that daemon is running or restart the wallet with correct daemon address." << ENDL << - "**********************************************************************" << ENDL; - } + std::string msg = "wallet failed to connect to daemon (" + m_daemon_address + "). " + + "Daemon either is not started or passed wrong port. " + + "Please, make sure that daemon is running or restart the wallet with correct daemon address."; + print_fail_msg(msg); + return false; } + return true; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password) @@ -231,7 +232,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa r = m_wallet->init(m_daemon_address); CHECK_AND_ASSERT_MES(r, false, "failed to init wallet"); - refresh(vector()); + refresh(std::vector()); std::cout << "**********************************************************************" << ENDL << "Use \"help\" command to see the list of available commands." << ENDL << "**********************************************************************" << ENDL ; @@ -250,52 +251,72 @@ bool simple_wallet::close_wallet() bool simple_wallet::save(const std::vector &args) { bool r = m_wallet->store(); - CHECK_AND_ASSERT_MES(r, false, "failed to store wallet " + m_wallet_file); - std::cout << "Wallet data saved" << ENDL; + if (r) + print_success_msg("Wallet data saved"); + else + print_fail_msg("failed to store wallet " + m_wallet_file); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::start_mining(const vector& args) +bool simple_wallet::start_mining(const std::vector& args) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; COMMAND_RPC_START_MINING::request req; req.miner_address = m_wallet->get_account().get_public_address_str(); - req.threads_count = 1; - if(args.size() == 1) + + if (0 == args.size()) { - if(!string_tools::get_xtype_from_string(req.threads_count, args[0])) - { - std::cout << "Threads count value invalid \"" << args[0] << "\"" << ENDL; - return false; - } + req.threads_count = 1; } + else if (1 == args.size()) + { + uint16_t num; + bool ok = string_tools::get_xtype_from_string(num, args[0]); + if(!ok || 0 == num) + { + print_fail_msg("wrong number of mining threads: \"" + args[0] + "\""); + return true; + } + req.threads_count = num; + } + else + { + print_fail_msg("wrong number of arguments, expected the number of mining threads"); + return true; + } + COMMAND_RPC_START_MINING::response res; bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/start_mining", req, res, m_http_client); - if (!r) - std::cout << "Mining has NOT been started" << std::endl; - CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request"); - std::cout << "Mining started in daemon." << ENDL; + std::string err = tools::interpret_rpc_response(r, res.status); + if (err.empty()) + print_success_msg("Mining started in daemon"); + else + print_fail_msg("mining has NOT been started: " + err); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::stop_mining(const vector& args) +bool simple_wallet::stop_mining(const std::vector& args) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; COMMAND_RPC_STOP_MINING::request req; COMMAND_RPC_STOP_MINING::response res; bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/stop_mining", req, res, m_http_client); - if (!r) - std::cout << "Mining has NOT been stopped" << std::endl; - CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request"); - std::cout << "Mining stopped in daemon." << ENDL; + std::string err = tools::interpret_rpc_response(r, res.status); + if (err.empty()) + print_success_msg("Mining stopped in daemon"); + else + print_fail_msg("mining has NOT been stopped: " + err); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::refresh(const vector& args) +bool simple_wallet::refresh(const std::vector& args) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; std::cout << "Starting refresh..." << endl; std::atomic refresh_is_done(false); @@ -304,132 +325,166 @@ bool simple_wallet::refresh(const vector& args) epee::misc_utils::sleep_no_w(1000); while(!refresh_is_done) { - bool ok; - uint64_t bc_height = get_daemon_blockchain_height(ok); - if (ok) + std::string err; + uint64_t bc_height = get_daemon_blockchain_height(err); + if (err.empty()) cout << "Height " << m_wallet->get_blockchain_current_height() << " of " << bc_height << endl; epee::misc_utils::sleep_no_w(1000); } }); + uint64_t initial_height = m_wallet->get_blockchain_current_height(); uint64_t fetched_blocks = 0; bool money_received = false; - bool ok = m_wallet->refresh(fetched_blocks, money_received); + tools::wallet2::fail_details fd; + bool ok = m_wallet->refresh(fetched_blocks, money_received, fd); refresh_is_done = true; th.join(); if (ok) - std::cout << "Refresh done, blocks received: " << fetched_blocks << endl; + { + std::stringstream ss; + ss << "Refresh done, blocks received: " << fetched_blocks; + print_success_msg(ss.str(), true); + + show_balance(); + } else - std::cout << "Refresh failed, no blocks received" << std::endl; - show_balance(vector()); + { + fetched_blocks = m_wallet->get_blockchain_current_height() - initial_height; + std::stringstream ss; + ss << "refresh failed: " << fd.what() << ". Blocks received: " << fetched_blocks; + print_fail_msg(ss.str()); + } return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::show_balance(const vector& args) +bool simple_wallet::show_balance(const std::vector& args/* = std::vector()*/) { - cout << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance()) << endl; + std::stringstream ss; + ss << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance()); + print_success_msg(ss.str()); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::show_incoming_transfers(const vector& args) +bool simple_wallet::show_incoming_transfers(const std::vector& args) { - m_wallet->show_incoming_transfers(); + std::cout << " amount \tspent\tglobal index\t tx id" << std::endl; + bool ok = m_wallet->enum_incoming_transfers([](const cryptonote::transaction& tx, uint64_t global_out_index, uint64_t amount, bool spent) { + epee::log_space::set_console_color(spent ? epee::log_space::console_color_magenta : epee::log_space::console_color_green, true); + std::cout << std::setw(21) << print_money(amount) << '\t' + << std::setw(3) << (spent ? 'T' : 'F') << " \t" + << std::setw(12) << global_out_index << '\t' + << get_transaction_hash(tx) + << '\n'; + }); + epee::log_space::reset_console_color(); + if (ok) + std::cout.flush(); + else + print_fail_msg("No incoming transfers"); return true; } //---------------------------------------------------------------------------------------------------- -uint64_t simple_wallet::get_daemon_blockchain_height(bool& ok) +uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err) { COMMAND_RPC_GET_HEIGHT::request req; COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized(); - ok = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client); - CHECK_AND_ASSERT_MES(ok, 0, "failed to invoke http request"); + bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client); + err = tools::interpret_rpc_response(r, res.status); return res.height; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::show_blockchain_height(const vector& args) +bool simple_wallet::show_blockchain_height(const std::vector& args) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; - bool ok; - uint64_t bc_height = get_daemon_blockchain_height(ok); - if (ok) - cout << "core returned height: " << bc_height << endl; + std::string err; + uint64_t bc_height = get_daemon_blockchain_height(err); + if (err.empty()) + print_success_msg(boost::lexical_cast(bc_height)); else - std::cout << "Failed to get blockchain height" << std::endl; + print_fail_msg("failed to get blockchain height: " + err); return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::transfer(const vector &args_) +bool simple_wallet::transfer(const std::vector &args_) { - try_connect_to_daemon(); + if (!try_connect_to_daemon()) + return true; - vector local_args = args_; + std::vector local_args = args_; if(local_args.size() < 3) { - std::cout << "wrong transfer arguments" << std::endl; - help(vector()); + print_fail_msg("wrong number of arguments, expected at least 3, got " + boost::lexical_cast(local_args.size())); return true; } + size_t fake_outs_count; if(!string_tools::get_xtype_from_string(fake_outs_count, local_args[0])) { - std::cout << " ambiguity_degree set wrong" << std::endl; - help(vector()); + print_fail_msg("mixin_count should be non-negative integer, got " + local_args[0]); return true; } local_args.erase(local_args.begin()); - if(local_args.size() % 2 != 0) - { - cout << "wrong transfer arguments" << endl; - help(vector()); - return true; - } vector dsts; uint64_t summary_amount = 0; for (size_t i = 0; i < local_args.size(); i += 2) { cryptonote::tx_destination_entry de; - if(!cryptonote::parse_amount(de.amount, local_args[i+1])) + if(!get_account_address_from_str(de.addr, local_args[i])) { - cout << "Wrong transfer arguments" << endl;; - help(vector()); + print_fail_msg("wrong address: " + local_args[i]); return true; } - if(de.amount <= 0) + + if (local_args.size() <= i + 1) { - cout << "Wrong transfer amount: " << de.amount << endl;; - help(vector()); + print_fail_msg("amount for the last address " + local_args[i] + " is not specified"); return true; } + + bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]); + if(!ok || 0 == de.amount) + { + print_fail_msg("amount is wrong: " + local_args[i] + " " + local_args[i + 1]); + return true; + } + summary_amount += de.amount; - if(!get_account_address_from_str(de.addr, local_args[i])) - { - cout << "Wrong address: " << local_args[i] << endl; - help(vector()); - return true; - } dsts.push_back(de); } if(summary_amount > m_wallet->unlocked_balance()) { - cout << "Not enough money to transfer " << print_money(summary_amount) << ", available(unlocked) only " << print_money(m_wallet->unlocked_balance()) << endl; + print_fail_msg("not enough money to transfer " + print_money(summary_amount) + ", available (unlocked) only " + print_money(m_wallet->unlocked_balance())); return true; } - m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE); + cryptonote::transaction tx; + tools::wallet2::fail_details tfd; + bool ok = m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, tx, tfd); + if (ok) + print_success_msg("Money successfully sent", true); + else + print_fail_msg("failed to transfer money: " + tfd.what()); return true; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::run() { - m_cmd_binder.run_handling(""); - return true; + return m_cmd_binder.run_handling("[wallet]# ", ""); +} +//---------------------------------------------------------------------------------------------------- +void simple_wallet::stop() +{ + m_cmd_binder.stop_handling(); + m_wallet->stop(); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::print_address(const std::vector &args) { - std::cout << "Public address: " << m_wallet->get_account().get_public_address_str() << ENDL; + print_success_msg(m_wallet->get_account().get_public_address_str()); return true; } //---------------------------------------------------------------------------------------------------- @@ -482,7 +537,7 @@ int main(int argc, char* argv[]) } else if (command_line::get_arg(vm, command_line::arg_version)) { - std::cout << "BYTECOIN WALLET v" << PROJECT_VERSION_LONG << ENDL; + std::cout << CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG << ENDL; return false; } @@ -495,18 +550,19 @@ int main(int argc, char* argv[]) return 1; //set up logging options - log_space::get_set_log_detalisation_level(true, LOG_LEVEL_1); - log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); + log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); + log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0); log_space::log_singletone::add_logger(LOGGER_FILE, log_space::log_singletone::get_default_log_file().c_str(), - log_space::log_singletone::get_default_log_folder().c_str()); + log_space::log_singletone::get_default_log_folder().c_str(), LOG_LEVEL_4); + + LOG_PRINT_L0(CRYPTONOTE_NAME << " wallet v" << PROJECT_VERSION_LONG); if(command_line::has_arg(vm, arg_log_level)) { LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, arg_log_level)); log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, arg_log_level)); } - LOG_PRINT("simplewallet starting", LOG_LEVEL_0); r = w.init(vm); CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet"); @@ -514,6 +570,10 @@ int main(int argc, char* argv[]) std::vector command = command_line::get_arg(vm, arg_command); if (!command.empty()) w.process_command(command); + + tools::signal_handler::install([&w] { + w.stop(); + }); w.run(); w.deinit(); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 01d3ac4a..c448467f 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -29,6 +29,7 @@ namespace cryptonote bool init(const boost::program_options::variables_map& vm); bool deinit(); bool run(); + void stop(); //wallet *create_wallet(); bool process_command(const std::vector &args); @@ -42,11 +43,11 @@ namespace cryptonote bool open_wallet(const std::string &wallet_file, const std::string& password); bool close_wallet(); - bool help(const std::vector &args); + bool help(const std::vector &args = std::vector()); bool start_mining(const std::vector &args); bool stop_mining(const std::vector &args); bool refresh(const std::vector &args); - bool show_balance(const std::vector &args); + bool show_balance(const std::vector &args = std::vector()); bool show_incoming_transfers(const std::vector &args); bool show_blockchain_height(const std::vector &args); bool transfer(const std::vector &args); @@ -54,8 +55,8 @@ namespace cryptonote bool save(const std::vector &args); bool set_log(const std::vector &args); - uint64_t get_daemon_blockchain_height(bool& ok); - void try_connect_to_daemon(); + uint64_t get_daemon_blockchain_height(std::string& err); + bool try_connect_to_daemon(); std::string m_wallet_file; std::string m_generate_new; @@ -64,11 +65,10 @@ namespace cryptonote std::string m_daemon_address; std::string m_daemon_host; int m_daemon_port; - bool m_tried_to_connect; epee::console_handlers_binder m_cmd_binder; - std::auto_ptr m_wallet; + std::unique_ptr m_wallet; net_utils::http::http_simple_client m_http_client; }; } diff --git a/src/version.h.in b/src/version.h.in index 0e64c7a1..fd566680 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define BUILD_COMMIT_ID "@VERSION@" #define PROJECT_VERSION "0.8.2" -#define PROJECT_VERSION_BUILD_NO "279" +#define PROJECT_VERSION_BUILD_NO "284" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")" diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index aa4e2f51..7b898755 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -32,14 +32,16 @@ bool wallet2::init(const std::string& daemon_address, uint64_t upper_transaction return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t height) +bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t height, fail_details& fd) { std::vector outs; uint64_t tx_money_got_in_outs = 0; crypto::public_key tx_pub_key = null_pkey; bool r = parse_and_validate_tx_extra(tx, tx_pub_key); + fd.reason = fail_details::error_to_parse_tx_extra; CHECK_AND_ASSERT_MES(r && tx_pub_key != null_pkey, false, "process_new_transaction failed."); r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs); + fd.reason = fail_details::error_invalid_tx; CHECK_AND_ASSERT_MES(r, false, "call lookup_acc_outs failed"); if(outs.size() && tx_money_got_in_outs) { @@ -49,14 +51,24 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig cryptonote::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response res = AUTO_VAL_INIT(res); req.txid = get_transaction_hash(tx); bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/get_o_indexes.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT); - CHECK_AND_ASSERT_MES(r, false, "failed to get_o_indexes.bin"); - if(res.status != CORE_RPC_STATUS_OK) - return false;// in case of split while lookup_acc_outs, transaction could be lost (especially if it is coinbase tx) + if (!r) fd.reason = fail_details::error_not_connected; + else if (CORE_RPC_STATUS_BUSY == res.status) fd.reason = fail_details::error_daemon_is_busy; + else if (CORE_RPC_STATUS_OK != res.status) fd.reason = fail_details::error_internal_error; + else fd.reason = fail_details::error_ok; + if (fail_details::error_ok != fd.reason) + { + // in case of split while lookup_acc_outs, transaction could be lost (especially if it is coinbase tx) + LOG_PRINT_L0("failed to invoke get_o_indexes.bin: " << interpret_rpc_response(r, res.status)); + return false; + } + + fd.reason = fail_details::error_internal_error; CHECK_AND_ASSERT_MES(res.o_indexes.size() == tx.vout.size(), false, "internal error: transactions outputs size=" << tx.vout.size() - << " not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response size=" << res.o_indexes.size()); + << " not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response size=" << res.o_indexes.size()); BOOST_FOREACH(size_t o, outs) { + fd.reason = fail_details::error_invalid_tx; CHECK_AND_ASSERT_MES(o < tx.vout.size(), false, "wrong out in transaction: internal index=" << o << ", total_outs" << tx.vout.size()); m_transfers.push_back(boost::value_initialized()); transfer_details& td = m_transfers.back(); @@ -67,10 +79,12 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig td.m_spent = false; cryptonote::keypair in_ephemeral; cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, o, in_ephemeral, td.m_key_image); + fd.reason = fail_details::error_internal_error; CHECK_AND_ASSERT_MES(in_ephemeral.pub == boost::get(tx.vout[o].target).key, - false, "internal error: at key_image generating ephemeral public key not matched with output_key"); + false, "internal error: at key_image generating ephemeral public key not matched with output_key"); m_key_images[td.m_key_image] = m_transfers.size()-1; - LOG_PRINT_L1("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx)); + LOG_PRINT_COLOR("Received money: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx), + LOG_LEVEL_0, epee::log_space::console_color_green); } } // check all outputs for spending (compare key images) @@ -81,22 +95,24 @@ bool wallet2::process_new_transaction(cryptonote::transaction& tx, uint64_t heig auto it = m_key_images.find(boost::get(in).k_image); if(it != m_key_images.end()) { - LOG_PRINT_L1("Spent money: " << print_money(boost::get(in).amount) << ", with tx: " << get_transaction_hash(tx)); + LOG_PRINT_COLOR("Spent money: " << print_money(boost::get(in).amount) << ", with tx: " << get_transaction_hash(tx), + LOG_LEVEL_0, epee::log_space::console_color_magenta); m_transfers[it->second].m_spent = true; } } return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height) +bool wallet2::process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height, fail_details& fd) { //handle transactions from new block + fd.reason = fail_details::error_internal_error; CHECK_AND_ASSERT_MES(height == m_blockchain.size(), false, "internal error: current_index=" << height << ", m_blockchain.size()=" << m_blockchain.size()); //optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup if(b.timestamp + 60*60*24 > m_account.get_createtime()) { TIME_MEASURE_START(miner_tx_handle_time); - bool r = process_new_transaction(b.miner_tx, height); + bool r = process_new_transaction(b.miner_tx, height, fd); TIME_MEASURE_FINISH(miner_tx_handle_time); CHECK_AND_NO_ASSERT_MES(r, false, "failed to process transaction"); @@ -105,8 +121,9 @@ bool wallet2::process_new_blockchain_entry(cryptonote::block& b, cryptonote::blo { cryptonote::transaction tx; r = parse_and_validate_tx_from_blob(txblob, tx); + fd.reason = fail_details::error_to_parse_tx; CHECK_AND_ASSERT_MES(r, false, "failed to parse and validate transaction from blob"); - r = process_new_transaction(tx, height); + r = process_new_transaction(tx, height, fd); CHECK_AND_ASSERT_MES(r, false, "failed to process transaction"); } TIME_MEASURE_FINISH(txs_handle_time); @@ -149,18 +166,26 @@ bool wallet2::get_short_chain_history(std::list& ids) return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::pull_blocks(size_t& blocks_added) +bool wallet2::pull_blocks(size_t& blocks_added, fail_details& fd) { blocks_added = 0; cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req); cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res); get_short_chain_history(req.block_ids); bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getblocks.bin", req, res, m_http_client, WALLET_RCP_CONNECTION_TIMEOUT); - CHECK_AND_ASSERT_MES(r, false, "failed to get blocks"); - CHECK_AND_ASSERT_MES(res.status == CORE_RPC_STATUS_OK, false, "failed to get blocks"); + if (!r) fd.reason = fail_details::error_not_connected; + else if (CORE_RPC_STATUS_BUSY == res.status) fd.reason = fail_details::error_daemon_is_busy; + else if (CORE_RPC_STATUS_OK != res.status) fd.reason = fail_details::error_internal_error; + else fd.reason = fail_details::error_ok; + if (fail_details::error_ok != fd.reason) + { + LOG_PRINT_L0("failed to get blocks: " << interpret_rpc_response(r, res.status)); + return false; + } //find split position, if split happened + fd.reason = fail_details::error_internal_error; CHECK_AND_ASSERT_MES(res.start_height < m_blockchain.size(), false, "wrong daemon response: m_start_height=" << res.start_height << " not less than local blockchain size=" << m_blockchain.size()); @@ -169,11 +194,12 @@ bool wallet2::pull_blocks(size_t& blocks_added) { cryptonote::block bl; r = cryptonote::parse_and_validate_block_from_blob(bl_entry.block, bl); + fd.reason = fail_details::error_to_parse_block; CHECK_AND_ASSERT_MES(r, false, "failed to parse/validate block"); crypto::hash bl_id = get_block_hash(bl); if(current_index >= m_blockchain.size()) { - r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index); + r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index, fd); if(!r) return false; ++blocks_added; }else @@ -181,12 +207,12 @@ bool wallet2::pull_blocks(size_t& blocks_added) if(bl_id != m_blockchain[current_index]) { //split detected here !!! + fd.reason = fail_details::error_internal_error; CHECK_AND_ASSERT_MES(current_index != res.start_height, false, "wrong daemon response: first block in response " << string_tools::pod_to_hex(bl_id) << "\nnot match with local block id " << string_tools::pod_to_hex(m_blockchain[current_index])); detach_blockchain(current_index); - r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index); + r = process_new_blockchain_entry(bl, bl_entry, bl_id, current_index, fd); if(!r) return false; - } } ++current_index; @@ -194,19 +220,19 @@ bool wallet2::pull_blocks(size_t& blocks_added) return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::refresh() +bool wallet2::refresh(fail_details& fd) { size_t blocks_fetched = 0; - return refresh(blocks_fetched); + return refresh(blocks_fetched, fd); } //---------------------------------------------------------------------------------------------------- -bool wallet2::refresh(size_t & blocks_fetched) +bool wallet2::refresh(size_t & blocks_fetched, fail_details& fd) { bool received_money = false; - return refresh(blocks_fetched, received_money); + return refresh(blocks_fetched, received_money, fd); } //---------------------------------------------------------------------------------------------------- -bool wallet2::refresh(size_t & blocks_fetched, bool& received_money) +bool wallet2::refresh(size_t & blocks_fetched, bool& received_money, fail_details& fd) { received_money = false; blocks_fetched = 0; @@ -214,19 +240,19 @@ bool wallet2::refresh(size_t & blocks_fetched, bool& received_money) size_t try_count = 0; crypto::hash last_tx_hash_id = m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash; - while(true) + while(m_run.load(std::memory_order_relaxed)) { - bool res = pull_blocks(added_blocks); + bool res = pull_blocks(added_blocks, fd); if(!res) { if(try_count < 3) { - LOG_PRINT_L0("Another try pull_blocks(try_count=" << try_count << ")..."); + LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")..."); ++try_count; continue; }else { - LOG_PRINT_L0("pull_blocks failed, try_count=" << try_count); + LOG_PRINT_L1("pull_blocks failed, try_count=" << try_count); return false; } } @@ -238,7 +264,7 @@ bool wallet2::refresh(size_t & blocks_fetched, bool& received_money) if(last_tx_hash_id != (m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash)) received_money = true; - LOG_PRINT_L2( "Refresh done, blocks received: " << blocks_fetched << ", balance: " << print_money(balance()) << ", unlocked: " << print_money(unlocked_balance())); + LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", balance: " << print_money(balance()) << ", unlocked: " << print_money(unlocked_balance())); return true; } //---------------------------------------------------------------------------------------------------- @@ -439,25 +465,6 @@ bool wallet2::store() return r; } //---------------------------------------------------------------------------------------------------- -void wallet2::show_incoming_transfers() -{ - uint64_t amount = 0; - if(!m_transfers.size()) - { - LOG_PRINT_L0("No incoming transfers"); - return; - } - BOOST_FOREACH(transfer_details& td, m_transfers) - { - LOG_PRINT_L0("transfer: " << print_money(td.amount()) - << ", spent: " << td.m_spent - << ", global_index: " << td.m_global_output_index - << ", tx_id: " << get_transaction_hash(td.m_tx)); - if(!td.m_spent) - amount += td.amount(); - } -} -//---------------------------------------------------------------------------------------------------- uint64_t wallet2::unlocked_balance() { uint64_t amount = 0; @@ -535,7 +542,7 @@ namespace } } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::select_transfers(uint64_t needed_money, uint64_t dust, std::list& selected_transfers) +uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list& selected_transfers) { std::vector unused_transfers_indices; std::vector unused_dust_indices; @@ -551,19 +558,19 @@ uint64_t wallet2::select_transfers(uint64_t needed_money, uint64_t dust, std::li } } - bool at_least_one_dust_selected = unused_dust_indices.empty(); + bool select_one_dust = add_dust && !unused_dust_indices.empty(); uint64_t found_money = 0; while (found_money < needed_money && (!unused_transfers_indices.empty() || !unused_dust_indices.empty())) { size_t idx; - if (at_least_one_dust_selected) + if (select_one_dust) { - idx = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices); + idx = pop_random_value(unused_dust_indices); + select_one_dust = false; } else { - idx = pop_random_value(unused_dust_indices); - at_least_one_dust_selected = true; + idx = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices); } transfer_container::iterator it = m_transfers.begin() + idx; @@ -580,7 +587,7 @@ bool wallet2::transfer(const std::vector& dsts return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx); } //---------------------------------------------------------------------------------------------------- -bool wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, transafer_fail_details& tfd) +bool wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, fail_details& tfd) { return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx, tfd); } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 27799e2d..f26f8022 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -25,11 +25,33 @@ namespace tools { + inline std::string interpret_rpc_response(bool ok, const std::string& status) + { + std::string err; + if (ok) + { + if (status == CORE_RPC_STATUS_BUSY) + { + err = "daemon is busy. Please try later"; + } + else if (status != CORE_RPC_STATUS_OK) + { + err = status; + } + } + else + { + err = "possible lost connection to daemon"; + } + return err; + } + + class wallet2 { - wallet2(const wallet2&){}; + wallet2(const wallet2&) : m_run(true) {}; public: - wallet2(){}; + wallet2() : m_run(true) {}; struct transfer_details { uint64_t m_block_height; @@ -68,20 +90,46 @@ namespace tools END_SERIALIZE() }; - struct transafer_fail_details + struct fail_details { enum fail_reason { error_ok = 0, error_not_connected, + error_daemon_is_busy, error_rejected_by_daemon, - error_too_big_transaction, - error_not_enough_money, + error_too_big_transaction, + error_not_enough_money, + error_too_big_mixin, + error_to_parse_block, + error_to_parse_tx, + error_to_parse_tx_extra, + error_invalid_tx, error_internal_error }; fail_reason reason; uint64_t tx_blob_size; uint64_t max_expected_tx_blob_size; + + std::string what() const + { + switch (reason) + { + case error_ok: return "OK"; + case error_not_connected: return "not connected"; + case error_daemon_is_busy: return "daemon is busy. Please try later"; + case error_rejected_by_daemon: return "rejected by daemon"; + case error_too_big_transaction: return "transaction size is too big"; + case error_not_enough_money: return "not enough money"; + case error_too_big_mixin: return "not enough outputs for specified mixin_count"; + case error_to_parse_block: return "failed to parse/validate block"; + case error_to_parse_tx: return "failed to parse/validate tx"; + case error_to_parse_tx_extra: return "failed to parse/validate tx extra"; + case error_invalid_tx: return "wrong tx"; + case error_internal_error: return "internal error"; + default: return "unknown error"; + } + } }; bool generate(const std::string& wallet, const std::string& password); @@ -91,23 +139,26 @@ namespace tools bool init(const std::string& daemon_address = "http://localhost:8080", uint64_t upper_transaction_size_limit = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE*2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE); - bool refresh(); - bool refresh(size_t & blocks_fetched); - bool refresh(size_t & blocks_fetched, bool& received_money); + bool refresh(fail_details& fd); + bool refresh(size_t & blocks_fetched, fail_details& fd); + bool refresh(size_t & blocks_fetched, bool& received_money, fail_details& fd); bool deinit(); + void stop() { m_run.store(false, std::memory_order_relaxed); } + uint64_t balance(); uint64_t unlocked_balance(); - void show_incoming_transfers(); + template + bool enum_incoming_transfers(const T& handler) const; template bool transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy); template - bool transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, transafer_fail_details& tfd); + bool transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, fail_details& tfd); template bool transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx); bool transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee); bool transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx); - bool transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, transafer_fail_details& tfd); + bool transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, fail_details& tfd); bool check_connection(); bool get_transfers(wallet2::transfer_container& incoming_transfers); uint64_t get_blockchain_current_height() const { return m_local_bc_height; } @@ -125,15 +176,15 @@ namespace tools private: bool store_keys(const std::string& keys_file_name, const std::string& password); bool load_keys(const std::string& keys_file_name, const std::string& password); - bool process_new_transaction(cryptonote::transaction& tx, uint64_t height); - bool process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height); + bool process_new_transaction(cryptonote::transaction& tx, uint64_t height, fail_details& fd); + bool process_new_blockchain_entry(cryptonote::block& b, cryptonote::block_complete_entry& bche, crypto::hash& bl_id, uint64_t height, fail_details& fd); bool detach_blockchain(uint64_t height); bool get_short_chain_history(std::list& ids); bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; bool is_transfer_unlocked(const transfer_details& td) const; bool clear(); - bool pull_blocks(size_t& blocks_added); - uint64_t select_transfers(uint64_t needed_money, uint64_t dust, std::list& selected_transfers); + bool pull_blocks(size_t& blocks_added, fail_details& fd); + uint64_t select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list& selected_transfers); bool prepare_file_names(const std::string& file_path); cryptonote::account_base m_account; @@ -148,6 +199,8 @@ namespace tools std::unordered_map m_key_images; cryptonote::account_public_address m_account_public_address; uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value + + std::atomic m_run; }; } BOOST_CLASS_VERSION(tools::wallet2, 5) @@ -229,12 +282,29 @@ namespace tools { std::string indexes; std::for_each(src.outputs.begin(), src.outputs.end(), [&](const cryptonote::tx_source_entry::output_entry& s_e) { indexes += boost::to_string(s_e.first) + " "; }); - std::cout << "amount=" << cryptonote::print_money(src.amount) << ", real_output=" < + bool wallet2::enum_incoming_transfers(const T& handler) const + { + if(!m_transfers.empty()) + { + BOOST_FOREACH(const transfer_details& td, m_transfers) + { + handler(td.m_tx, td.m_global_output_index, td.amount(), td.m_spent); + } + return true; + } + else + { + return false; + } + } + //---------------------------------------------------------------------------------------------------- + template bool wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy) { @@ -246,13 +316,13 @@ namespace tools bool wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx) { - transafer_fail_details stub = AUTO_VAL_INIT(stub); + fail_details stub = AUTO_VAL_INIT(stub); return transfer(dsts, fake_outputs_count, unlock_time, fee, destination_split_strategy, dust_policy, tx, stub); } template bool wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, - uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, transafer_fail_details& tfd) + uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx, fail_details& tfd) { using namespace cryptonote; @@ -264,12 +334,13 @@ namespace tools } std::list selected_transfers; - uint64_t found_money = select_transfers(needed_money, dust_policy.dust_threshold, selected_transfers); + uint64_t found_money = select_transfers(needed_money, 0 == fake_outputs_count, dust_policy.dust_threshold, selected_transfers); if(found_money < needed_money) { - LOG_ERROR("not enough money, available only " << print_money(found_money) << ", expected " << print_money(needed_money) ); - tfd.reason = transafer_fail_details::error_not_enough_money; + LOG_ERROR("not enough money, available only " << print_money(found_money) << ", transaction amount " << + print_money(needed_money) << " = " << print_money(needed_money - fee) << " + " << print_money(fee) << " (fee)"); + tfd.reason = fail_details::error_not_enough_money; return false; } //typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount; @@ -279,7 +350,6 @@ namespace tools COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp); if(fake_outputs_count) { - COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req); req.outs_count = fake_outputs_count + 1;// add one to make possible (if need) to skip real output key BOOST_FOREACH(transfer_container::iterator it, selected_transfers) @@ -288,15 +358,37 @@ namespace tools << it->m_internal_output_index << " more than " << it->m_tx.vout.size()); req.amounts.push_back(it->amount()); } + bool r = net_utils::invoke_http_bin_remote_command2(m_daemon_address + "/getrandom_outs.bin", req, daemon_resp, m_http_client, 200000); - tfd.reason = transafer_fail_details::error_not_connected; - CHECK_AND_ASSERT_MES(r, false, "failed to get getrandom_outs"); - tfd.reason = transafer_fail_details::error_internal_error; - CHECK_AND_ASSERT_MES(daemon_resp.status == CORE_RPC_STATUS_OK, false, "failed to getrandom_outs.bin"); - CHECK_AND_ASSERT_MES(daemon_resp.outs.size() == selected_transfers.size(), false, "internal error: daemon returned wrong response for getrandom_outs, wrong amounts count = " + if (!r) tfd.reason = fail_details::error_not_connected; + else if (CORE_RPC_STATUS_BUSY == daemon_resp.status) tfd.reason = fail_details::error_daemon_is_busy; + else if (CORE_RPC_STATUS_OK != daemon_resp.status) tfd.reason = fail_details::error_internal_error; + else tfd.reason = fail_details::error_ok; + if (fail_details::error_ok != tfd.reason) + { + LOG_PRINT_L0("failed to invoke getrandom_outs.bin: " << interpret_rpc_response(r, daemon_resp.status)); + return false; + } + + tfd.reason = fail_details::error_internal_error; + CHECK_AND_ASSERT_MES(daemon_resp.outs.size() == selected_transfers.size(), false, + "internal error: daemon returned wrong response for getrandom_outs.bin, wrong amounts count = " << daemon_resp.outs.size() << ", expected " << selected_transfers.size()); + + tfd.reason = fail_details::error_ok; + BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs) + { + if (amount_outs.outs.size() != fake_outputs_count) + { + tfd.reason = fail_details::error_too_big_mixin; + LOG_PRINT_L0("not enough outputs to mix output " << print_money(amount_outs.amount) << ", requested " << + fake_outputs_count << ", found " << amount_outs.outs.size()); + } + } + if (fail_details::error_ok != tfd.reason) + return false; } - tfd.reason = transafer_fail_details::error_ok; + tfd.reason = fail_details::error_ok; //prepare inputs size_t i = 0; @@ -356,34 +448,48 @@ namespace tools { splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust)); } - - tfd.reason = transafer_fail_details::error_internal_error; + + tfd.reason = fail_details::error_internal_error; bool r = cryptonote::construct_tx(m_account.get_keys(), sources, splitted_dsts, tx, unlock_time); CHECK_AND_ASSERT_MES(r, false, "Transaction construction failed"); //check transaction size if(get_object_blobsize(tx) >= m_upper_transaction_size_limit) { - LOG_PRINT_RED("Transaction size is too big: " << get_object_blobsize(tx) << ", expected size < " << m_upper_transaction_size_limit, LOG_LEVEL_2); - tfd.reason = transafer_fail_details::error_too_big_transaction; + LOG_PRINT_L0("Transaction size is too big: " << get_object_blobsize(tx) << ", expected size < " << m_upper_transaction_size_limit); + tfd.reason = fail_details::error_too_big_transaction; tfd.tx_blob_size = get_object_blobsize(tx); tfd.max_expected_tx_blob_size = m_upper_transaction_size_limit; return false; } - COMMAND_RPC_SEND_RAW_TX::request req; req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx)); COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp; - tfd.reason = transafer_fail_details::error_not_connected; r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000); - CHECK_AND_ASSERT_MES(r, false, "failed to send transaction"); - if(daemon_send_resp.status != CORE_RPC_STATUS_OK) + if (!r) { - tfd.reason = transafer_fail_details::error_rejected_by_daemon; - LOG_ERROR("daemon failed to accept generated transaction, id: " << get_transaction_hash(tx) ); + tfd.reason = fail_details::error_not_connected; + LOG_PRINT_L0("failed to send transaction: " << interpret_rpc_response(r, daemon_send_resp.status)); return false; } + else if (CORE_RPC_STATUS_BUSY == daemon_send_resp.status) + { + tfd.reason = fail_details::error_daemon_is_busy; + LOG_PRINT_L0("failed to send transaction: " << interpret_rpc_response(r, daemon_send_resp.status)); + return false; + } + else if (CORE_RPC_STATUS_OK != daemon_send_resp.status) + { + tfd.reason = fail_details::error_rejected_by_daemon; + LOG_ERROR("daemon failed to accept generated transaction, id: " << get_transaction_hash(tx)); + return false; + } + else + { + tfd.reason = fail_details::error_ok; + } + std::string key_images; std::for_each(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool { @@ -397,12 +503,12 @@ namespace tools it->m_spent = true; LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(tx) << ">" << ENDL - << "Commission: " << print_money(fee+dust) << "(dust: " << print_money(dust) << ")" << ENDL + << "Commission: " << print_money(fee+dust) << " (dust: " << print_money(dust) << ")" << ENDL << "Balance: " << print_money(balance()) << ENDL << "Unlocked: " << print_money(unlocked_balance()) << ENDL << "Please, wait for confirmation for your balance to be unlocked."); - tfd.reason = transafer_fail_details::error_ok; + tfd.reason = fail_details::error_ok; return true; } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 64dde411..922622e0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -40,13 +40,6 @@ target_link_libraries(unit_tests cryptonote_core common crypto gtest_main ${Boos target_link_libraries(net_load_tests_clt cryptonote_core common crypto gtest_main ${Boost_LIBRARIES}) target_link_libraries(net_load_tests_srv cryptonote_core common crypto gtest_main ${Boost_LIBRARIES}) -if(NOT WIN32) - target_link_libraries(coretests rt) - target_link_libraries(functional_tests rt) - target_link_libraries(performance_tests rt) - target_link_libraries(core_proxy rt) - target_link_libraries(unit_tests rt) -endif() if(NOT MSVC) set_property(TARGET gtest gtest_main unit_tests net_load_tests_clt net_load_tests_srv APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-sign-compare") endif() @@ -57,8 +50,8 @@ set_property(TARGET coretests crypto-tests functional_tests difficulty-tests gte add_test(coretests coretests --generate_and_play_test_data) add_test(crypto crypto-tests ${CMAKE_CURRENT_SOURCE_DIR}/crypto/tests.txt) add_test(difficulty difficulty-tests ${CMAKE_CURRENT_SOURCE_DIR}/difficulty/data.txt) -foreach(hash IN ITEMS fast slow tree)# extra-blake extra-groestl extra-jh extra-skein) -add_test(hash-${hash} hash-tests ${hash} ${CMAKE_CURRENT_SOURCE_DIR}/hash/tests-${hash}.txt) +foreach(hash IN ITEMS fast slow tree extra-blake extra-groestl extra-jh extra-skein) + add_test(hash-${hash} hash-tests ${hash} ${CMAKE_CURRENT_SOURCE_DIR}/hash/tests-${hash}.txt) endforeach(hash) add_test(hash-target hash-target-tests) add_test(unit_tests unit_tests) \ No newline at end of file diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index af42f06a..3683c216 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -102,7 +102,8 @@ bool transactions_flow_test(std::string& working_folder, return false; } size_t blocks_fetched = 0; - if(!w1.refresh(blocks_fetched)) + tools::wallet2::fail_details fd; + if(!w1.refresh(blocks_fetched, fd)) { LOG_ERROR( "failed to refresh source wallet from " << daemon_addr_a ); return false; @@ -134,11 +135,11 @@ bool transactions_flow_test(std::string& working_folder, CHECK_AND_ASSERT_MES(daemon_rsp.status == CORE_RPC_STATUS_OK, false, "failed to getrandom_outs.bin"); //wait for money, until balance will have enough money - w1.refresh(blocks_fetched); + w1.refresh(blocks_fetched, fd); while(w1.unlocked_balance() < amount_to_transfer) { misc_utils::sleep_no_w(1000); - w1.refresh(blocks_fetched); + w1.refresh(blocks_fetched, fd); } //lets make a lot of small outs to ourselves @@ -165,7 +166,7 @@ bool transactions_flow_test(std::string& working_folder, }else { misc_utils::sleep_no_w(1000); - w1.refresh(); + w1.refresh(fd); } } //do actual transfer @@ -187,7 +188,7 @@ bool transactions_flow_test(std::string& working_folder, { misc_utils::sleep_no_w(1000); LOG_PRINT_L0("not enough money, waiting for cashback or mining"); - w1.refresh(blocks_fetched); + w1.refresh(blocks_fetched, fd); } transaction tx; @@ -202,7 +203,7 @@ bool transactions_flow_test(std::string& working_folder, if(!do_send_money(w1, w2, mix_in_factor, amount_to_tx, tx)) { LOG_PRINT_L0("failed to transfer money, tx: " << get_transaction_hash(tx) << ", refresh and try again" ); - w1.refresh(blocks_fetched); + w1.refresh(blocks_fetched, fd); if(!do_send_money(w1, w2, mix_in_factor, amount_to_tx, tx)) { LOG_PRINT_L0( "failed to transfer money, second chance. tx: " << get_transaction_hash(tx) << ", exit" ); @@ -227,7 +228,7 @@ bool transactions_flow_test(std::string& working_folder, misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*20*1000);//wait two blocks before sync on another wallet on another daemon LOG_PRINT_L0( "refreshing..."); bool recvd_money = false; - while(w2.refresh(blocks_fetched, recvd_money) && ( (blocks_fetched && recvd_money) || !blocks_fetched ) ) + while(w2.refresh(blocks_fetched, recvd_money, fd) && ( (blocks_fetched && recvd_money) || !blocks_fetched ) ) { misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*1000);//wait two blocks before sync on another wallet on another daemon } diff --git a/tests/net_load_tests/clt.cpp b/tests/net_load_tests/clt.cpp index 45c1d085..3bb29a7d 100644 --- a/tests/net_load_tests/clt.cpp +++ b/tests/net_load_tests/clt.cpp @@ -12,6 +12,7 @@ #include "gtest/gtest.h" #include "include_base_utils.h" +#include "misc_language.h" #include "misc_log_ex.h" #include "storages/levin_abstract_invoke2.h" @@ -33,7 +34,8 @@ namespace { if (predicate()) return true; - std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms)); + //std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms)); + epee::misc_utils::sleep_no_w(sleep_ms); } return false; } @@ -292,7 +294,8 @@ namespace return true; } - std::this_thread::sleep_for(std::chrono::seconds(1)); + //std::this_thread::sleep_for(std::chrono::seconds(1)); + epee::misc_utils::sleep_no_w(1000); } return false; diff --git a/tests/unit_tests/base58.cpp b/tests/unit_tests/base58.cpp index 05bf5afc..87afd5d0 100644 --- a/tests/unit_tests/base58.cpp +++ b/tests/unit_tests/base58.cpp @@ -399,9 +399,12 @@ TEST_encode_decode_addr(PuT7GAdgbA83uoWF3eanGG1aRoG, 0x1122334455667788, "\x TEST_encode_decode_addr(PuT7GAdgbA83vT1umSHMYJ4oNVdu, 0x1122334455667788, "\x77\x77\x77\x77\x77\x77\x77"); TEST_encode_decode_addr(PuT7GAdgbA83w6XaVDyvpoGQBEWbB, 0x1122334455667788, "\x88\x88\x88\x88\x88\x88\x88\x88"); TEST_encode_decode_addr(PuT7GAdgbA83wk3FD1gW7J2KVGofA1r, 0x1122334455667788, "\x99\x99\x99\x99\x99\x99\x99\x99\x99"); +TEST_encode_decode_addr(15p2yAV, 0, ""); +TEST_encode_decode_addr(FNQ3D6A, 0x7F, ""); +TEST_encode_decode_addr(26k9QWweu, 0x80, ""); +TEST_encode_decode_addr(3BzAD7n3y, 0xFF, ""); TEST_encode_decode_addr(11efCaY6UjG7JrxuB, 0, "\x11\x22\x33\x44\x55\x66\x77"); TEST_encode_decode_addr(21rhHRT48LN4PriP9, 6, "\x11\x22\x33\x44\x55\x66\x77"); -TEST_encode_decode_addr(3BzAD7n3y, 0xFF, ""); #define TEST_decode_addr_neg(addr, test_name) \ @@ -421,6 +424,14 @@ TEST_decode_addr_neg("\0uT7GAdgbA819VwdWVDP", decode_fails_due_invalid_char_00); TEST_decode_addr_neg("PuT7GAdgbA819VwdWVD", decode_fails_due_invalid_lenght); TEST_decode_addr_neg("11efCaY6UjG7JrxuC", handles_invalid_checksum); TEST_decode_addr_neg("jerj2e4mESo", handles_non_correct_tag); // "jerj2e4mESo" == "\xFF\x00\xFF\xFF\x5A\xD9\xF1\x1C" +TEST_decode_addr_neg("1", decode_fails_due_invalid_block_len_0); +TEST_decode_addr_neg("1111", decode_fails_due_invalid_block_len_1); +TEST_decode_addr_neg("11", decode_fails_due_address_too_short_0); +TEST_decode_addr_neg("111", decode_fails_due_address_too_short_1); +TEST_decode_addr_neg("11111", decode_fails_due_address_too_short_2); +TEST_decode_addr_neg("111111", decode_fails_due_address_too_short_3); +TEST_decode_addr_neg("999999", decode_fails_due_address_too_short_4); +TEST_decode_addr_neg("ZZZZZZ", decode_fails_due_address_too_short_5); namespace { diff --git a/tests/unit_tests/decompose_amount_into_digits.cpp b/tests/unit_tests/decompose_amount_into_digits.cpp index d7c66cc7..319b39e2 100644 --- a/tests/unit_tests/decompose_amount_into_digits.cpp +++ b/tests/unit_tests/decompose_amount_into_digits.cpp @@ -56,8 +56,7 @@ namespace TEST_F(decompose_amount_into_digits_test, is_correct_0) { - uint64_t expected_chunks_arr[] = {0}; - VEC_FROM_ARR(expected_chunks); + std::vector expected_chunks; cryptonote::decompose_amount_into_digits(0, 0, m_chunk_handler, m_dust_handler); ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); ASSERT_EQ(m_dust_handler.m_has_dust, false); @@ -65,8 +64,7 @@ TEST_F(decompose_amount_into_digits_test, is_correct_0) TEST_F(decompose_amount_into_digits_test, is_correct_1) { - uint64_t expected_chunks_arr[] = {0}; - VEC_FROM_ARR(expected_chunks); + std::vector expected_chunks; cryptonote::decompose_amount_into_digits(0, 10, m_chunk_handler, m_dust_handler); ASSERT_EQ(m_chunk_handler.m_chunks, expected_chunks); ASSERT_EQ(m_dust_handler.m_has_dust, false); diff --git a/tests/unit_tests/get_xtype_from_string.cpp b/tests/unit_tests/get_xtype_from_string.cpp new file mode 100644 index 00000000..0ba80fb3 --- /dev/null +++ b/tests/unit_tests/get_xtype_from_string.cpp @@ -0,0 +1,133 @@ +// 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. + +#include "gtest/gtest.h" + +#include + +using namespace epee::string_tools; + +namespace +{ + template + void do_pos_test(T expected, const std::string& str) + { + T val; + ASSERT_TRUE(get_xtype_from_string(val, str)); + ASSERT_EQ(expected, val); + } + + template + void do_neg_test(const std::string& str) + { + T val; + ASSERT_FALSE(get_xtype_from_string(val, str)); + } +} + +#define TEST_pos(int_type, expected, str) \ + TEST(get_xtype_from_string, handles_pos_ ## int_type ## _ ## expected) \ + { \ + do_pos_test(expected, str); \ + } + +#define DO_MAKE_NEG_TEST_NAME(prefix, int_type, ln) prefix ## int_type ## _ ## ln +#define MAKE_NEG_TEST_NAME(prefix, int_type, ln) DO_MAKE_NEG_TEST_NAME(prefix, int_type, ln) + +#define TEST_neg(int_type, str) \ + TEST(get_xtype_from_string, MAKE_NEG_TEST_NAME(handles_neg, int_type, __LINE__)) \ + { \ + do_neg_test(str); \ + } + +TEST_pos(uint16_t, 0, "0"); +TEST_pos(uint16_t, 1, "1"); +TEST_pos(uint16_t, 65535, "65535"); + +TEST_neg(uint16_t, "+0"); +TEST_neg(uint16_t, "+1"); +TEST_neg(uint16_t, "+65535"); +TEST_neg(uint16_t, "+65536"); + +TEST_neg(uint16_t, "-0"); +TEST_neg(uint16_t, "-1"); +TEST_neg(uint16_t, "-65535"); +TEST_neg(uint16_t, "-65536"); + +TEST_neg(uint16_t, ".0"); +TEST_neg(uint16_t, ".1"); +TEST_neg(uint16_t, "0.0"); +TEST_neg(uint16_t, "0.1"); +TEST_neg(uint16_t, "1.0"); +TEST_neg(uint16_t, "1.1"); + +TEST_neg(uint16_t, "w"); +TEST_neg(uint16_t, "0w"); +TEST_neg(uint16_t, "1w"); +TEST_neg(uint16_t, "1w1"); +TEST_neg(uint16_t, "65535w"); + +TEST_neg(uint16_t, "65536"); +TEST_neg(uint16_t, "4294967296"); +TEST_neg(uint16_t, "18446744073709551616"); + + +TEST_pos(uint32_t, 0, "0"); +TEST_pos(uint32_t, 1, "1"); +TEST_pos(uint32_t, 4294967295, "4294967295"); + +TEST_neg(uint32_t, "+0"); +TEST_neg(uint32_t, "+1"); +TEST_neg(uint32_t, "+4294967295"); +TEST_neg(uint32_t, "+4294967296"); + +TEST_neg(uint32_t, "-0"); +TEST_neg(uint32_t, "-1"); +TEST_neg(uint32_t, "-4294967295"); +TEST_neg(uint32_t, "-4294967296"); + +TEST_neg(uint32_t, ".0"); +TEST_neg(uint32_t, ".1"); +TEST_neg(uint32_t, "0.0"); +TEST_neg(uint32_t, "0.1"); +TEST_neg(uint32_t, "1.0"); +TEST_neg(uint32_t, "1.1"); + +TEST_neg(uint32_t, "w"); +TEST_neg(uint32_t, "0w"); +TEST_neg(uint32_t, "1w"); +TEST_neg(uint32_t, "1w1"); +TEST_neg(uint32_t, "4294967295w"); + +TEST_neg(uint32_t, "4294967296"); +TEST_neg(uint32_t, "18446744073709551616"); + +TEST_pos(uint64_t, 0, "0"); +TEST_pos(uint64_t, 1, "1"); +TEST_pos(uint64_t, 18446744073709551615ULL, "18446744073709551615"); + +TEST_neg(uint64_t, "+0"); +TEST_neg(uint64_t, "+1"); +TEST_neg(uint64_t, "+18446744073709551615"); +TEST_neg(uint64_t, "+18446744073709551616"); + +TEST_neg(uint64_t, "-0"); +TEST_neg(uint64_t, "-1"); +TEST_neg(uint64_t, "-18446744073709551615"); +TEST_neg(uint64_t, "-18446744073709551616"); + +TEST_neg(uint64_t, ".0"); +TEST_neg(uint64_t, ".1"); +TEST_neg(uint64_t, "0.0"); +TEST_neg(uint64_t, "0.1"); +TEST_neg(uint64_t, "1.0"); +TEST_neg(uint64_t, "1.1"); + +TEST_neg(uint64_t, "w"); +TEST_neg(uint64_t, "0w"); +TEST_neg(uint64_t, "1w"); +TEST_neg(uint64_t, "1w1"); +TEST_neg(uint64_t, "18446744073709551615w"); + +TEST_neg(uint64_t, "18446744073709551616"); diff --git a/utils/munin_plugins/height b/utils/munin_plugins/height index eaa9e3e1..d9f9aabd 100644 --- a/utils/munin_plugins/height +++ b/utils/munin_plugins/height @@ -13,4 +13,4 @@ EOM esac printf "height.value " -/home/user/bytecoin_bin/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep hight | cut -d ' ' -f2 +/home/user/bytecoin_bin/connectivity_tool --ip=127.0.0.1 --rpc_port=8081 --timeout=1000 --rpc_get_daemon_info | grep height | cut -d ' ' -f2