some fixes

This commit is contained in:
Antonio Juarez 2014-03-20 11:46:11 +00:00
parent 296ae46ed8
commit 8efa1313f3
67 changed files with 1523 additions and 757 deletions

View file

@ -65,12 +65,7 @@ else()
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}")
if(STATIC) if(STATIC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
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()
endif() endif()
endif() endif()
@ -85,6 +80,8 @@ endif()
include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
if(MINGW) if(MINGW)
set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock") set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock")
elseif(NOT MSVC)
set(Boost_LIBRARIES "${Boost_LIBRARIES};rt")
endif() endif()
set(COMMIT_ID_IN_VERSION ON CACHE BOOL "Include commit ID in version") set(COMMIT_ID_IN_VERSION ON CACHE BOOL "Include commit ID in version")

2
README
View file

@ -2,7 +2,7 @@
On *nix: 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: You may download them from:
http://gcc.gnu.org/ http://gcc.gnu.org/
http://www.cmake.org/ http://www.cmake.org/

View file

@ -1,6 +1,6 @@
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net // Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: // modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright // * Redistributions of source code must retain the above copyright
@ -11,7 +11,7 @@
// * Neither the name of the Andrey N. Sabelnikov nor the // * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products // names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission. // derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // 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 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // 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 // 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 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
#pragma once #pragma once
#include <atomic>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
namespace epee 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<bool> 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<class t_server> template<class t_server>
@ -39,124 +210,113 @@ namespace epee
{ {
return true; return true;
} }
template<class t_server, class chain_handler>
bool default_console_handler(t_server* psrv, chain_handler ch_handler, const std::string usage = "") class async_console_handler
{ {
TRY_ENTRY(); public:
bool continue_handle = true; async_console_handler()
while(continue_handle)
{ {
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<class chain_handler> template<class t_server, class chain_handler>
bool default_console_handler2(chain_handler ch_handler, const std::string usage) bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
{
TRY_ENTRY();
bool continue_handle = true;
while(continue_handle)
{ {
char command_buff[400] = {0}; return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); });
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 true;
CATCH_ENTRY_L0("console_handler", false);
}
template<class chain_handler>
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<typename t_cmd_handler, typename t_exit_handler>
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<class t_server, class t_handler> template<class t_server, class t_handler>
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<t_server, t_handler>, ptsrv, handlr, usage) ); std::shared_ptr<async_console_handler> console_handler = std::make_shared<async_console_handler>();
boost::thread(boost::bind(&async_console_handler::run<t_server, t_handler>, console_handler, ptsrv, handlr, prompt, usage)).detach();
return true; return true;
} }
template<class t_server> template<class t_server>
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<t_server>, usage); return start_default_console(ptsrv, empty_commands_handler<t_server>, prompt, usage);
} }
template<class t_server, class t_handler> template<class t_server, class t_handler>
@ -166,15 +326,16 @@ namespace epee
} }
template<class t_server, class t_handler> template<class t_server, class t_handler>
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<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), usage); async_console_handler console_handler;
return console_handler.run(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), prompt, usage);
} }
template<class t_server, class t_handler> template<class t_server, class t_handler>
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<t_server, t_handler>, ptsrv, handlr, usage) ); boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, prompt, usage) );
return true; return true;
} }
@ -209,7 +370,8 @@ namespace epee
typedef std::map<std::string, std::pair<console_command_handler, std::string> > command_handlers_map; typedef std::map<std::string, std::pair<console_command_handler, std::string> > command_handlers_map;
std::unique_ptr<boost::thread> m_console_thread; std::unique_ptr<boost::thread> m_console_thread;
command_handlers_map m_command_handlers; command_handlers_map m_command_handlers;
public: async_console_handler m_console_handler;
public:
std::string get_usage() std::string get_usage()
{ {
std::stringstream ss; std::stringstream ss;
@ -217,7 +379,7 @@ namespace epee
for(auto& x:m_command_handlers) for(auto& x:m_command_handlers)
if(x.first.size() > max_command_len) if(x.first.size() > max_command_len)
max_command_len = x.first.size(); max_command_len = x.first.size();
for(auto& x:m_command_handlers) for(auto& x:m_command_handlers)
{ {
ss.width(max_command_len + 3); 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)); start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1));
return true; 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; return true;
} }
bool stop_handling() void stop_handling()
{ {
if(m_console_thread.get()) m_console_handler.stop();
m_console_thread->interrupt();
return true;
} }
bool run_handling(const std::string& prompt, const std::string& usage_string)
bool run_handling(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<class t_srv> /*template<class t_srv>
@ -280,7 +440,6 @@ namespace epee
{ {
return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string); return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string);
}*/ }*/
}; };
/* work around because of broken boost bind */ /* work around because of broken boost bind */
@ -292,19 +451,23 @@ namespace epee
return console_handlers_binder::process_command_str(cmd); return console_handlers_binder::process_command_str(cmd);
} }
public: 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<t_server>::run_handling, this, psrv, usage_string) ); boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
return true; 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<t_server>::process_command_str, this, _1, _2), usage_string); return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), prompt, usage_string);
} }
void stop_handling()
{
m_console_handler.stop();
}
private:
async_console_handler m_console_handler;
}; };
} }

View file

@ -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 <atomic>
namespace epee
{
class copyable_atomic: public std::atomic<uint32_t>
{
public:
copyable_atomic()
{};
copyable_atomic(const copyable_atomic& a):std::atomic<uint32_t>(a.load())
{}
copyable_atomic& operator= (const copyable_atomic& a)
{
store(a.load());
return *this;
}
uint32_t operator++()
{
return std::atomic<uint32_t>::operator++();
}
uint32_t operator++(int fake)
{
return std::atomic<uint32_t>::operator++(fake);
}
};
}

View file

@ -154,7 +154,7 @@ namespace math_helper
#endif #endif
//#ifdef WINDOWS_PLATFORM_EX //#ifdef WINDOWS_PLATFORM_EX
template<boost::uint64_t default_time_window> template<uint64_t default_time_window>
class speed class speed
{ {
public: public:
@ -167,7 +167,7 @@ namespace math_helper
bool chick() bool chick()
{ {
#ifndef DEBUG_STUB #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); CRITICAL_REGION_BEGIN(m_lock);
m_chicks.push_back(ticks); m_chicks.push_back(ticks);
CRITICAL_REGION_END(); CRITICAL_REGION_END();
@ -192,10 +192,10 @@ namespace math_helper
} }
private: private:
bool flush(boost::uint64_t ticks) bool flush(uint64_t ticks)
{ {
CRITICAL_REGION_BEGIN(m_lock); CRITICAL_REGION_BEGIN(m_lock);
std::list<boost::uint64_t>::iterator it = m_chicks.begin(); std::list<uint64_t>::iterator it = m_chicks.begin();
while(it != m_chicks.end()) while(it != m_chicks.end())
{ {
if(*it + m_time_window < ticks) if(*it + m_time_window < ticks)
@ -207,8 +207,8 @@ namespace math_helper
return true; return true;
} }
std::list<boost::uint64_t> m_chicks; std::list<uint64_t> m_chicks;
boost::uint64_t m_time_window; uint64_t m_time_window;
size_t m_last_speed_value; size_t m_last_speed_value;
critical_section m_lock; critical_section m_lock;
}; };

View file

@ -29,6 +29,7 @@
#define _MISC_LOG_EX_H_ #define _MISC_LOG_EX_H_
//#include <windows.h> //#include <windows.h>
#include <atomic>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -43,17 +44,20 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#if defined(WIN32)
#include <io.h>
#else
#include <unistd.h>
#endif
#include "static_initializer.h" #include "static_initializer.h"
#include "string_tools.h" #include "string_tools.h"
#include "time_helper.h" #include "time_helper.h"
#include "misc_os_dependent.h" #include "misc_os_dependent.h"
#include "syncobj.h" #include "syncobj.h"
#define LOG_LEVEL_SILENT -1 #define LOG_LEVEL_SILENT -1
#define LOG_LEVEL_0 0 #define LOG_LEVEL_0 0
#define LOG_LEVEL_1 1 #define LOG_LEVEL_1 1
@ -64,8 +68,6 @@
#define LOG_LEVEL_MAX LOG_LEVEL_4 #define LOG_LEVEL_MAX LOG_LEVEL_4
#define LOGGER_NULL 0 #define LOGGER_NULL 0
#define LOGGER_FILE 1 #define LOGGER_FILE 1
#define LOGGER_DEBUGGER 2 #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 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 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;}; virtual bool set_log_rotate_cmd(const std::string& cmd){return true;};
}; };
@ -198,8 +200,29 @@ namespace log_space
}; };
#endif #endif
inline bool is_stdout_a_tty()
{
static std::atomic<bool> initialized(false);
static std::atomic<bool> 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) inline void set_console_color(int color, bool bright)
{ {
if (!is_stdout_a_tty())
return;
switch(color) switch(color)
{ {
case console_color_default: case console_color_default:
@ -315,11 +338,15 @@ namespace log_space
} }
inline void reset_console_color() { inline void reset_console_color() {
if (!is_stdout_a_tty())
return;
#ifdef WIN32 #ifdef WIN32
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
#else #else
std::cout << "\033[0m"; std::cout << "\033[0m";
std::cout.flush();
#endif #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); //::WriteConsoleA(::GetStdHandle(STD_OUTPUT_HANDLE), ptarget_buf, buffer_len, (DWORD*)&b, 0);
std::cout << ptarget_buf; std::cout << ptarget_buf;
if(pallocated_buf) delete [] pallocated_buf; if(pallocated_buf) delete [] pallocated_buf;
@ -459,7 +486,7 @@ namespace log_space
std::ofstream* m_pdefault_file_stream; std::ofstream* m_pdefault_file_stream;
std::string m_log_rotate_cmd; std::string m_log_rotate_cmd;
std::string m_default_log_filename; 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) std::ofstream* add_new_stream_and_open(const char* pstream_name)
@ -474,7 +501,7 @@ namespace log_space
return pstream; 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; m_max_logfile_size = max_size;
return true; return true;
@ -508,7 +535,7 @@ namespace log_space
if(m_max_logfile_size) if(m_max_logfile_size)
{ {
std::ofstream::pos_type pt = m_target_file_stream->tellp(); 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) if(current_sz > m_max_logfile_size)
{ {
std::cout << "current_sz= " << current_sz << " m_max_logfile_size= " << m_max_logfile_size << std::endl; 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()); 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++) for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++)
it->first->set_max_logfile_size(max_size); 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); CRITICAL_REGION_BEGIN(m_critical_sec);
m_log_target.set_max_logfile_size(max_size); m_log_target.set_max_logfile_size(max_size);
@ -895,7 +922,7 @@ namespace log_space
return res; 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(); logger* plogger = get_or_create_instance();
if(!plogger) return false; if(!plogger) return false;
@ -1004,9 +1031,9 @@ POP_WARNINGS
return is_need; 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) if(is_need_set)
err_count = err_val; err_count = err_val;

View file

@ -48,7 +48,7 @@ namespace epee
namespace misc_utils namespace misc_utils
{ {
inline boost::uint64_t get_tick_count() inline uint64_t get_tick_count()
{ {
#if defined(_MSC_VER) #if defined(_MSC_VER)
return ::GetTickCount64(); return ::GetTickCount64();

View file

@ -57,7 +57,7 @@ namespace net_utils
struct i_connection_filter 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: protected:
virtual ~i_connection_filter(){} virtual ~i_connection_filter(){}
}; };
@ -76,7 +76,7 @@ namespace net_utils
typedef typename t_protocol_handler::connection_context t_connection_context; typedef typename t_protocol_handler::connection_context t_connection_context;
/// Construct a connection with the given io_service. /// Construct a connection with the given io_service.
explicit connection(boost::asio::io_service& 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(); virtual ~connection();
/// Get the socket associated with the connection. /// Get the socket associated with the connection.
@ -117,11 +117,11 @@ namespace net_utils
boost::array<char, 8192> buffer_; boost::array<char, 8192> buffer_;
t_connection_context context; t_connection_context context;
volatile boost::uint32_t m_want_close_connection; volatile uint32_t m_want_close_connection;
std::atomic<bool> m_was_shutdown; std::atomic<bool> m_was_shutdown;
critical_section m_send_que_lock; critical_section m_send_que_lock;
std::list<std::string> m_send_que; std::list<std::string> m_send_que;
volatile boost::uint32_t& m_ref_sockets_count; volatile uint32_t& m_ref_sockets_count;
i_connection_filter* &m_pfilter; i_connection_filter* &m_pfilter;
volatile bool m_is_multithreaded; volatile bool m_is_multithreaded;
@ -156,7 +156,7 @@ namespace net_utils
bool run_server(size_t threads_count, bool wait = true); bool run_server(size_t threads_count, bool wait = true);
/// wait for service workers stop /// 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. /// Stop the server.
void send_stop_signal(); void send_stop_signal();
@ -171,9 +171,9 @@ namespace net_utils
void set_connection_filter(i_connection_filter* pfilter); 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<class t_callback> template<class t_callback>
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;} typename t_protocol_handler::config_type& get_config_object(){return m_config;}
@ -191,13 +191,13 @@ namespace net_utils
m_timer(io_serice) m_timer(io_serice)
{} {}
boost::asio::deadline_timer m_timer; boost::asio::deadline_timer m_timer;
boost::uint64_t m_period; uint64_t m_period;
}; };
template <class t_handler> template <class t_handler>
struct idle_callback_conext: public idle_callback_conext_base 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), idle_callback_conext_base(io_serice),
m_handler(h) m_handler(h)
{this->m_period = period;} {this->m_period = period;}
@ -210,7 +210,7 @@ namespace net_utils
}; };
template<class t_handler> template<class t_handler>
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<idle_callback_conext_base> ptr(new idle_callback_conext<t_handler>(io_service_, t_callback, timeout_ms)); boost::shared_ptr<idle_callback_conext_base> ptr(new idle_callback_conext<t_handler>(io_service_, t_callback, timeout_ms));
//needed call handler here ?... //needed call handler here ?...
@ -258,7 +258,7 @@ namespace net_utils
connection_ptr new_connection_; connection_ptr new_connection_;
std::atomic<bool> m_stop_signal_sent; std::atomic<bool> m_stop_signal_sent;
uint32_t m_port; uint32_t m_port;
volatile boost::uint32_t m_sockets_count; volatile uint32_t m_sockets_count;
std::string m_address; std::string m_address;
std::string m_thread_name_prefix; std::string m_thread_name_prefix;
size_t m_threads_count; size_t m_threads_count;

View file

@ -49,10 +49,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
template<class t_protocol_handler> template<class t_protocol_handler>
connection<t_protocol_handler>::connection(boost::asio::io_service& io_service, connection<t_protocol_handler>::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), : strand_(io_service),
socket_(io_service), socket_(io_service),
//context(typename boost::value_initialized<t_connection_context>())
m_protocol_handler(this, config, context), m_protocol_handler(this, config, context),
m_want_close_connection(0), m_want_close_connection(0),
m_was_shutdown(0), m_was_shutdown(0),
@ -217,6 +216,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
if (!e) if (!e)
{ {
LOG_PRINT("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred, LOG_LEVEL_4); 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); bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred);
if(!recv_res) if(!recv_res)
{ {
@ -294,6 +295,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
return false; return false;
LOG_PRINT("[sock " << socket_.native_handle() << "] SEND " << cb, LOG_LEVEL_4); 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 //some data should be wrote to stream
//request complete //request complete
@ -473,8 +476,8 @@ DISABLE_GCC_WARNING(maybe-uninitialized)
uint32_t p = 0; uint32_t p = 0;
if (port.size() && !string_tools::get_xtype_from_string(p, port)) { if (port.size() && !string_tools::get_xtype_from_string(p, port)) {
LOG_ERROR("Failed to convert port no = " << port);
return false; return false;
LOG_ERROR("Failed to convert port no = port");
} }
return this->init_server(p, address); return this->init_server(p, address);
} }
@ -586,7 +589,7 @@ POP_WARNINGS
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
template<class t_protocol_handler> template<class t_protocol_handler>
bool boosted_tcp_server<t_protocol_handler>::timed_wait_server_stop(boost::uint64_t wait_mseconds) bool boosted_tcp_server<t_protocol_handler>::timed_wait_server_stop(uint64_t wait_mseconds)
{ {
TRY_ENTRY(); TRY_ENTRY();
boost::chrono::milliseconds ms(wait_mseconds); boost::chrono::milliseconds ms(wait_mseconds);
@ -641,7 +644,7 @@ POP_WARNINGS
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
template<class t_protocol_handler> template<class t_protocol_handler>
bool boosted_tcp_server<t_protocol_handler>::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<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip)
{ {
TRY_ENTRY(); TRY_ENTRY();
@ -732,7 +735,7 @@ POP_WARNINGS
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
template<class t_protocol_handler> template<class t_callback> template<class t_protocol_handler> template<class t_callback>
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, boost::uint32_t conn_timeout, t_callback cb, const std::string& bind_ip) bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_callback cb, const std::string& bind_ip)
{ {
TRY_ENTRY(); TRY_ENTRY();
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sockets_count, m_pfilter) ); connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sockets_count, m_pfilter) );

View file

@ -127,7 +127,7 @@ namespace net_utils
std::string schema; std::string schema;
std::string host; std::string host;
std::string uri; std::string uri;
boost::uint64_t port; uint64_t port;
uri_content m_uri_content; uri_content m_uri_content;
}; };

View file

@ -55,10 +55,11 @@ namespace net_utils
/************************************************************************/ /************************************************************************/
/* */ /* */
/************************************************************************/ /************************************************************************/
template<class t_connection_context = net_utils::connection_context_base>
class simple_http_connection_handler class simple_http_connection_handler
{ {
public: 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; typedef http_server_config config_type;
simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config); 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; i_service_endpoint* m_psnd_hndlr;
}; };
template<class t_connection_context>
struct i_http_server_handler struct i_http_server_handler
{ {
virtual ~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 init_server_thread(){return true;}
virtual bool deinit_server_thread(){return true;} virtual bool deinit_server_thread(){return true;}
}; };
template<class t_connection_context>
struct custum_handler_config: public http_server_config struct custum_handler_config: public http_server_config
{ {
i_http_server_handler* m_phandler; i_http_server_handler<t_connection_context>* m_phandler;
}; };
/************************************************************************/ /************************************************************************/
/* */ /* */
/************************************************************************/ /************************************************************************/
class http_custom_handler: public simple_http_connection_handler
template<class t_connection_context = net_utils::connection_context_base>
class http_custom_handler: public simple_http_connection_handler<t_connection_context>
{ {
public: public:
typedef custum_handler_config config_type; typedef custum_handler_config<t_connection_context> 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<t_connection_context>(psnd_hndlr, config),
m_config(config), m_config(config),
m_conn_context(conn_context) m_conn_context(conn_context)
{} {}
@ -198,7 +201,7 @@ namespace net_utils
private: private:
//simple_http_connection_handler::config_type m_stub_config; //simple_http_connection_handler::config_type m_stub_config;
config_type& m_config; config_type& m_config;
const net_utils::connection_context_base& m_conn_context; t_connection_context& m_conn_context;
}; };
} }
} }

View file

@ -191,8 +191,8 @@ namespace net_utils
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
inline template<class t_connection_context>
simple_http_connection_handler::simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config): simple_http_connection_handler<t_connection_context>::simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config):
m_state(http_state_retriving_comand_line), m_state(http_state_retriving_comand_line),
m_body_transfer_type(http_body_transfer_undefined), m_body_transfer_type(http_body_transfer_undefined),
m_is_stop_handling(false), m_is_stop_handling(false),
@ -205,7 +205,8 @@ namespace net_utils
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
inline bool simple_http_connection_handler::set_ready_state() template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::set_ready_state()
{ {
m_is_stop_handling = false; m_is_stop_handling = false;
m_state = http_state_retriving_comand_line; m_state = http_state_retriving_comand_line;
@ -215,7 +216,8 @@ namespace net_utils
return true; return true;
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
inline bool simple_http_connection_handler::handle_recv(const void* ptr, size_t cb) template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::handle_recv(const void* ptr, size_t cb)
{ {
std::string buf((const char*)ptr, cb); std::string buf((const char*)ptr, cb);
//LOG_PRINT_L0("HTTP_RECV: " << ptr << "\r\n" << buf); //LOG_PRINT_L0("HTTP_RECV: " << ptr << "\r\n" << buf);
@ -227,7 +229,8 @@ namespace net_utils
return res; return res;
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
inline bool simple_http_connection_handler::handle_buff_in(std::string& buf) template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::handle_buff_in(std::string& buf)
{ {
if(m_cache.size()) if(m_cache.size())
@ -324,9 +327,10 @@ namespace net_utils
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
inline bool simple_http_connection_handler::handle_invoke_query_line() template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::handle_invoke_query_line()
{ {
LOG_FRAME("simple_http_connection_handler::handle_recognize_protocol_out(*)", LOG_LEVEL_3); LOG_FRAME("simple_http_connection_handler<t_connection_context>::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); 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 // 123 4 5 6 7 8 9 10 11 12
@ -348,14 +352,15 @@ namespace net_utils
}else }else
{ {
m_state = http_state_error; 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<t_connection_context>::handle_invoke_query_line(): Failed to match first line: " << m_cache);
return false; return false;
} }
return false; return false;
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
inline std::string::size_type simple_http_connection_handler::match_end_of_header(const std::string& buf) template<class t_connection_context>
std::string::size_type simple_http_connection_handler<t_connection_context>::match_end_of_header(const std::string& buf)
{ {
//Here we returning head size, including terminating sequence (\r\n\r\n or \n\n) //Here we returning head size, including terminating sequence (\r\n\r\n or \n\n)
@ -368,18 +373,19 @@ namespace net_utils
return res; return res;
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
inline bool simple_http_connection_handler::analize_cached_request_header_and_invoke_state(size_t pos) template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(size_t pos)
{ {
//LOG_PRINT_L4("HTTP HEAD:\r\n" << m_cache.substr(0, 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<t_connection_context>::analize_cached_request_header_and_invoke_state(*)", LOG_LEVEL_3);
m_query_info.m_full_request_buf_size = pos; m_query_info.m_full_request_buf_size = pos;
m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+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)) 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<t_connection_context>::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache);
m_state = http_state_error; m_state = http_state_error;
} }
@ -394,7 +400,7 @@ namespace net_utils
m_body_transfer_type = http_body_transfer_measure; 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)) 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="<<m_query_info.m_header_info.m_content_length); LOG_ERROR("simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<<m_query_info.m_header_info.m_content_length);
m_state = http_state_error; m_state = http_state_error;
return false; return false;
} }
@ -415,7 +421,8 @@ namespace net_utils
return true; return true;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
inline bool simple_http_connection_handler::handle_retriving_query_body() template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::handle_retriving_query_body()
{ {
switch(m_body_transfer_type) switch(m_body_transfer_type)
{ {
@ -426,7 +433,7 @@ namespace net_utils
case http_body_transfer_multipart: case http_body_transfer_multipart:
case http_body_transfer_undefined: case http_body_transfer_undefined:
default: 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<t_connection_context>::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type);
m_state = http_state_error; m_state = http_state_error;
return false; return false;
} }
@ -434,7 +441,8 @@ namespace net_utils
return true; return true;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
inline bool simple_http_connection_handler::handle_query_measure() template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::handle_query_measure()
{ {
if(m_len_remain >= m_cache.size()) if(m_len_remain >= m_cache.size())
@ -459,7 +467,8 @@ namespace net_utils
return true; 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<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::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); 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<std::string, std::string>(result[field_etc_name], result[field_val])); body_info.m_etc_fields.push_back(std::pair<std::string, std::string>(result[field_etc_name], result[field_val]));
else else
{ {
LOG_ERROR("simple_http_connection_handler::parse_cached_header() not matched last entry in:"<<m_cache_to_process); LOG_ERROR("simple_http_connection_handler<t_connection_context>::parse_cached_header() not matched last entry in:"<<m_cache_to_process);
} }
it_current_bound = result[(int)result.size()-1]. first; it_current_bound = result[(int)result.size()-1]. first;
@ -511,7 +520,8 @@ namespace net_utils
return true; return true;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
inline bool simple_http_connection_handler::get_len_from_content_lenght(const std::string& str, size_t& OUT len) template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::get_len_from_content_lenght(const std::string& str, size_t& OUT len)
{ {
STATIC_REGEXP_EXPR_1(rexp_mach_field, "\\d+", boost::regex::normal); STATIC_REGEXP_EXPR_1(rexp_mach_field, "\\d+", boost::regex::normal);
std::string res; std::string res;
@ -523,7 +533,8 @@ namespace net_utils
return true; return true;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
inline bool simple_http_connection_handler::handle_request_and_send_response(const http::http_request_info& query_info) template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::handle_request_and_send_response(const http::http_request_info& query_info)
{ {
http_response_info response; http_response_info response;
bool res = handle_request(query_info, response); bool res = handle_request(query_info, response);
@ -540,7 +551,8 @@ namespace net_utils
return res; return res;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
inline bool simple_http_connection_handler::handle_request(const http::http_request_info& query_info, http_response_info& response) template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::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; std::string uri_to_path = query_info.m_uri_content.m_path;
@ -570,7 +582,8 @@ namespace net_utils
return true; return true;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
inline std::string simple_http_connection_handler::get_response_header(const http_response_info& response) template<class t_connection_context>
std::string simple_http_connection_handler<t_connection_context>::get_response_header(const http_response_info& response)
{ {
std::string buf = "HTTP/1.1 "; std::string buf = "HTTP/1.1 ";
buf += boost::lexical_cast<std::string>(response.m_response_code) + " " + response.m_response_comment + "\r\n" + buf += boost::lexical_cast<std::string>(response.m_response_code) + " " + response.m_response_comment + "\r\n" +
@ -607,7 +620,8 @@ namespace net_utils
return buf; return buf;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
inline std::string simple_http_connection_handler::get_file_mime_tipe(const std::string& path) template<class t_connection_context>
std::string simple_http_connection_handler<t_connection_context>::get_file_mime_tipe(const std::string& path)
{ {
std::string result; std::string result;
std::string ext = string_tools::get_extension(path); std::string ext = string_tools::get_extension(path);
@ -632,7 +646,8 @@ namespace net_utils
return result; return result;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
inline std::string simple_http_connection_handler::get_not_found_response_body(const std::string& URI) template<class t_connection_context>
std::string simple_http_connection_handler<t_connection_context>::get_not_found_response_body(const std::string& URI)
{ {
std::string body = std::string body =
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
@ -648,7 +663,8 @@ namespace net_utils
return body; return body;
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
inline bool simple_http_connection_handler::slash_to_back_slash(std::string& str) template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::slash_to_back_slash(std::string& str)
{ {
for(std::string::iterator it = str.begin(); it!=str.end(); it++) for(std::string::iterator it = str.begin(); it!=str.end(); it++)
if('/' == *it) if('/' == *it)

View file

@ -36,8 +36,8 @@ namespace epee
{ {
namespace net_utils namespace net_utils
{ {
typedef boosted_tcp_server<http::simple_http_connection_handler> boosted_http_server_file_system; typedef boosted_tcp_server<http::simple_http_connection_handler<> > boosted_http_server_file_system;
typedef boosted_tcp_server<http::http_custom_handler> boosted_http_server_custum_handling; typedef boosted_tcp_server<http::http_custom_handler<> > boosted_http_server_custum_handling;
} }
} }

View file

@ -31,9 +31,9 @@
#include "http_base.h" #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, \ 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); \ 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; \ 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<class t_context> bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response_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; \ bool handled = false; \
if(false) return true; //just a stub to have "else if" if(false) return true; //just a stub to have "else if"
@ -58,22 +58,22 @@
else if(query_info.m_URI == s_pattern) \ else if(query_info.m_URI == s_pattern) \
{ \ { \
handled = true; \ handled = true; \
boost::uint64_t ticks = misc_utils::get_tick_count(); \ uint64_t ticks = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \ boost::value_initialized<command_type::request> req; \
bool parse_res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \ bool parse_res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse json: \r\n" << 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<command_type::response> resp;\ boost::value_initialized<command_type::response> resp;\
if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp))) \ if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), m_conn_context)) \
{ \ { \
LOG_ERROR("Failed to " << #callback_f << "()"); \ LOG_ERROR("Failed to " << #callback_f << "()"); \
response_info.m_response_code = 500; \ response_info.m_response_code = 500; \
response_info.m_response_comment = "Internal Server Error"; \ response_info.m_response_comment = "Internal Server Error"; \
return true; \ 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<command_type::response&>(resp), response_info.m_body); \ epee::serialization::store_t_to_json(static_cast<command_type::response&>(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_mime_tipe = "application/json"; \
response_info.m_header_info.m_content_type = " 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); \ 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) \ else if(query_info.m_URI == s_pattern) \
{ \ { \
handled = true; \ handled = true; \
boost::uint64_t ticks = misc_utils::get_tick_count(); \ uint64_t ticks = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \ boost::value_initialized<command_type::request> req; \
bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), query_info.m_body); \ bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(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()); \ 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<command_type::response> resp;\ boost::value_initialized<command_type::response> resp;\
if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp))) \ if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), m_conn_context)) \
{ \ { \
LOG_ERROR("Failed to " << #callback_f << "()"); \ LOG_ERROR("Failed to " << #callback_f << "()"); \
response_info.m_response_code = 500; \ response_info.m_response_code = 500; \
response_info.m_response_comment = "Internal Server Error"; \ response_info.m_response_comment = "Internal Server Error"; \
return true; \ 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<command_type::response&>(resp), response_info.m_body); \ epee::serialization::store_t_to_binary(static_cast<command_type::response&>(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_mime_tipe = " application/octet-stream"; \
response_info.m_header_info.m_content_type = " 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); \ 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) \ #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; \ epee::serialization::portable_storage ps; \
if(!ps.load_from_json(query_info.m_body)) \ if(!ps.load_from_json(query_info.m_body)) \
{ \ { \
@ -198,20 +198,20 @@ namespace epee
boost::value_initialized<epee::json_rpc::request<command_type::request> > req_; \ boost::value_initialized<epee::json_rpc::request<command_type::request> > req_; \
epee::json_rpc::request<command_type::request>& req = static_cast<epee::json_rpc::request<command_type::request>&>(req_);\ epee::json_rpc::request<command_type::request>& req = static_cast<epee::json_rpc::request<command_type::request>&>(req_);\
req.load(ps); \ 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<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \ boost::value_initialized<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \
epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp = static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \ epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp = static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \
resp.id = req.id; \ resp.id = req.id; \
epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
fail_resp.id = req.id; \ 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<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \ epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
return true; \ 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); \ 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_mime_tipe = "application/json"; \
response_info.m_header_info.m_content_type = " 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); \ 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<epee::json_rpc::request<command_type::request> > req_; \ boost::value_initialized<epee::json_rpc::request<command_type::request> > req_; \
epee::json_rpc::request<command_type::request>& req = static_cast<epee::json_rpc::request<command_type::request>&>(req_);\ epee::json_rpc::request<command_type::request>& req = static_cast<epee::json_rpc::request<command_type::request>&>(req_);\
req.load(ps); \ 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<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \ boost::value_initialized<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \
epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp = static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \ epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp = static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \
resp.id = req.id; \ 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); \ epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
fail_resp.id = req.id; \ fail_resp.id = req.id; \
@ -239,9 +239,9 @@ namespace epee
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \ epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
return true; \ 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); \ 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_mime_tipe = "application/json"; \
response_info.m_header_info.m_content_type = " 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); \ LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \

View file

@ -39,8 +39,8 @@
namespace epee namespace epee
{ {
template<class t_child_class> template<class t_child_class, class t_connection_context = epee::net_utils::connection_context_base>
class http_server_impl_base: public net_utils::http::i_http_server_handler class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>
{ {
public: public:
@ -107,6 +107,6 @@ namespace epee
} }
protected: protected:
net_utils::boosted_http_server_custum_handling m_net_server; net_utils::boosted_tcp_server<net_utils::http::http_custom_handler<t_connection_context> > m_net_server;
}; };
} }

View file

@ -41,13 +41,13 @@ namespace levin
#pragma pack(1) #pragma pack(1)
struct bucket_head struct bucket_head
{ {
boost::uint64_t m_signature; uint64_t m_signature;
boost::uint64_t m_cb; uint64_t m_cb;
bool m_have_to_return_data; bool m_have_to_return_data;
boost::uint32_t m_command; uint32_t m_command;
boost::int32_t m_return_code; int32_t m_return_code;
boost::uint32_t m_reservedA; //probably some flags in future uint32_t m_reservedA; //probably some flags in future
boost::uint32_t m_reservedB; //probably some check sum in future uint32_t m_reservedB; //probably some check sum in future
}; };
#pragma pack(pop) #pragma pack(pop)
@ -56,13 +56,13 @@ namespace levin
#pragma pack(1) #pragma pack(1)
struct bucket_head2 struct bucket_head2
{ {
boost::uint64_t m_signature; uint64_t m_signature;
boost::uint64_t m_cb; uint64_t m_cb;
bool m_have_to_return_data; bool m_have_to_return_data;
boost::uint32_t m_command; uint32_t m_command;
boost::int32_t m_return_code; int32_t m_return_code;
boost::uint32_t m_flags; uint32_t m_flags;
boost::uint32_t m_protocol_version; uint32_t m_protocol_version;
}; };
#pragma pack(pop) #pragma pack(pop)

View file

@ -49,16 +49,16 @@ namespace levin
class levin_client_async class levin_client_async
{ {
levin_commands_handler* m_pcommands_handler; levin_commands_handler* m_pcommands_handler;
volatile boost::uint32_t m_is_stop; volatile uint32_t m_is_stop;
volatile boost::uint32_t m_threads_count; volatile uint32_t m_threads_count;
::critical_section m_send_lock; ::critical_section m_send_lock;
std::string m_local_invoke_buff; std::string m_local_invoke_buff;
::critical_section m_local_invoke_buff_lock; ::critical_section m_local_invoke_buff_lock;
volatile int m_invoke_res; volatile int m_invoke_res;
volatile boost::uint32_t m_invoke_data_ready; volatile uint32_t m_invoke_data_ready;
volatile boost::uint32_t m_invoke_is_active; volatile uint32_t m_invoke_is_active;
boost::mutex m_invoke_event; boost::mutex m_invoke_event;
boost::condition_variable m_invoke_cond; boost::condition_variable m_invoke_cond;
@ -69,14 +69,14 @@ namespace levin
{ {
bucket_head m_hd; bucket_head m_hd;
std::string m_body; std::string m_body;
boost::uint32_t m_connection_index; uint32_t m_connection_index;
}; };
std::list<packet_entry> m_recieved_packets; std::list<packet_entry> m_recieved_packets;
/* /*
m_current_connection_index needed when some connection was broken and reconnected - in this 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 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_invoke_lock;
::critical_section m_reciev_packet_lock; ::critical_section m_reciev_packet_lock;
::critical_section m_connection_lock; ::critical_section m_connection_lock;
@ -101,7 +101,7 @@ namespace levin
m_pcommands_handler = phandler; 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(); loop_call_guard();
critical_region cr(m_connection_lock); critical_region cr(m_connection_lock);
@ -388,7 +388,7 @@ namespace levin
bool reciev_and_process_incoming_data() bool reciev_and_process_incoming_data()
{ {
bucket_head head = {0}; bucket_head head = {0};
boost::uint32_t conn_index = 0; uint32_t conn_index = 0;
bool is_request = false; bool is_request = false;
std::string local_buff; std::string local_buff;
CRITICAL_REGION_BEGIN(m_reciev_packet_lock);//to protect from socket reconnect between head and body CRITICAL_REGION_BEGIN(m_reciev_packet_lock);//to protect from socket reconnect between head and body
@ -485,7 +485,7 @@ namespace levin
return true; 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; net_utils::connection_context_base conn_context;
@ -544,7 +544,7 @@ namespace levin
bool have_some_work = false; bool have_some_work = false;
std::string local_buff; std::string local_buff;
bucket_head bh = {0}; bucket_head bh = {0};
boost::uint32_t conn_index = 0; uint32_t conn_index = 0;
CRITICAL_REGION_BEGIN(m_recieved_packets_lock); CRITICAL_REGION_BEGIN(m_recieved_packets_lock);
if(m_recieved_packets.size()) if(m_recieved_packets.size())

View file

@ -98,7 +98,7 @@ namespace levin
case conn_state_reading_head: case conn_state_reading_head:
if(m_cach_in_buffer.size() < sizeof(bucket_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"); LOG_ERROR("Signature missmatch on accepted connection");
return false; return false;

View file

@ -64,8 +64,8 @@ class async_protocol_handler_config
public: public:
typedef t_connection_context connection_context; typedef t_connection_context connection_context;
levin_commands_handler<t_connection_context>* m_pcommands_handler; levin_commands_handler<t_connection_context>* m_pcommands_handler;
boost::uint64_t m_max_packet_size; uint64_t m_max_packet_size;
boost::uint64_t m_invoke_timeout; uint64_t m_invoke_timeout;
int invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id); int invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id);
template<class callback_t> template<class callback_t>
@ -122,7 +122,7 @@ public:
std::string m_cache_in_buffer; std::string m_cache_in_buffer;
stream_state m_state; stream_state m_state;
boost::int32_t m_oponent_protocol_ver; int32_t m_oponent_protocol_ver;
bool m_connection_initialized; bool m_connection_initialized;
struct invoke_response_handler_base 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(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"); LOG_ERROR_CC(m_connection_context, "Signature mismatch, connection will be closed");
return false; return false;

View file

@ -32,7 +32,7 @@ namespace epee
namespace net_utils namespace net_utils
{ {
inline inline
bool is_ip_local(boost::uint32_t ip) bool is_ip_local(uint32_t ip)
{ {
/* /*
local ip area local ip area
@ -55,7 +55,7 @@ namespace epee
return false; return false;
} }
inline inline
bool is_ip_loopback(boost::uint32_t ip) bool is_ip_loopback(uint32_t ip)
{ {
if( (ip | 0xffffff00) == 0xffffff7f) if( (ip | 0xffffff00) == 0xffffff7f)
return true; return true;

View file

@ -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 try
@ -564,7 +564,7 @@ namespace net_utils
bool m_initialized; bool m_initialized;
bool m_connected; bool m_connected;
boost::asio::deadline_timer m_deadline; boost::asio::deadline_timer m_deadline;
volatile boost::uint32_t m_shutdowned; volatile uint32_t m_shutdowned;
}; };

View file

@ -153,7 +153,7 @@ namespace net_utils
} }
if(result[6].matched) if(result[6].matched)
{ {
content.port = boost::lexical_cast<boost::uint64_t>(result[6]); content.port = boost::lexical_cast<uint64_t>(result[6]);
} }
if(result[7].matched) if(result[7].matched)
{ {

View file

@ -47,23 +47,36 @@ namespace net_utils
struct connection_context_base struct connection_context_base
{ {
const boost::uuids::uuid m_connection_id; const boost::uuids::uuid m_connection_id;
const boost::uint32_t m_remote_ip; const uint32_t m_remote_ip;
const boost::uint32_t m_remote_port; const uint32_t m_remote_port;
const bool m_is_income; 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_connection_id(connection_id),
m_remote_ip(remote_ip), m_remote_ip(remote_ip),
m_remote_port(remote_port), 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(), connection_context_base(): m_connection_id(),
m_remote_ip(0), m_remote_ip(0),
m_remote_port(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) connection_context_base& operator=(const connection_context_base& a)

View file

@ -95,10 +95,10 @@ namespace net_utils
else else
{ {
m_cached_buff.append((const char*)ptr, cb); 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; 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; pcurrent_handler = &m_levin_handler;
return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size()); return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size());

View file

@ -51,12 +51,12 @@ namespace epee
#define PROFILE_FUNC_THIRD(immortal_ptr_str) #define PROFILE_FUNC_THIRD(immortal_ptr_str)
#endif #endif
#define START_WAY_POINTS() boost::uint64_t _____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) {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_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) {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 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; #define TIME_MEASURE_FINISH(var_name) var_name = misc_utils::get_tick_count() - var_name;
namespace profile_tools namespace profile_tools
@ -71,7 +71,7 @@ namespace profile_tools
} }
size_t m_count_of_call; size_t m_count_of_call;
boost::uint64_t m_summary_time_used; uint64_t m_summary_time_used;
const char* m_pname; 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::ptime now_t(boost::posix_time::microsec_clock::local_time());
boost::posix_time::time_duration delta_microsec = now_t - m_call_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); //::QueryPerformanceCounter((LARGE_INTEGER *)&ret_time);
//m_call_time = (ret_time-m_call_time)/1000; //m_call_time = (ret_time-m_call_time)/1000;

View file

@ -45,8 +45,8 @@ namespace epee
const static global_regexp_critical_section gregexplock; const static global_regexp_critical_section gregexplock;
#define STATIC_REGEXP_EXPR_1(var_name, xpr_text, reg_exp_flags) \ #define STATIC_REGEXP_EXPR_1(var_name, xpr_text, reg_exp_flags) \
static volatile boost::uint32_t regexp_initialized_1 = 0;\ static volatile uint32_t regexp_initialized_1 = 0;\
volatile boost::uint32_t local_is_initialized_1 = regexp_initialized_1;\ volatile uint32_t local_is_initialized_1 = regexp_initialized_1;\
if(!local_is_initialized_1)\ if(!local_is_initialized_1)\
gregexplock.get_lock().lock();\ gregexplock.get_lock().lock();\
static const boost::regex var_name(xpr_text , reg_exp_flags);\ 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) \ #define STATIC_REGEXP_EXPR_2(var_name, xpr_text, reg_exp_flags) \
static volatile boost::uint32_t regexp_initialized_2 = 0;\ static volatile uint32_t regexp_initialized_2 = 0;\
volatile boost::uint32_t local_is_initialized_2 = regexp_initialized_2;\ volatile uint32_t local_is_initialized_2 = regexp_initialized_2;\
if(!local_is_initialized_2)\ if(!local_is_initialized_2)\
gregexplock.get_lock().lock().lock();\ gregexplock.get_lock().lock().lock();\
static const boost::regex var_name(xpr_text , reg_exp_flags);\ 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) \ #define STATIC_REGEXP_EXPR_3(var_name, xpr_text, reg_exp_flags) \
static volatile boost::uint32_t regexp_initialized_3 = 0;\ static volatile uint32_t regexp_initialized_3 = 0;\
volatile boost::uint32_t local_is_initialized_3 = regexp_initialized_3;\ volatile uint32_t local_is_initialized_3 = regexp_initialized_3;\
if(!local_is_initialized_3)\ if(!local_is_initialized_3)\
gregexplock.get_lock().lock().lock();\ gregexplock.get_lock().lock().lock();\
static const boost::regex var_name(xpr_text , reg_exp_flags);\ static const boost::regex var_name(xpr_text , reg_exp_flags);\

View file

@ -34,22 +34,22 @@ namespace soci
{ {
template <> template <>
struct type_conversion<boost::uint64_t> struct type_conversion<uint64_t>
{ {
typedef long long base_type; 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) if (ind == i_null)
{ {
mi = 0; mi = 0;
//throw soci_error("Null value not allowed for this type"); //throw soci_error("Null value not allowed for this type");
} }
mi = (boost::uint64_t)a_; mi = (uint64_t)a_;
//mi.set(i); //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; i = (base_type)mi;
ind = i_ok; ind = i_ok;

View file

@ -281,7 +281,7 @@ namespace epee
bool insert_res = false; bool insert_res = false;
if(!is_v_float) if(!is_v_float)
{ {
boost::int64_t nval = boost::lexical_cast<int64_t>(val); //bool res = string_tools::string_to_num_fast(val, nval); int64_t nval = boost::lexical_cast<int64_t>(val); //bool res = string_tools::string_to_num_fast(val, nval);
insert_res = stg.insert_next_value(h_array, nval); insert_res = stg.insert_next_value(h_array, nval);
}else }else

View file

@ -183,27 +183,35 @@ namespace string_tools
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
PUSH_WARNINGS PUSH_WARNINGS
DISABLE_GCC_WARNING(maybe-uninitialized) DISABLE_GCC_WARNING(maybe-uninitialized)
template<class XType> template<class XType>
inline bool get_xtype_from_string(OUT XType& val, const std::string& str_id) inline bool get_xtype_from_string(OUT XType& val, const std::string& str_id)
{ {
try if (std::is_integral<XType>::value && !std::numeric_limits<XType>::is_signed && !std::is_same<XType, bool>::value)
{ {
val = boost::lexical_cast<XType>(str_id); for (char c : str_id)
{
if (!std::isdigit(c))
return false;
}
}
try
{
val = boost::lexical_cast<XType>(str_id);
return true; return true;
} }
catch(std::exception& /*e*/) catch(std::exception& /*e*/)
{ {
//const char* pmsg = e.what(); //const char* pmsg = e.what();
return false; return false;
} }
catch(...)
{
return false;
}
catch(...) return true;
{ }
return false;
}
return true;
}
POP_WARNINGS POP_WARNINGS
//--------------------------------------------------- //---------------------------------------------------
template<typename int_t> template<typename int_t>
@ -315,7 +323,7 @@ POP_WARNINGS
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
//#ifdef _WINSOCK2API_ //#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; in_addr adr;
adr.s_addr = ip; adr.s_addr = ip;
@ -326,7 +334,7 @@ POP_WARNINGS
return "[failed]"; 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()); ip = inet_addr(ip_str.c_str());
if(INADDR_NONE == ip) if(INADDR_NONE == ip)
@ -369,7 +377,7 @@ POP_WARNINGS
return ss.str(); 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}; char buff[30] = {0};
@ -378,7 +386,7 @@ POP_WARNINGS
return boost::lexical_cast<std::string>(val); return boost::lexical_cast<std::string>(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); //return get_xtype_from_string(val, buff);
#if (defined _MSC_VER) #if (defined _MSC_VER)

View file

@ -41,27 +41,29 @@ namespace epee
struct simple_event 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<std::mutex> lock(m_mx); std::unique_lock<std::mutex> lock(m_mx);
rised = true; m_rised = true;
m_cond_var.notify_one(); m_cond_var.notify_one();
} }
void wait() void wait()
{ {
std::unique_lock<std::mutex> lock(m_mx); std::unique_lock<std::mutex> lock(m_mx);
while (!rised) while (!m_rised)
m_cond_var.wait(lock); 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; class critical_region;

View file

@ -44,7 +44,7 @@ namespace tests
{ {
std::string str1; std::string str1;
std::list<boost::uint64_t> array_of_id; std::list<uint64_t> array_of_id;
BEGIN_NAMED_SERIALIZE_MAP() BEGIN_NAMED_SERIALIZE_MAP()
SERIALIZE_STL_ANSI_STRING(str1) SERIALIZE_STL_ANSI_STRING(str1)
@ -64,7 +64,7 @@ namespace tests
{ {
std::string example_string_data; std::string example_string_data;
boost::uint64_t example_id_data; uint64_t example_id_data;
some_subdata sub; some_subdata sub;
BEGIN_NAMED_SERIALIZE_MAP() BEGIN_NAMED_SERIALIZE_MAP()
@ -78,7 +78,7 @@ namespace tests
struct response struct response
{ {
bool m_success; bool m_success;
boost::uint64_t example_id_data; uint64_t example_id_data;
std::list<some_subdata> subs; std::list<some_subdata> subs;
BEGIN_NAMED_SERIALIZE_MAP() BEGIN_NAMED_SERIALIZE_MAP()
@ -96,7 +96,7 @@ namespace tests
struct request struct request
{ {
std::string example_string_data2; std::string example_string_data2;
boost::uint64_t example_id_data; uint64_t example_id_data;
BEGIN_NAMED_SERIALIZE_MAP() BEGIN_NAMED_SERIALIZE_MAP()
SERIALIZE_POD(example_id_data) SERIALIZE_POD(example_id_data)
@ -106,8 +106,8 @@ namespace tests
struct response struct response
{ {
bool m_success; bool m_success;
boost::uint64_t example_id_data; uint64_t example_id_data;
BEGIN_NAMED_SERIALIZE_MAP() BEGIN_NAMED_SERIALIZE_MAP()
SERIALIZE_POD(example_id_data) SERIALIZE_POD(example_id_data)
@ -127,12 +127,12 @@ namespace tests
m_net_server.set_threads_prefix(pref); m_net_server.set_threads_prefix(pref);
} }
template<class calback_t> template<class calback_t>
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); 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); return m_net_server.connect(adr, port, conn_timeot, cn, bind_ip);
} }

View file

@ -227,6 +227,7 @@ namespace tools
std::string addr_data; std::string addr_data;
bool r = decode(addr, addr_data); bool r = decode(addr, addr_data);
if (!r) return false; if (!r) return false;
if (addr_data.size() <= addr_checksum_size) return false;
std::string checksum(addr_checksum_size, '\0'); std::string checksum(addr_checksum_size, '\0');
checksum = addr_data.substr(addr_data.size() - addr_checksum_size); checksum = addr_data.substr(addr_data.size() - addr_checksum_size);

View file

@ -34,15 +34,15 @@ static inline uint64_t rol64(uint64_t x, int r) {
#endif #endif
inline uint64_t hi_dword(uint64_t val) { static inline uint64_t hi_dword(uint64_t val) {
return val >> 32; return val >> 32;
} }
inline uint64_t lo_dword(uint64_t val) { static inline uint64_t lo_dword(uint64_t val) {
return val & 0xFFFFFFFF; 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 // multiplier = ab = a * 2^32 + b
// multiplicand = cd = c * 2^32 + d // multiplicand = cd = c * 2^32 + d
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * 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; 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; dividend |= ((uint64_t)*remainder) << 32;
*remainder = dividend % divisor; *remainder = dividend % divisor;
return dividend / divisor; return dividend / divisor;
} }
// Long division with 2^32 base // 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]; uint64_t dividend_dwords[4];
uint32_t remainder = 0; uint32_t remainder = 0;

View file

@ -21,6 +21,7 @@ using namespace epee;
namespace tools namespace tools
{ {
std::function<void(void)> signal_handler::m_handler;
#ifdef WIN32 #ifdef WIN32
std::string get_windows_version_display_string() std::string get_windows_version_display_string()

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <mutex>
#include <system_error> #include <system_error>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
@ -26,4 +27,60 @@ namespace tools
s.append(reinterpret_cast<const char*>(&pot.time), sizeof(pot.time)); s.append(reinterpret_cast<const char*>(&pot.time), sizeof(pot.time));
return crypto::cn_fast_hash(s.data(), s.size()); return crypto::cn_fast_hash(s.data(), s.size());
} }
class signal_handler
{
public:
template<typename T>
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<std::mutex> lock(m_mutex);
m_handler();
}
private:
static std::function<void(void)> m_handler;
};
} }

View file

@ -27,12 +27,12 @@ using namespace nodetool;
namespace namespace
{ {
const command_line::arg_descriptor<std::string, true> arg_ip = {"ip", "set ip"}; const command_line::arg_descriptor<std::string, true> arg_ip = {"ip", "set ip"};
const command_line::arg_descriptor<size_t> arg_port = {"port", "set port"}; const command_line::arg_descriptor<size_t> arg_port = {"port", "set port"};
const command_line::arg_descriptor<size_t> arg_rpc_port = {"rpc_port", "set rpc port"}; const command_line::arg_descriptor<size_t> arg_rpc_port = {"rpc_port", "set rpc port"};
const command_line::arg_descriptor<uint32_t, true> arg_timeout = {"timeout", "set timeout"}; const command_line::arg_descriptor<uint32_t, true> arg_timeout = {"timeout", "set timeout"};
const command_line::arg_descriptor<std::string> arg_priv_key = {"private_key", "private key to subscribe debug command", "", true}; const command_line::arg_descriptor<std::string> arg_priv_key = {"private_key", "private key to subscribe debug command", "", true};
const command_line::arg_descriptor<boost::uint64_t> arg_peer_id = {"peer_id", "peer_id if known(if not - will be requested)", 0}; const command_line::arg_descriptor<uint64_t> arg_peer_id = {"peer_id", "peer_id if known(if not - will be requested)", 0};
const command_line::arg_descriptor<bool> arg_generate_keys = {"generate_keys_pair", "generate private and public keys pair"}; const command_line::arg_descriptor<bool> arg_generate_keys = {"generate_keys_pair", "generate private and public keys pair"};
const command_line::arg_descriptor<bool> arg_request_stat_info = {"request_stat_info", "request statistics information"}; const command_line::arg_descriptor<bool> arg_request_stat_info = {"request_stat_info", "request statistics information"};
const command_line::arg_descriptor<bool> arg_request_net_state = {"request_net_state", "request network state information (peer list, connections count)"}; const command_line::arg_descriptor<bool> arg_request_net_state = {"request_net_state", "request network state information (peer list, connections count)"};

View file

@ -104,6 +104,9 @@ bool blockchain_storage::init(const std::string& config_folder)
//------------------------------------------------------------------ //------------------------------------------------------------------
bool blockchain_storage::store_blockchain() 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..."); LOG_PRINT_L0("Storing blockchain...");
if (!tools::create_directories_if_necessary(m_config_folder)) 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++) 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) << "\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; << "\ndifficulty\t\t" << block_difficulty(i) << ", nonce " << m_blocks[i].bl.nonce << ", tx_count " << m_blocks[i].bl.tx_hashes.size() << ENDL;
} }

View file

@ -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 = NULL);
bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id); 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(); uint64_t get_current_comulative_blocksize_limit();
bool is_storing_blockchain(){return m_is_blockchain_storing;}
template<class t_ids_container, class t_blocks_container, class t_missed_container> template<class t_ids_container, class t_blocks_container, class t_missed_container>
bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) 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; std::string m_config_folder;
checkpoints m_checkpoints; checkpoints m_checkpoints;
std::atomic<bool> m_is_in_checkpoint_zone; std::atomic<bool> m_is_in_checkpoint_zone;
std::atomic<bool> m_is_blockchain_storing;

View file

@ -6,32 +6,10 @@
#include <unordered_set> #include <unordered_set>
#include <atomic> #include <atomic>
#include "net/net_utils_base.h" #include "net/net_utils_base.h"
#include "copyable_atomic.h"
namespace cryptonote namespace cryptonote
{ {
class my_atomic: public std::atomic<uint32_t>
{
public:
my_atomic()
{};
my_atomic(const my_atomic& a):std::atomic<uint32_t>(a.load())
{}
my_atomic& operator= (const my_atomic& a)
{
store(a.load());
return *this;
}
uint32_t operator++()
{
return std::atomic<uint32_t>::operator++();
}
uint32_t operator++(int fake)
{
return std::atomic<uint32_t>::operator++(fake);
}
};
struct cryptonote_connection_context: public epee::net_utils::connection_context_base struct cryptonote_connection_context: public epee::net_utils::connection_context_base
{ {
@ -40,6 +18,7 @@ namespace cryptonote
{ {
state_befor_handshake = 0, //default state state_befor_handshake = 0, //default state
state_synchronizing, state_synchronizing,
state_idle,
state_normal state_normal
}; };
@ -48,7 +27,25 @@ namespace cryptonote
std::unordered_set<crypto::hash> m_requested_objects; std::unordered_set<crypto::hash> m_requested_objects;
uint64_t m_remote_blockchain_height; uint64_t m_remote_blockchain_height;
uint64_t m_last_response_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 //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";
}
}
} }

View file

@ -109,25 +109,25 @@ namespace cryptonote {
uint64_t prefix; uint64_t prefix;
if (!tools::base58::decode_addr(str, prefix, data)) if (!tools::base58::decode_addr(str, prefix, data))
{ {
LOG_PRINT_L0("Invalid address format"); LOG_PRINT_L1("Invalid address format");
return false; return false;
} }
if (CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX != prefix) 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; return false;
} }
if (!::serialization::parse_binary(data, adr)) 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; return false;
} }
if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key)) 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; return false;
} }
} }
@ -140,7 +140,7 @@ namespace cryptonote {
if(buff.size()!=sizeof(public_address_outer_blob)) 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; return false;
} }
@ -149,13 +149,13 @@ namespace cryptonote {
if(blob.m_ver > CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER) 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; return false;
} }
if(blob.check_sum != get_account_address_checksum(blob)) 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; return false;
} }

View file

@ -230,9 +230,9 @@ namespace cryptonote
return false; return false;
} }
boost::uint64_t amount_in = 0; uint64_t amount_in = 0;
get_inputs_money_amount(tx, amount_in); 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) if(amount_in <= amount_out)
{ {

View file

@ -139,7 +139,6 @@ namespace cryptonote
{ {
if (0 == amount) if (0 == amount)
{ {
chunk_handler(0);
return; return;
} }

View file

@ -22,7 +22,7 @@ namespace cryptonote
template<class t_core> template<class t_core>
class t_cryptonote_protocol_handler: public i_cryptonote_protocol class t_cryptonote_protocol_handler: public i_cryptonote_protocol
{ {
public: public:
typedef cryptonote_connection_context connection_context; typedef cryptonote_connection_context connection_context;
typedef core_stat_info stat_info; typedef core_stat_info stat_info;
@ -51,8 +51,8 @@ namespace cryptonote
bool get_stat_info(core_stat_info& stat_inf); bool get_stat_info(core_stat_info& stat_inf);
bool on_callback(cryptonote_connection_context& context); bool on_callback(cryptonote_connection_context& context);
t_core& get_core(){return m_core;} t_core& get_core(){return m_core;}
bool is_synchronized(){return m_synchronized;}
void log_connections();
private: private:
//----------------- commands handlers ---------------------------------------------- //----------------- commands handlers ----------------------------------------------
int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context); 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_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_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(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); 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<connection_context> m_p2p_stub; nodetool::p2p_endpoint_stub<connection_context> m_p2p_stub;
nodetool::i_p2p_endpoint<connection_context>* m_p2p; nodetool::i_p2p_endpoint<connection_context>* m_p2p;
std::atomic<uint32_t> m_syncronized_connections_count; std::atomic<uint32_t> m_syncronized_connections_count;
//std::atomic<uint32_t> m_syncronizing_connections_count; std::atomic<bool> m_synchronized;
std::atomic<bool> m_welcome_showed;
template<class t_parametr> template<class t_parametr>
bool post_notify(typename t_parametr::request& arg, cryptonote_connection_context& context) bool post_notify(typename t_parametr::request& arg, cryptonote_connection_context& context)

View file

@ -13,7 +13,7 @@ namespace cryptonote
t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore), t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore),
m_p2p(p_net_layout), m_p2p(p_net_layout),
m_syncronized_connections_count(0), m_syncronized_connections_count(0),
m_welcome_showed(false) m_synchronized(false)
{ {
if(!m_p2p) if(!m_p2p)
@ -68,6 +68,30 @@ namespace cryptonote
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> template<class t_core>
void t_cryptonote_protocol_handler<t_core>::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<class t_core>
bool t_cryptonote_protocol_handler<t_core>::process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital) bool t_cryptonote_protocol_handler<t_core>::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) if(context.m_state == cryptonote_connection_context::state_befor_handshake && !is_inital)
@ -84,7 +108,7 @@ namespace cryptonote
return true; 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_state = cryptonote_connection_context::state_synchronizing;
context.m_remote_blockchain_height = hshd.current_height; 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 //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); m_p2p->request_callback(context);
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------
/* template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::process_handshake_data(const blobdata& data, cryptonote_connection_context& context)
{
CORE_SYNC_DATA hsd = boost::value_initialized<CORE_SYNC_DATA>();
StorageNamed::load_struct_from_storage_buff(hsd, data);
return process_handshake_data(hsd, context);
}*/
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(CORE_SYNC_DATA& hshd) bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(CORE_SYNC_DATA& hshd)
@ -228,8 +244,10 @@ namespace cryptonote
context.m_remote_blockchain_height = arg.current_blockchain_height; context.m_remote_blockchain_height = arg.current_blockchain_height;
size_t count = 0;
BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks) BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
{ {
++count;
block b; block b;
if(!parse_and_validate_block_from_blob(block_entry.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"); << string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection");
m_p2p->drop_connection(context); m_p2p->drop_connection(context);
return 1; 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)); 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; context.m_state = cryptonote_connection_context::state_normal;
LOG_PRINT_CCONTEXT_GREEN(" SYNCHRONIZED OK", LOG_LEVEL_0); 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; return true;
} }
@ -392,7 +419,7 @@ namespace cryptonote
bool t_cryptonote_protocol_handler<t_core>::on_connection_synchronized() bool t_cryptonote_protocol_handler<t_core>::on_connection_synchronized()
{ {
bool val_expected = false; 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 LOG_PRINT_L0(ENDL << "**********************************************************************" << ENDL
<< "You are now synchronized with the network. You may now start simplewallet." << 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<t_core>::get_synchronizing_connections_count() size_t t_cryptonote_protocol_handler<t_core>::get_synchronizing_connections_count()
{ {
size_t count = 0; 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) if(context.m_state == cryptonote_connection_context::state_synchronizing)
++count; ++count;
return true; return true;

View file

@ -38,6 +38,7 @@ namespace
const command_line::arg_descriptor<bool> arg_os_version = {"os-version", ""}; const command_line::arg_descriptor<bool> arg_os_version = {"os-version", ""};
const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", "", ""}; const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", "", ""};
const command_line::arg_descriptor<int> arg_log_level = {"log-level", "", LOG_LEVEL_0}; const command_line::arg_descriptor<int> arg_log_level = {"log-level", "", LOG_LEVEL_0};
const command_line::arg_descriptor<bool> arg_console = {"no-console", "Disable daemon console commands"};
} }
bool command_line_preprocessor(const boost::program_options::variables_map& vm); 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_file);
command_line::add_arg(desc_cmd_sett, arg_log_level); 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::init_options(desc_cmd_sett);
cryptonote::core_rpc_server::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_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_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)) if (command_line_preprocessor(vm))
{ {
@ -162,15 +166,23 @@ int main(int argc, char* argv[])
res = ccore.init(vm); res = ccore.init(vm);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core");
LOG_PRINT_L0("Core initialized OK"); LOG_PRINT_L0("Core initialized OK");
// start components // start components
dch.start_handling(); if(!command_line::has_arg(vm, arg_console))
{
dch.start_handling();
}
LOG_PRINT_L0("Starting core rpc server..."); LOG_PRINT_L0("Starting core rpc server...");
res = rpc_server.run(2, false); res = rpc_server.run(2, false);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server."); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server.");
LOG_PRINT_L0("Core rpc server started ok"); 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..."); LOG_PRINT_L0("Starting p2p net loop...");
p2psrv.run(); p2psrv.run();
LOG_PRINT_L0("p2p net loop stopped"); 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; bool exit = false;
if (command_line::get_arg(vm, command_line::arg_version)) 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; exit = true;
} }
if (command_line::get_arg(vm, arg_os_version)) if (command_line::get_arg(vm, arg_os_version))

View file

@ -38,10 +38,15 @@ public:
bool start_handling() bool start_handling()
{ {
m_cmd_binder.start_handling(&m_srv, ""); m_cmd_binder.start_handling(&m_srv, "", "");
return true; return true;
} }
void stop_handling()
{
m_cmd_binder.stop_handling();
}
private: private:
epee::srv_console_handlers_binder<nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > > m_cmd_binder; epee::srv_console_handlers_binder<nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > > m_cmd_binder;
@ -77,7 +82,13 @@ private:
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
bool show_hr(const std::vector<std::string>& args) bool show_hr(const std::vector<std::string>& 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; return true;
} }
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
@ -100,7 +111,7 @@ private:
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
bool print_cn(const std::vector<std::string>& args) bool print_cn(const std::vector<std::string>& args)
{ {
m_srv.log_connections(); m_srv.get_payload_object().log_connections();
return true; return true;
} }
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
@ -263,7 +274,7 @@ private:
{ {
if(!args.size()) 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 <addr> [threads=1]" << std::endl;
return true; return true;
} }
@ -273,10 +284,11 @@ private:
std::cout << "target account address has wrong format" << std::endl; std::cout << "target account address has wrong format" << std::endl;
return true; return true;
} }
size_t threads_count = 1; size_t threads_count = 1;
if(args.size() > 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); m_srv.get_payload_object().get_core().get_miner().start(adr, threads_count);

View file

@ -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 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 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 request_callback(const epee::net_utils::connection_context_base& context);
virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&)> f); virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f);
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool parse_peer_from_string(nodetool::net_address& pe, const std::string& node_addr); 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); bool handle_command_line(const boost::program_options::variables_map& vm);

View file

@ -76,10 +76,10 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&)> f) void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f)
{ {
m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){ 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; 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); \ namespace
CHECK_AND_ASSERT_MES(r, false, "Failed to parse seed address from string: " << addr_str); m_seed_nodes.push_back(na); } {
template<typename T>
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<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::init(const boost::program_options::variables_map& vm) bool node_server<t_payload_net_handler>::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.201.95:8080");
ADD_HARDCODED_SEED_NODE("85.25.196.145: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.146:8080");
ADD_HARDCODED_SEED_NODE("85.25.196.144:8080"); ADD_HARDCODED_SEED_NODE("85.25.196.144:8080");
ADD_HARDCODED_SEED_NODE("5.199.168.138: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("85.25.194.245:8080");
ADD_HARDCODED_SEED_NODE("95.211.224.160:8080"); ADD_HARDCODED_SEED_NODE("95.211.224.160:8080");
ADD_HARDCODED_SEED_NODE("144.76.200.44:8080"); ADD_HARDCODED_SEED_NODE("144.76.200.44:8080");
@ -290,7 +329,7 @@ namespace nodetool
bool r = net_utils::async_invoke_remote_command2<typename COMMAND_HANDSHAKE::response>(context_.m_connection_id, COMMAND_HANDSHAKE::ID, arg, m_net_server.get_config_object(), bool r = net_utils::async_invoke_remote_command2<typename COMMAND_HANDSHAKE::response>(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) [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) if(code < 0)
{ {
@ -542,7 +581,7 @@ namespace nodetool
LOG_PRINT_RED_L0("Failed to connect to any of seed peers, continuing without seeds"); LOG_PRINT_RED_L0("Failed to connect to any of seed peers, continuing without seeds");
break; break;
} }
if(++current_index > m_seed_nodes.size()) if(++current_index >= m_seed_nodes.size())
current_index = 0; 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) 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; 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 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]() try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]()
{ {

View file

@ -6,7 +6,7 @@
#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid.hpp>
#include "net/net_utils_base.h" #include "net/net_utils_base.h"
#include "p2p_protocol_defs.h"
namespace nodetool namespace nodetool
{ {
@ -23,7 +23,7 @@ namespace nodetool
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0; 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 void request_callback(const epee::net_utils::connection_context_base& context)=0;
virtual uint64_t get_connections_count()=0; virtual uint64_t get_connections_count()=0;
virtual void for_each_connection(std::function<bool(t_connection_context&)> f)=0; virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type)> f)=0;
}; };
template<class t_connection_context> template<class t_connection_context>
@ -49,7 +49,7 @@ namespace nodetool
{ {
} }
virtual void for_each_connection(std::function<bool(t_connection_context&)> f) virtual void for_each_connection(std::function<bool(t_connection_context&,peerid_type)> f)
{ {
} }

View file

@ -49,7 +49,7 @@ namespace nodetool
bool get_gray_peer_by_index(peerlist_entry& p, size_t i); 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_white(const peerlist_entry& pr);
bool append_with_peer_gray(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_just_seen(peerid_type peer, const net_address& addr);
bool set_peer_unreachable(const peerlist_entry& pr); bool set_peer_unreachable(const peerlist_entry& pr);
bool is_ip_allowed(uint32_t ip); bool is_ip_allowed(uint32_t ip);
@ -284,7 +284,7 @@ namespace nodetool
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
inline 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; net_address addr;
addr.ip = ip; addr.ip = ip;
@ -343,10 +343,6 @@ namespace nodetool
if(!is_ip_allowed(ple.adr.ip)) if(!is_ip_allowed(ple.adr.ip))
return true; return true;
if(ple.adr.port != 8080)
assert(false);
CRITICAL_REGION_LOCAL(m_peerlist_lock); CRITICAL_REGION_LOCAL(m_peerlist_lock);
//find in white list //find in white list
auto by_addr_it_wt = m_peers_white.get<by_addr>().find(ple.adr); auto by_addr_it_wt = m_peers_white.get<by_addr>().find(ple.adr);

View file

@ -19,8 +19,8 @@ namespace nodetool
struct net_address struct net_address
{ {
boost::uint32_t ip; uint32_t ip;
boost::uint32_t port; uint32_t port;
}; };
struct peerlist_entry struct peerlist_entry
@ -74,13 +74,13 @@ namespace nodetool
KV_SERIALIZE(config_id) KV_SERIALIZE(config_id)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
boost::uint32_t connections_count; uint32_t connections_count;
boost::uint32_t connection_timeout; uint32_t connection_timeout;
boost::uint32_t ping_connection_timeout; uint32_t ping_connection_timeout;
boost::uint32_t handshake_interval; uint32_t handshake_interval;
boost::uint32_t packet_max_size; uint32_t packet_max_size;
boost::uint32_t config_id; uint32_t config_id;
boost::uint32_t send_peerlist_sz; uint32_t send_peerlist_sz;
}; };
struct basic_node_data struct basic_node_data

View file

@ -45,17 +45,35 @@ namespace cryptonote
m_net_server.set_threads_prefix("RPC"); m_net_server.set_threads_prefix("RPC");
bool r = handle_command_line(vm); bool r = handle_command_line(vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server"); CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server");
return epee::http_server_impl_base<core_rpc_server>::init(m_port, m_bind_ip); return epee::http_server_impl_base<core_rpc_server, connection_context>::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.height = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;
return true; 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.height = m_core.get_current_blockchain_height();
res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block(); 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 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.incoming_connections_count = total_conn - res.outgoing_connections_count;
res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_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.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count();
res.status = CORE_RPC_STATUS_OK;
return true; 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) 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)
{
std::list<crypto::hash> 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)
{ {
CHECK_CORE_READY();
std::list<std::pair<block, std::list<transaction> > > bs; std::list<std::pair<block, std::list<transaction> > > bs;
if(!m_core.find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT)) 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; 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"; res.status = "Failed";
if(!m_core.get_random_outs_for_amounts(req, res)) 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::outs_for_amount outs_for_amount;
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; 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) std::for_each(res.outs.begin(), res.outs.end(), [&](outs_for_amount& ofa)
{ {
ss << "[" << ofa.amount << "]:"; ss << "[" << ofa.amount << "]:";
CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << 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) std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe)
{ {
ss << oe.global_amount_index << " "; ss << oe.global_amount_index << " ";
}); });
ss << ENDL; ss << ENDL;
}); });
std::string s = ss.str(); std::string s = ss.str();
LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s); LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s);
res.status = CORE_RPC_STATUS_OK; res.status = CORE_RPC_STATUS_OK;
return true; 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); bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes);
if(!r) if(!r)
{ {
@ -143,8 +155,9 @@ namespace cryptonote
return true; 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<crypto::hash> vh; std::vector<crypto::hash> vh;
BOOST_FOREACH(const auto& tx_hex_str, req.txs_hashes) BOOST_FOREACH(const auto& tx_hex_str, req.txs_hashes)
{ {
@ -184,12 +197,7 @@ namespace cryptonote
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
/*bool core_rpc_server::on_get_outputs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::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)
{
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)
{ {
std::string tx_blob; std::string tx_blob;
if(!string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob)) if(!string_tools::parse_hexstr_to_binbuff(req.tx_as_hex, tx_blob))
@ -231,8 +239,9 @@ namespace cryptonote
return true; 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; account_public_address adr;
if(!get_account_address_from_str(adr, req.miner_address)) if(!get_account_address_from_str(adr, req.miner_address))
{ {
@ -249,9 +258,9 @@ namespace cryptonote
return true; 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()) if(!m_core.get_miner().stop())
{ {
res.status = "Failed, mining not stopped"; res.status = "Failed, mining not stopped";
@ -261,14 +270,22 @@ namespace cryptonote
return true; 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; 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) if(req.size() != 1)
{ {
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
@ -300,8 +317,15 @@ namespace cryptonote
return 0; 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) if(req.reserve_size > 255)
{ {
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE; error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_RESERVE_SIZE;
@ -359,8 +383,9 @@ namespace cryptonote
return true; 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) if(req.size()!=1)
{ {
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;

View file

@ -21,17 +21,18 @@ namespace cryptonote
class core_rpc_server: public epee::http_server_impl_base<core_rpc_server> class core_rpc_server: public epee::http_server_impl_base<core_rpc_server>
{ {
public: public:
typedef epee::net_utils::connection_context_base connection_context;
core_rpc_server(core& cr, nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& p2p); core_rpc_server(core& cr, nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& p2p);
static void init_options(boost::program_options::options_description& desc); static void init_options(boost::program_options::options_description& desc);
bool init(const boost::program_options::variables_map& vm); bool init(const boost::program_options::variables_map& vm);
private: 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() BEGIN_URI_MAP2()
MAP_URI_AUTO_JON2("/getheight", on_get_height, COMMAND_RPC_GET_HEIGHT) 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("/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("/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) 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_JSON_RPC_MAP()
END_URI_MAP2() END_URI_MAP2()
bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::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_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, connection_context& cntx);
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, connection_context& cntx);
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, 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); 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_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, connection_context& cntx);
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, connection_context& cntx);
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, 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); bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx);
bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
//json_rpc //json_rpc
bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res); 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); 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); 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); 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 handle_command_line(const boost::program_options::variables_map& vm);
bool check_core_ready();
core& m_core; core& m_core;
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p; nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;

View file

@ -11,6 +11,7 @@ namespace cryptonote
{ {
//----------------------------------------------- //-----------------------------------------------
#define CORE_RPC_STATUS_OK "OK" #define CORE_RPC_STATUS_OK "OK"
#define CORE_RPC_STATUS_BUSY "BUSY"
struct COMMAND_RPC_GET_HEIGHT struct COMMAND_RPC_GET_HEIGHT
{ {
@ -23,35 +24,15 @@ namespace cryptonote
struct response struct response
{ {
uint64_t height; uint64_t height;
std::string status;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height) KV_SERIALIZE(height)
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP() 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<std::string> main;
std::list<std::string> alt;
std::list<std::string> invalid;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(main)
KV_SERIALIZE(alt)
KV_SERIALIZE(invalid)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_GET_BLOCKS_FAST struct COMMAND_RPC_GET_BLOCKS_FAST
{ {
@ -153,6 +134,7 @@ namespace cryptonote
{ {
uint64_t amount; uint64_t amount;
std::list<out_entry> outs; std::list<out_entry> outs;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount) KV_SERIALIZE(amount)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs)
@ -283,7 +265,17 @@ namespace cryptonote
{ {
typedef std::list<std::string> request; typedef std::list<std::string> 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 struct COMMAND_RPC_GETBLOCKHASH
@ -313,12 +305,14 @@ namespace cryptonote
uint64_t height; uint64_t height;
uint64_t reserved_offset; uint64_t reserved_offset;
blobdata blocktemplate_blob; blobdata blocktemplate_blob;
std::string status;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(difficulty) KV_SERIALIZE(difficulty)
KV_SERIALIZE(height) KV_SERIALIZE(height)
KV_SERIALIZE(reserved_offset) KV_SERIALIZE(reserved_offset)
KV_SERIALIZE(blocktemplate_blob) KV_SERIALIZE(blocktemplate_blob)
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
}; };

View file

@ -12,3 +12,8 @@
#define CORE_RPC_ERROR_CODE_INTERNAL_ERROR -5 #define CORE_RPC_ERROR_CODE_INTERNAL_ERROR -5
#define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB -6 #define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB -6
#define CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED -7 #define CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED -7
#define CORE_RPC_ERROR_CODE_CORE_BUSY -9

View file

@ -8,6 +8,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "include_base_utils.h" #include "include_base_utils.h"
#include "common/command_line.h" #include "common/command_line.h"
#include "common/util.h"
#include "p2p/net_node.h" #include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "simplewallet.h" #include "simplewallet.h"
@ -40,22 +41,26 @@ namespace
const command_line::arg_descriptor<uint32_t> arg_log_level = {"set_log", "", 0, true}; const command_line::arg_descriptor<uint32_t> arg_log_level = {"set_log", "", 0, true};
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""}; const command_line::arg_descriptor< std::vector<std::string> > 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 <mixin_count> (<addr> <amount>)... Transfer <amount> to <addr>\n";*/
std::string simple_wallet::get_commands_str() std::string simple_wallet::get_commands_str()
{ {
@ -68,7 +73,7 @@ std::string simple_wallet::get_commands_str()
return ss.str(); return ss.str();
} }
bool simple_wallet::help(const std::vector<std::string> &args) bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{ {
std::cout << get_commands_str(); std::cout << get_commands_str();
return true; return true;
@ -76,15 +81,14 @@ bool simple_wallet::help(const std::vector<std::string> &args)
simple_wallet::simple_wallet() simple_wallet::simple_wallet()
: m_daemon_port(0) : 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 <threads_count>");
m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon"); 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("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_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_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("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 <mixin_count> <<addr> <amount>> Transfer <amount> to <address>. <mixin_count> 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 <mixin_count> {<addr> <amount>} Transfer <amount> to <address>. <mixin_count> 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, <level> is a number 0-4"); m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "Change current log detalization level, <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("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"); 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<std::string> &args)
std::cout << "use: set_log <log_level_number_0-4>" << ENDL; std::cout << "use: set_log <log_level_number_0-4>" << ENDL;
return true; return true;
} }
int l = 0; uint16_t l = 0;
if(!string_tools::get_xtype_from_string(l, args[0])) if(!string_tools::get_xtype_from_string(l, args[0]))
{ {
std::cout << "wrong number format, use: set_log <log_level_number_0-4>" << ENDL; std::cout << "wrong number format, use: set_log <log_level_number_0-4>" << ENDL;
return true; return true;
} }
if(l < 0 || l > LOG_LEVEL_4) if(LOG_LEVEL_4 < l)
{ {
std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << ENDL; std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << ENDL;
return true; return true;
@ -176,20 +180,17 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
return true; 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; std::string msg = "wallet failed to connect to daemon (" + m_daemon_address + "). " +
"Daemon either is not started or passed wrong port. " +
if(!m_wallet->check_connection()) "Please, make sure that daemon is running or restart the wallet with correct daemon address.";
{ print_fail_msg(msg);
std::cout << return false;
"**********************************************************************" << 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;
}
} }
return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password) 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); r = m_wallet->init(m_daemon_address);
CHECK_AND_ASSERT_MES(r, false, "failed to init wallet"); CHECK_AND_ASSERT_MES(r, false, "failed to init wallet");
refresh(vector<string>()); refresh(std::vector<std::string>());
std::cout << "**********************************************************************" << ENDL std::cout << "**********************************************************************" << ENDL
<< "Use \"help\" command to see the list of available commands." << ENDL << "Use \"help\" command to see the list of available commands." << ENDL
<< "**********************************************************************" << ENDL ; << "**********************************************************************" << ENDL ;
@ -250,52 +251,72 @@ bool simple_wallet::close_wallet()
bool simple_wallet::save(const std::vector<std::string> &args) bool simple_wallet::save(const std::vector<std::string> &args)
{ {
bool r = m_wallet->store(); bool r = m_wallet->store();
CHECK_AND_ASSERT_MES(r, false, "failed to store wallet " + m_wallet_file); if (r)
std::cout << "Wallet data saved" << ENDL; print_success_msg("Wallet data saved");
else
print_fail_msg("failed to store wallet " + m_wallet_file);
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::start_mining(const vector<string>& args) bool simple_wallet::start_mining(const std::vector<std::string>& args)
{ {
try_connect_to_daemon(); if (!try_connect_to_daemon())
return true;
COMMAND_RPC_START_MINING::request req; COMMAND_RPC_START_MINING::request req;
req.miner_address = m_wallet->get_account().get_public_address_str(); 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])) req.threads_count = 1;
{
std::cout << "Threads count value invalid \"" << args[0] << "\"" << ENDL;
return false;
}
} }
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; 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); bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/start_mining", req, res, m_http_client);
if (!r) std::string err = tools::interpret_rpc_response(r, res.status);
std::cout << "Mining has NOT been started" << std::endl; if (err.empty())
CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request"); print_success_msg("Mining started in daemon");
std::cout << "Mining started in daemon." << ENDL; else
print_fail_msg("mining has NOT been started: " + err);
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::stop_mining(const vector<string>& args) bool simple_wallet::stop_mining(const std::vector<std::string>& args)
{ {
try_connect_to_daemon(); if (!try_connect_to_daemon())
return true;
COMMAND_RPC_STOP_MINING::request req; COMMAND_RPC_STOP_MINING::request req;
COMMAND_RPC_STOP_MINING::response res; 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); bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/stop_mining", req, res, m_http_client);
if (!r) std::string err = tools::interpret_rpc_response(r, res.status);
std::cout << "Mining has NOT been stopped" << std::endl; if (err.empty())
CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "failed to invoke http request"); print_success_msg("Mining stopped in daemon");
std::cout << "Mining stopped in daemon." << ENDL; else
print_fail_msg("mining has NOT been stopped: " + err);
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::refresh(const vector<string>& args) bool simple_wallet::refresh(const std::vector<std::string>& args)
{ {
try_connect_to_daemon(); if (!try_connect_to_daemon())
return true;
std::cout << "Starting refresh..." << endl; std::cout << "Starting refresh..." << endl;
std::atomic<bool> refresh_is_done(false); std::atomic<bool> refresh_is_done(false);
@ -304,132 +325,166 @@ bool simple_wallet::refresh(const vector<string>& args)
epee::misc_utils::sleep_no_w(1000); epee::misc_utils::sleep_no_w(1000);
while(!refresh_is_done) while(!refresh_is_done)
{ {
bool ok; std::string err;
uint64_t bc_height = get_daemon_blockchain_height(ok); uint64_t bc_height = get_daemon_blockchain_height(err);
if (ok) if (err.empty())
cout << "Height " << m_wallet->get_blockchain_current_height() << " of " << bc_height << endl; cout << "Height " << m_wallet->get_blockchain_current_height() << " of " << bc_height << endl;
epee::misc_utils::sleep_no_w(1000); epee::misc_utils::sleep_no_w(1000);
} }
}); });
uint64_t initial_height = m_wallet->get_blockchain_current_height();
uint64_t fetched_blocks = 0; uint64_t fetched_blocks = 0;
bool money_received = false; 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; refresh_is_done = true;
th.join(); th.join();
if (ok) 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 else
std::cout << "Refresh failed, no blocks received" << std::endl; {
show_balance(vector<string>()); 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; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::show_balance(const vector<string>& args) bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::vector<std::string>()*/)
{ {
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; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::show_incoming_transfers(const vector<string>& args) bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& 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; 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::request req;
COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>(); COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>();
ok = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/getheight", req, res, m_http_client); bool r = 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"); err = tools::interpret_rpc_response(r, res.status);
return res.height; return res.height;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::show_blockchain_height(const vector<string>& args) bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
{ {
try_connect_to_daemon(); if (!try_connect_to_daemon())
return true;
bool ok; std::string err;
uint64_t bc_height = get_daemon_blockchain_height(ok); uint64_t bc_height = get_daemon_blockchain_height(err);
if (ok) if (err.empty())
cout << "core returned height: " << bc_height << endl; print_success_msg(boost::lexical_cast<std::string>(bc_height));
else else
std::cout << "Failed to get blockchain height" << std::endl; print_fail_msg("failed to get blockchain height: " + err);
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer(const vector<string> &args_) bool simple_wallet::transfer(const std::vector<std::string> &args_)
{ {
try_connect_to_daemon(); if (!try_connect_to_daemon())
return true;
vector<string> local_args = args_; std::vector<std::string> local_args = args_;
if(local_args.size() < 3) if(local_args.size() < 3)
{ {
std::cout << "wrong transfer arguments" << std::endl; print_fail_msg("wrong number of arguments, expected at least 3, got " + boost::lexical_cast<std::string>(local_args.size()));
help(vector<string>());
return true; return true;
} }
size_t fake_outs_count; size_t fake_outs_count;
if(!string_tools::get_xtype_from_string(fake_outs_count, local_args[0])) if(!string_tools::get_xtype_from_string(fake_outs_count, local_args[0]))
{ {
std::cout << " ambiguity_degree set wrong" << std::endl; print_fail_msg("mixin_count should be non-negative integer, got " + local_args[0]);
help(vector<string>());
return true; return true;
} }
local_args.erase(local_args.begin()); local_args.erase(local_args.begin());
if(local_args.size() % 2 != 0)
{
cout << "wrong transfer arguments" << endl;
help(vector<string>());
return true;
}
vector<cryptonote::tx_destination_entry> dsts; vector<cryptonote::tx_destination_entry> dsts;
uint64_t summary_amount = 0; uint64_t summary_amount = 0;
for (size_t i = 0; i < local_args.size(); i += 2) for (size_t i = 0; i < local_args.size(); i += 2)
{ {
cryptonote::tx_destination_entry de; 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;; print_fail_msg("wrong address: " + local_args[i]);
help(vector<string>());
return true; return true;
} }
if(de.amount <= 0)
if (local_args.size() <= i + 1)
{ {
cout << "Wrong transfer amount: " << de.amount << endl;; print_fail_msg("amount for the last address " + local_args[i] + " is not specified");
help(vector<string>());
return true; 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; summary_amount += de.amount;
if(!get_account_address_from_str(de.addr, local_args[i]))
{
cout << "Wrong address: " << local_args[i] << endl;
help(vector<string>());
return true;
}
dsts.push_back(de); dsts.push_back(de);
} }
if(summary_amount > m_wallet->unlocked_balance()) 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; 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; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::run() bool simple_wallet::run()
{ {
m_cmd_binder.run_handling(""); return m_cmd_binder.run_handling("[wallet]# ", "");
return true; }
//----------------------------------------------------------------------------------------------------
void simple_wallet::stop()
{
m_cmd_binder.stop_handling();
m_wallet->stop();
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::print_address(const std::vector<std::string> &args) bool simple_wallet::print_address(const std::vector<std::string> &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; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -482,7 +537,7 @@ int main(int argc, char* argv[])
} }
else if (command_line::get_arg(vm, command_line::arg_version)) 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; return false;
} }
@ -495,18 +550,19 @@ int main(int argc, char* argv[])
return 1; return 1;
//set up logging options //set up logging options
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_1); log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); 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::add_logger(LOGGER_FILE,
log_space::log_singletone::get_default_log_file().c_str(), 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)) if(command_line::has_arg(vm, arg_log_level))
{ {
LOG_PRINT_L0("Setting log level = " << command_line::get_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_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); r = w.init(vm);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet"); CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");
@ -514,6 +570,10 @@ int main(int argc, char* argv[])
std::vector<std::string> command = command_line::get_arg(vm, arg_command); std::vector<std::string> command = command_line::get_arg(vm, arg_command);
if (!command.empty()) if (!command.empty())
w.process_command(command); w.process_command(command);
tools::signal_handler::install([&w] {
w.stop();
});
w.run(); w.run();
w.deinit(); w.deinit();

View file

@ -29,6 +29,7 @@ namespace cryptonote
bool init(const boost::program_options::variables_map& vm); bool init(const boost::program_options::variables_map& vm);
bool deinit(); bool deinit();
bool run(); bool run();
void stop();
//wallet *create_wallet(); //wallet *create_wallet();
bool process_command(const std::vector<std::string> &args); bool process_command(const std::vector<std::string> &args);
@ -42,11 +43,11 @@ namespace cryptonote
bool open_wallet(const std::string &wallet_file, const std::string& password); bool open_wallet(const std::string &wallet_file, const std::string& password);
bool close_wallet(); bool close_wallet();
bool help(const std::vector<std::string> &args); bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args); bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args); bool stop_mining(const std::vector<std::string> &args);
bool refresh(const std::vector<std::string> &args); bool refresh(const std::vector<std::string> &args);
bool show_balance(const std::vector<std::string> &args); bool show_balance(const std::vector<std::string> &args = std::vector<std::string>());
bool show_incoming_transfers(const std::vector<std::string> &args); bool show_incoming_transfers(const std::vector<std::string> &args);
bool show_blockchain_height(const std::vector<std::string> &args); bool show_blockchain_height(const std::vector<std::string> &args);
bool transfer(const std::vector<std::string> &args); bool transfer(const std::vector<std::string> &args);
@ -54,8 +55,8 @@ namespace cryptonote
bool save(const std::vector<std::string> &args); bool save(const std::vector<std::string> &args);
bool set_log(const std::vector<std::string> &args); bool set_log(const std::vector<std::string> &args);
uint64_t get_daemon_blockchain_height(bool& ok); uint64_t get_daemon_blockchain_height(std::string& err);
void try_connect_to_daemon(); bool try_connect_to_daemon();
std::string m_wallet_file; std::string m_wallet_file;
std::string m_generate_new; std::string m_generate_new;
@ -64,11 +65,10 @@ namespace cryptonote
std::string m_daemon_address; std::string m_daemon_address;
std::string m_daemon_host; std::string m_daemon_host;
int m_daemon_port; int m_daemon_port;
bool m_tried_to_connect;
epee::console_handlers_binder m_cmd_binder; epee::console_handlers_binder m_cmd_binder;
std::auto_ptr<tools::wallet2> m_wallet; std::unique_ptr<tools::wallet2> m_wallet;
net_utils::http::http_simple_client m_http_client; net_utils::http::http_simple_client m_http_client;
}; };
} }

View file

@ -1,4 +1,4 @@
#define BUILD_COMMIT_ID "@VERSION@" #define BUILD_COMMIT_ID "@VERSION@"
#define PROJECT_VERSION "0.8.2" #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 ")" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"

View file

@ -32,14 +32,16 @@ bool wallet2::init(const std::string& daemon_address, uint64_t upper_transaction
return true; 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<size_t> outs; std::vector<size_t> outs;
uint64_t tx_money_got_in_outs = 0; uint64_t tx_money_got_in_outs = 0;
crypto::public_key tx_pub_key = null_pkey; crypto::public_key tx_pub_key = null_pkey;
bool r = parse_and_validate_tx_extra(tx, tx_pub_key); 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."); 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); 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"); CHECK_AND_ASSERT_MES(r, false, "call lookup_acc_outs failed");
if(outs.size() && tx_money_got_in_outs) 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); cryptonote::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response res = AUTO_VAL_INIT(res);
req.txid = get_transaction_hash(tx); 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); 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 (!r) fd.reason = fail_details::error_not_connected;
if(res.status != CORE_RPC_STATUS_OK) else if (CORE_RPC_STATUS_BUSY == res.status) fd.reason = fail_details::error_daemon_is_busy;
return false;// in case of split while lookup_acc_outs, transaction could be lost (especially if it is coinbase tx) 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() 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) 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()); 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>()); m_transfers.push_back(boost::value_initialized<transfer_details>());
transfer_details& td = m_transfers.back(); 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; td.m_spent = false;
cryptonote::keypair in_ephemeral; cryptonote::keypair in_ephemeral;
cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, o, in_ephemeral, td.m_key_image); 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<cryptonote::txout_to_key>(tx.vout[o].target).key, CHECK_AND_ASSERT_MES(in_ephemeral.pub == boost::get<cryptonote::txout_to_key>(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; 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) // 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<cryptonote::txin_to_key>(in).k_image); auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
if(it != m_key_images.end()) if(it != m_key_images.end())
{ {
LOG_PRINT_L1("Spent money: " << print_money(boost::get<cryptonote::txin_to_key>(in).amount) << ", with tx: " << get_transaction_hash(tx)); LOG_PRINT_COLOR("Spent money: " << print_money(boost::get<cryptonote::txin_to_key>(in).amount) << ", with tx: " << get_transaction_hash(tx),
LOG_LEVEL_0, epee::log_space::console_color_magenta);
m_transfers[it->second].m_spent = true; m_transfers[it->second].m_spent = true;
} }
} }
return 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 //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()); 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 //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()) if(b.timestamp + 60*60*24 > m_account.get_createtime())
{ {
TIME_MEASURE_START(miner_tx_handle_time); 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); TIME_MEASURE_FINISH(miner_tx_handle_time);
CHECK_AND_NO_ASSERT_MES(r, false, "failed to process transaction"); 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; cryptonote::transaction tx;
r = parse_and_validate_tx_from_blob(txblob, 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"); 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"); CHECK_AND_ASSERT_MES(r, false, "failed to process transaction");
} }
TIME_MEASURE_FINISH(txs_handle_time); TIME_MEASURE_FINISH(txs_handle_time);
@ -149,18 +166,26 @@ bool wallet2::get_short_chain_history(std::list<crypto::hash>& ids)
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool wallet2::pull_blocks(size_t& blocks_added) bool wallet2::pull_blocks(size_t& blocks_added, fail_details& fd)
{ {
blocks_added = 0; blocks_added = 0;
cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req); cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res); cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res);
get_short_chain_history(req.block_ids); 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); 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"); if (!r) fd.reason = fail_details::error_not_connected;
CHECK_AND_ASSERT_MES(res.status == CORE_RPC_STATUS_OK, false, "failed to get blocks"); 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 //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=" 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()); << 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; cryptonote::block bl;
r = cryptonote::parse_and_validate_block_from_blob(bl_entry.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"); CHECK_AND_ASSERT_MES(r, false, "failed to parse/validate block");
crypto::hash bl_id = get_block_hash(bl); crypto::hash bl_id = get_block_hash(bl);
if(current_index >= m_blockchain.size()) 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; if(!r) return false;
++blocks_added; ++blocks_added;
}else }else
@ -181,12 +207,12 @@ bool wallet2::pull_blocks(size_t& blocks_added)
if(bl_id != m_blockchain[current_index]) if(bl_id != m_blockchain[current_index])
{ {
//split detected here !!! //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) 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])); << "\nnot match with local block id " << string_tools::pod_to_hex(m_blockchain[current_index]));
detach_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; if(!r) return false;
} }
} }
++current_index; ++current_index;
@ -194,19 +220,19 @@ bool wallet2::pull_blocks(size_t& blocks_added)
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool wallet2::refresh() bool wallet2::refresh(fail_details& fd)
{ {
size_t blocks_fetched = 0; 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; 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; received_money = false;
blocks_fetched = 0; blocks_fetched = 0;
@ -214,19 +240,19 @@ bool wallet2::refresh(size_t & blocks_fetched, bool& received_money)
size_t try_count = 0; size_t try_count = 0;
crypto::hash last_tx_hash_id = m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash; 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(!res)
{ {
if(try_count < 3) 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; ++try_count;
continue; continue;
}else }else
{ {
LOG_PRINT_L0("pull_blocks failed, try_count=" << try_count); LOG_PRINT_L1("pull_blocks failed, try_count=" << try_count);
return false; 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)) if(last_tx_hash_id != (m_transfers.size() ? get_transaction_hash(m_transfers.back().m_tx) : null_hash))
received_money = true; 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; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -439,25 +465,6 @@ bool wallet2::store()
return r; 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 wallet2::unlocked_balance()
{ {
uint64_t amount = 0; uint64_t amount = 0;
@ -535,7 +542,7 @@ namespace
} }
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
uint64_t wallet2::select_transfers(uint64_t needed_money, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers) uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers)
{ {
std::vector<size_t> unused_transfers_indices; std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices; std::vector<size_t> 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; uint64_t found_money = 0;
while (found_money < needed_money && (!unused_transfers_indices.empty() || !unused_dust_indices.empty())) while (found_money < needed_money && (!unused_transfers_indices.empty() || !unused_dust_indices.empty()))
{ {
size_t idx; 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 else
{ {
idx = pop_random_value(unused_dust_indices); idx = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices);
at_least_one_dust_selected = true;
} }
transfer_container::iterator it = m_transfers.begin() + idx; transfer_container::iterator it = m_transfers.begin() + idx;
@ -580,7 +587,7 @@ bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts
return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx); return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& 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<cryptonote::tx_destination_entry>& 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); return transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx, tfd);
} }

View file

@ -25,11 +25,33 @@
namespace tools 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 class wallet2
{ {
wallet2(const wallet2&){}; wallet2(const wallet2&) : m_run(true) {};
public: public:
wallet2(){}; wallet2() : m_run(true) {};
struct transfer_details struct transfer_details
{ {
uint64_t m_block_height; uint64_t m_block_height;
@ -68,20 +90,46 @@ namespace tools
END_SERIALIZE() END_SERIALIZE()
}; };
struct transafer_fail_details struct fail_details
{ {
enum fail_reason enum fail_reason
{ {
error_ok = 0, error_ok = 0,
error_not_connected, error_not_connected,
error_daemon_is_busy,
error_rejected_by_daemon, error_rejected_by_daemon,
error_too_big_transaction, error_too_big_transaction,
error_not_enough_money, 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 error_internal_error
}; };
fail_reason reason; fail_reason reason;
uint64_t tx_blob_size; uint64_t tx_blob_size;
uint64_t max_expected_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); 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 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(fail_details& fd);
bool refresh(size_t & blocks_fetched); bool refresh(size_t & blocks_fetched, fail_details& fd);
bool refresh(size_t & blocks_fetched, bool& received_money); bool refresh(size_t & blocks_fetched, bool& received_money, fail_details& fd);
bool deinit(); bool deinit();
void stop() { m_run.store(false, std::memory_order_relaxed); }
uint64_t balance(); uint64_t balance();
uint64_t unlocked_balance(); uint64_t unlocked_balance();
void show_incoming_transfers(); template<typename T>
bool enum_incoming_transfers(const T& handler) const;
template<typename T> template<typename T>
bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy); bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy);
template<typename T> template<typename T>
bool transfer(const std::vector<cryptonote::tx_destination_entry>& 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<cryptonote::tx_destination_entry>& 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<typename T> template<typename T>
bool transfer(const std::vector<cryptonote::tx_destination_entry>& 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<cryptonote::tx_destination_entry>& 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<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee); bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee);
bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx); bool transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx);
bool transfer(const std::vector<cryptonote::tx_destination_entry>& 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<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx, fail_details& tfd);
bool check_connection(); bool check_connection();
bool get_transfers(wallet2::transfer_container& incoming_transfers); bool get_transfers(wallet2::transfer_container& incoming_transfers);
uint64_t get_blockchain_current_height() const { return m_local_bc_height; } uint64_t get_blockchain_current_height() const { return m_local_bc_height; }
@ -125,15 +176,15 @@ namespace tools
private: private:
bool store_keys(const std::string& keys_file_name, const std::string& password); 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 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_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); 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 detach_blockchain(uint64_t height);
bool get_short_chain_history(std::list<crypto::hash>& ids); bool get_short_chain_history(std::list<crypto::hash>& ids);
bool is_tx_spendtime_unlocked(uint64_t unlock_time) const; bool is_tx_spendtime_unlocked(uint64_t unlock_time) const;
bool is_transfer_unlocked(const transfer_details& td) const; bool is_transfer_unlocked(const transfer_details& td) const;
bool clear(); bool clear();
bool pull_blocks(size_t& blocks_added); bool pull_blocks(size_t& blocks_added, fail_details& fd);
uint64_t select_transfers(uint64_t needed_money, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers); uint64_t select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, std::list<transfer_container::iterator>& selected_transfers);
bool prepare_file_names(const std::string& file_path); bool prepare_file_names(const std::string& file_path);
cryptonote::account_base m_account; cryptonote::account_base m_account;
@ -148,6 +199,8 @@ namespace tools
std::unordered_map<crypto::key_image, size_t> m_key_images; std::unordered_map<crypto::key_image, size_t> m_key_images;
cryptonote::account_public_address m_account_public_address; 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 uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
std::atomic<bool> m_run;
}; };
} }
BOOST_CLASS_VERSION(tools::wallet2, 5) BOOST_CLASS_VERSION(tools::wallet2, 5)
@ -229,12 +282,29 @@ namespace tools
{ {
std::string indexes; 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::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=" <<src.real_output << ", real_output_in_tx_index=" << src.real_output_in_tx_index << ", indexes: " << indexes << ENDL; LOG_PRINT_L0("amount=" << cryptonote::print_money(src.amount) << ", real_output=" <<src.real_output << ", real_output_in_tx_index=" << src.real_output_in_tx_index << ", indexes: " << indexes);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
template<typename T> template<typename T>
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<typename T>
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy) 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<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& 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) 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); return transfer(dsts, fake_outputs_count, unlock_time, fee, destination_split_strategy, dust_policy, tx, stub);
} }
template<typename T> template<typename T>
bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, bool wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& 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; using namespace cryptonote;
@ -264,12 +334,13 @@ namespace tools
} }
std::list<transfer_container::iterator> selected_transfers; std::list<transfer_container::iterator> 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) if(found_money < needed_money)
{ {
LOG_ERROR("not enough money, available only " << print_money(found_money) << ", expected " << print_money(needed_money) ); LOG_ERROR("not enough money, available only " << print_money(found_money) << ", transaction amount " <<
tfd.reason = transafer_fail_details::error_not_enough_money; print_money(needed_money) << " = " << print_money(needed_money - fee) << " + " << print_money(fee) << " (fee)");
tfd.reason = fail_details::error_not_enough_money;
return false; return false;
} }
//typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount; //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); COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
if(fake_outputs_count) if(fake_outputs_count)
{ {
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req); 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 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) 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()); << it->m_internal_output_index << " more than " << it->m_tx.vout.size());
req.amounts.push_back(it->amount()); 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); 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; if (!r) tfd.reason = fail_details::error_not_connected;
CHECK_AND_ASSERT_MES(r, false, "failed to get getrandom_outs"); else if (CORE_RPC_STATUS_BUSY == daemon_resp.status) tfd.reason = fail_details::error_daemon_is_busy;
tfd.reason = transafer_fail_details::error_internal_error; else if (CORE_RPC_STATUS_OK != daemon_resp.status) tfd.reason = fail_details::error_internal_error;
CHECK_AND_ASSERT_MES(daemon_resp.status == CORE_RPC_STATUS_OK, false, "failed to getrandom_outs.bin"); else tfd.reason = fail_details::error_ok;
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 (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()); << 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 //prepare inputs
size_t i = 0; size_t i = 0;
@ -356,34 +448,48 @@ namespace tools
{ {
splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust)); 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); 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_AND_ASSERT_MES(r, false, "Transaction construction failed");
//check transaction size //check transaction size
if(get_object_blobsize(tx) >= m_upper_transaction_size_limit) 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); LOG_PRINT_L0("Transaction size is too big: " << get_object_blobsize(tx) << ", expected size < " << m_upper_transaction_size_limit);
tfd.reason = transafer_fail_details::error_too_big_transaction; tfd.reason = fail_details::error_too_big_transaction;
tfd.tx_blob_size = get_object_blobsize(tx); tfd.tx_blob_size = get_object_blobsize(tx);
tfd.max_expected_tx_blob_size = m_upper_transaction_size_limit; tfd.max_expected_tx_blob_size = m_upper_transaction_size_limit;
return false; return false;
} }
COMMAND_RPC_SEND_RAW_TX::request req; COMMAND_RPC_SEND_RAW_TX::request req;
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx)); req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx));
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp; 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); 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 (!r)
if(daemon_send_resp.status != CORE_RPC_STATUS_OK)
{ {
tfd.reason = transafer_fail_details::error_rejected_by_daemon; tfd.reason = fail_details::error_not_connected;
LOG_ERROR("daemon failed to accept generated transaction, id: " << get_transaction_hash(tx) ); LOG_PRINT_L0("failed to send transaction: " << interpret_rpc_response(r, daemon_send_resp.status));
return false; 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::string key_images;
std::for_each(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool 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; it->m_spent = true;
LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(tx) << ">" << ENDL 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 << "Balance: " << print_money(balance()) << ENDL
<< "Unlocked: " << print_money(unlocked_balance()) << ENDL << "Unlocked: " << print_money(unlocked_balance()) << ENDL
<< "Please, wait for confirmation for your balance to be unlocked."); << "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; return true;
} }
} }

View file

@ -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_clt cryptonote_core common crypto gtest_main ${Boost_LIBRARIES})
target_link_libraries(net_load_tests_srv 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) 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") 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() 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(coretests coretests --generate_and_play_test_data)
add_test(crypto crypto-tests ${CMAKE_CURRENT_SOURCE_DIR}/crypto/tests.txt) add_test(crypto crypto-tests ${CMAKE_CURRENT_SOURCE_DIR}/crypto/tests.txt)
add_test(difficulty difficulty-tests ${CMAKE_CURRENT_SOURCE_DIR}/difficulty/data.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) 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) add_test(hash-${hash} hash-tests ${hash} ${CMAKE_CURRENT_SOURCE_DIR}/hash/tests-${hash}.txt)
endforeach(hash) endforeach(hash)
add_test(hash-target hash-target-tests) add_test(hash-target hash-target-tests)
add_test(unit_tests unit_tests) add_test(unit_tests unit_tests)

View file

@ -102,7 +102,8 @@ bool transactions_flow_test(std::string& working_folder,
return false; return false;
} }
size_t blocks_fetched = 0; 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 ); LOG_ERROR( "failed to refresh source wallet from " << daemon_addr_a );
return false; 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"); 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 //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) while(w1.unlocked_balance() < amount_to_transfer)
{ {
misc_utils::sleep_no_w(1000); misc_utils::sleep_no_w(1000);
w1.refresh(blocks_fetched); w1.refresh(blocks_fetched, fd);
} }
//lets make a lot of small outs to ourselves //lets make a lot of small outs to ourselves
@ -165,7 +166,7 @@ bool transactions_flow_test(std::string& working_folder,
}else }else
{ {
misc_utils::sleep_no_w(1000); misc_utils::sleep_no_w(1000);
w1.refresh(); w1.refresh(fd);
} }
} }
//do actual transfer //do actual transfer
@ -187,7 +188,7 @@ bool transactions_flow_test(std::string& working_folder,
{ {
misc_utils::sleep_no_w(1000); misc_utils::sleep_no_w(1000);
LOG_PRINT_L0("not enough money, waiting for cashback or mining"); LOG_PRINT_L0("not enough money, waiting for cashback or mining");
w1.refresh(blocks_fetched); w1.refresh(blocks_fetched, fd);
} }
transaction tx; 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)) 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" ); 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)) 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" ); 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 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..."); LOG_PRINT_L0( "refreshing...");
bool recvd_money = false; 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 misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*1000);//wait two blocks before sync on another wallet on another daemon
} }

View file

@ -12,6 +12,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "include_base_utils.h" #include "include_base_utils.h"
#include "misc_language.h"
#include "misc_log_ex.h" #include "misc_log_ex.h"
#include "storages/levin_abstract_invoke2.h" #include "storages/levin_abstract_invoke2.h"
@ -33,7 +34,8 @@ namespace
{ {
if (predicate()) if (predicate())
return true; 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; return false;
} }
@ -292,7 +294,8 @@ namespace
return true; 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; return false;

View file

@ -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(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(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(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(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(21rhHRT48LN4PriP9, 6, "\x11\x22\x33\x44\x55\x66\x77");
TEST_encode_decode_addr(3BzAD7n3y, 0xFF, "");
#define TEST_decode_addr_neg(addr, test_name) \ #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("PuT7GAdgbA819VwdWVD", decode_fails_due_invalid_lenght);
TEST_decode_addr_neg("11efCaY6UjG7JrxuC", handles_invalid_checksum); 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("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 namespace
{ {

View file

@ -56,8 +56,7 @@ namespace
TEST_F(decompose_amount_into_digits_test, is_correct_0) TEST_F(decompose_amount_into_digits_test, is_correct_0)
{ {
uint64_t expected_chunks_arr[] = {0}; std::vector<uint64_t> expected_chunks;
VEC_FROM_ARR(expected_chunks);
cryptonote::decompose_amount_into_digits(0, 0, m_chunk_handler, m_dust_handler); 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_chunk_handler.m_chunks, expected_chunks);
ASSERT_EQ(m_dust_handler.m_has_dust, false); 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) TEST_F(decompose_amount_into_digits_test, is_correct_1)
{ {
uint64_t expected_chunks_arr[] = {0}; std::vector<uint64_t> expected_chunks;
VEC_FROM_ARR(expected_chunks);
cryptonote::decompose_amount_into_digits(0, 10, m_chunk_handler, m_dust_handler); 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_chunk_handler.m_chunks, expected_chunks);
ASSERT_EQ(m_dust_handler.m_has_dust, false); ASSERT_EQ(m_dust_handler.m_has_dust, false);

View file

@ -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 <string_tools.h>
using namespace epee::string_tools;
namespace
{
template<typename T>
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<typename T>
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<int_type>(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<int_type>(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");

View file

@ -13,4 +13,4 @@ EOM
esac esac
printf "height.value " 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