diff options
Diffstat (limited to 'contrib/epee')
-rw-r--r-- | contrib/epee/include/console_handler.h | 24 | ||||
-rw-r--r-- | contrib/epee/include/file_io_utils.h | 6 | ||||
-rw-r--r-- | contrib/epee/include/misc_log_ex.h | 3 | ||||
-rw-r--r-- | contrib/epee/include/net/abstract_tcp_server2.h | 8 | ||||
-rw-r--r-- | contrib/epee/include/net/abstract_tcp_server2.inl | 61 | ||||
-rw-r--r-- | contrib/epee/include/net/http_protocol_handler.h | 10 | ||||
-rw-r--r-- | contrib/epee/include/net/http_protocol_handler.inl | 44 | ||||
-rw-r--r-- | contrib/epee/include/net/local_ip.h | 2 | ||||
-rw-r--r-- | contrib/epee/include/serialization/keyvalue_serialization_overloads.h | 2 | ||||
-rw-r--r-- | contrib/epee/src/mlog.cpp | 53 |
10 files changed, 181 insertions, 32 deletions
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h index 4ea3fa54b..0e22a971c 100644 --- a/contrib/epee/include/console_handler.h +++ b/contrib/epee/include/console_handler.h @@ -401,13 +401,19 @@ eof: template<class t_server, class t_handler> - bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") + bool start_default_console(t_server* ptsrv, t_handler handlr, std::function<std::string(void)> prompt, const std::string& usage = "") { std::shared_ptr<async_console_handler> console_handler = std::make_shared<async_console_handler>(); boost::thread([=](){console_handler->run<t_server, t_handler>(ptsrv, handlr, prompt, usage);}).detach(); return true; } + template<class t_server, class t_handler> + bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") + { + return start_default_console(ptsrv, handlr, [prompt](){ return prompt; }, usage); + } + template<class t_server> bool start_default_console(t_server* ptsrv, const std::string& prompt, const std::string& usage = "") { @@ -421,19 +427,31 @@ eof: } template<class t_server, class t_handler> - bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") + bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, std::function<std::string(void)> prompt, const std::string& 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> - bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, 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 run_default_console_handler_no_srv_param(ptsrv, handlr, [prompt](){return prompt;},usage); + } + + template<class t_server, class t_handler> + bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, std::function<std::string(void)> prompt, const std::string& usage = "") { boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, prompt, usage) ); return true; } + template<class t_server, class t_handler> + bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") + { + return start_default_console_handler_no_srv_param(ptsrv, handlr, [prompt](){return prompt;}, usage); + } + /*template<class a> bool f(int i, a l) { diff --git a/contrib/epee/include/file_io_utils.h b/contrib/epee/include/file_io_utils.h index 196610674..0afff800f 100644 --- a/contrib/epee/include/file_io_utils.h +++ b/contrib/epee/include/file_io_utils.h @@ -128,7 +128,7 @@ namespace file_io_utils inline - bool load_file_to_string(const std::string& path_to_file, std::string& target_str) + bool load_file_to_string(const std::string& path_to_file, std::string& target_str, size_t max_size = 1000000000) { #ifdef WIN32 WCHAR wide_path[1000]; @@ -139,7 +139,7 @@ namespace file_io_utils if (file_handle == INVALID_HANDLE_VALUE) return false; DWORD file_size = GetFileSize(file_handle, NULL); - if ((file_size == INVALID_FILE_SIZE) || (file_size > 1000000000)) { + if ((file_size == INVALID_FILE_SIZE) || (uint64_t)file_size > (uint64_t)max_size) { CloseHandle(file_handle); return false; } @@ -159,7 +159,7 @@ namespace file_io_utils std::ifstream::pos_type file_size = fstream.tellg(); - if(file_size > 1000000000) + if((uint64_t)file_size > (uint64_t)max_size) // ensure a large domain for comparison, and negative -> too large return false;//don't go crazy size_t file_size_t = static_cast<size_t>(file_size); diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 35ec0950b..530f8e636 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -34,6 +34,7 @@ #define MONERO_DEFAULT_LOG_CATEGORY "default" #define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes +#define MAX_LOG_FILES 50 #define MCFATAL(cat,x) CLOG(FATAL,cat) << x #define MCERROR(cat,x) CLOG(ERROR,cat) << x @@ -105,7 +106,7 @@ #endif std::string mlog_get_default_log_path(const char *default_filename); -void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size = MAX_LOG_FILE_SIZE); +void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size = MAX_LOG_FILE_SIZE, const std::size_t max_log_files = MAX_LOG_FILES); void mlog_set_categories(const char *categories); std::string mlog_get_categories(); void mlog_set_log_level(int level); diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index ccde928ba..2f7325be5 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -135,6 +135,11 @@ namespace net_utils /// Handle completion of a write operation. void handle_write(const boost::system::error_code& e, size_t cb); + /// reset connection timeout timer and callback + void reset_timer(boost::posix_time::milliseconds ms, bool add); + boost::posix_time::milliseconds get_default_time() const; + boost::posix_time::milliseconds get_timeout_from_bytes_read(size_t bytes) const; + /// Buffer for incoming data. boost::array<char, 8192> buffer_; //boost::array<char, 1024> buffer_; @@ -158,6 +163,9 @@ namespace net_utils boost::mutex m_throttle_speed_in_mutex; boost::mutex m_throttle_speed_out_mutex; + boost::asio::deadline_timer m_timer; + bool m_local; + public: void setRpcStation(); }; diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 52b4c85ba..91a94c21e 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -44,6 +44,7 @@ #include <boost/thread/thread.hpp> // TODO #include <boost/thread/condition_variable.hpp> // TODO #include "misc_language.h" +#include "net/local_ip.h" #include "pragma_comp_defs.h" #include <sstream> @@ -55,6 +56,10 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "net" +#define DEFAULT_TIMEOUT_MS_LOCAL boost::posix_time::milliseconds(120000) // 2 minutes +#define DEFAULT_TIMEOUT_MS_REMOTE boost::posix_time::milliseconds(10000) // 10 seconds +#define TIMEOUT_EXTRA_MS_PER_BYTE 0.2 + PRAGMA_WARNING_PUSH namespace epee { @@ -79,7 +84,9 @@ PRAGMA_WARNING_DISABLE_VS(4355) m_pfilter( pfilter ), m_connection_type( connection_type ), m_throttle_speed_in("speed_in", "throttle_speed_in"), - m_throttle_speed_out("speed_out", "throttle_speed_out") + m_throttle_speed_out("speed_out", "throttle_speed_out"), + m_timer(io_service), + m_local(false) { MDEBUG("test, connection constructor set m_connection_type="<<m_connection_type); } @@ -139,6 +146,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) context = boost::value_initialized<t_connection_context>(); const unsigned long ip_{boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong())}; + m_local = epee::net_utils::is_ip_loopback(ip_); // create a random uuid boost::uuids::uuid random_uuid; @@ -159,6 +167,8 @@ PRAGMA_WARNING_DISABLE_VS(4355) m_protocol_handler.after_init_connection(); + reset_timer(get_default_time(), false); + socket_.async_read_some(boost::asio::buffer(buffer_), strand_.wrap( boost::bind(&connection<t_protocol_handler>::handle_read, self, @@ -304,6 +314,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) delay *= 0.5; if (delay > 0) { long int ms = (long int)(delay * 100); + reset_timer(boost::posix_time::milliseconds(ms + 1), true); boost::this_thread::sleep_for(boost::chrono::milliseconds(ms)); } } while(delay > 0); @@ -329,6 +340,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) shutdown(); }else { + reset_timer(get_timeout_from_bytes_read(bytes_transferred), false); socket_.async_read_some(boost::asio::buffer(buffer_), strand_.wrap( boost::bind(&connection<t_protocol_handler>::handle_read, connection<t_protocol_handler>::shared_from_this(), @@ -539,6 +551,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) do_send_handler_write( ptr , size_now ); // (((H))) CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), false, "Unexpected queue size"); + reset_timer(get_default_time(), false); boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now ) , //strand_.wrap( boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2) @@ -557,9 +570,53 @@ PRAGMA_WARNING_DISABLE_VS(4355) } // do_send_chunk //--------------------------------------------------------------------------------- template<class t_protocol_handler> + boost::posix_time::milliseconds connection<t_protocol_handler>::get_default_time() const + { + if (m_local) + return DEFAULT_TIMEOUT_MS_LOCAL; + else + return DEFAULT_TIMEOUT_MS_REMOTE; + } + //--------------------------------------------------------------------------------- + template<class t_protocol_handler> + boost::posix_time::milliseconds connection<t_protocol_handler>::get_timeout_from_bytes_read(size_t bytes) const + { + boost::posix_time::milliseconds ms = (boost::posix_time::milliseconds)(unsigned)(bytes * TIMEOUT_EXTRA_MS_PER_BYTE); + ms += m_timer.expires_from_now(); + if (ms > get_default_time()) + ms = get_default_time(); + return ms; + } + //--------------------------------------------------------------------------------- + template<class t_protocol_handler> + void connection<t_protocol_handler>::reset_timer(boost::posix_time::milliseconds ms, bool add) + { + if (m_connection_type != e_connection_type_RPC) + return; + MTRACE("Setting " << ms << " expiry"); + auto self = safe_shared_from_this(); + if(!self) + { + MERROR("Resetting timer on a dead object"); + return; + } + if (add) + ms += m_timer.expires_from_now(); + m_timer.expires_from_now(ms); + m_timer.async_wait([=](const boost::system::error_code& ec) + { + if(ec == boost::asio::error::operation_aborted) + return; + MDEBUG(context << "connection timeout, closing"); + self->close(); + }); + } + //--------------------------------------------------------------------------------- + template<class t_protocol_handler> bool connection<t_protocol_handler>::shutdown() { // Initiate graceful connection closure. + m_timer.cancel(); boost::system::error_code ignored_ec; socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); m_was_shutdown = true; @@ -572,6 +629,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) { TRY_ENTRY(); //_info("[sock " << socket_.native_handle() << "] Que Shutdown called."); + m_timer.cancel(); size_t send_que_size = 0; CRITICAL_REGION_BEGIN(m_send_que_lock); send_que_size = m_send_que.size(); @@ -629,6 +687,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) }else { //have more data to send + reset_timer(get_default_time(), false); auto size_now = m_send_que.front().size(); MDEBUG("handle_write() NOW SENDS: packet="<<size_now<<" B" <<", from queue size="<<m_send_que.size()); if (speed_limit_is_enabled()) diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h index b4485d1cd..1780f2393 100644 --- a/contrib/epee/include/net/http_protocol_handler.h +++ b/contrib/epee/include/net/http_protocol_handler.h @@ -69,7 +69,7 @@ namespace net_utils typedef t_connection_context connection_context;//t_connection_context net_utils::connection_context_base connection_context; typedef http_server_config config_type; - simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config); + simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context); virtual ~simple_http_connection_handler(){} bool release_protocol() @@ -141,8 +141,10 @@ namespace net_utils size_t m_len_summary, m_len_remain; config_type& m_config; bool m_want_close; + size_t m_newlines; protected: i_service_endpoint* m_psnd_hndlr; + t_connection_context& m_conn_context; }; template<class t_connection_context> @@ -174,9 +176,8 @@ namespace net_utils typedef custum_handler_config<t_connection_context> config_type; 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), + : simple_http_connection_handler<t_connection_context>(psnd_hndlr, config, conn_context), m_config(config), - m_conn_context(conn_context), m_auth(m_config.m_user ? http_server_auth{*m_config.m_user, config.rng} : http_server_auth{}) {} inline bool handle_request(const http_request_info& query_info, http_response_info& response) @@ -196,7 +197,7 @@ namespace net_utils response.m_response_comment = "OK"; response.m_body.clear(); - return m_config.m_phandler->handle_http_request(query_info, response, m_conn_context); + return m_config.m_phandler->handle_http_request(query_info, response, this->m_conn_context); } virtual bool thread_init() @@ -218,7 +219,6 @@ namespace net_utils private: //simple_http_connection_handler::config_type m_stub_config; config_type& m_config; - t_connection_context& m_conn_context; http_server_auth m_auth; }; } diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl index c18f7f706..b35bcb670 100644 --- a/contrib/epee/include/net/http_protocol_handler.inl +++ b/contrib/epee/include/net/http_protocol_handler.inl @@ -38,6 +38,7 @@ #define HTTP_MAX_URI_LEN 9000 #define HTTP_MAX_HEADER_LEN 100000 +#define HTTP_MAX_STARTING_NEWLINES 8 namespace epee { @@ -195,15 +196,17 @@ namespace net_utils //-------------------------------------------------------------------------------------------- template<class t_connection_context> - simple_http_connection_handler<t_connection_context>::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, t_connection_context& conn_context): m_state(http_state_retriving_comand_line), m_body_transfer_type(http_body_transfer_undefined), - m_is_stop_handling(false), + m_is_stop_handling(false), m_len_summary(0), m_len_remain(0), - m_config(config), + m_config(config), m_want_close(false), - m_psnd_hndlr(psnd_hndlr) + m_newlines(0), + m_psnd_hndlr(psnd_hndlr), + m_conn_context(conn_context) { } @@ -216,6 +219,7 @@ namespace net_utils m_body_transfer_type = http_body_transfer_undefined; m_query_info.clear(); m_len_summary = 0; + m_newlines = 0; return true; } //-------------------------------------------------------------------------------------------- @@ -236,6 +240,8 @@ namespace net_utils bool simple_http_connection_handler<t_connection_context>::handle_buff_in(std::string& buf) { + size_t ndel; + if(m_cache.size()) m_cache += buf; else @@ -253,11 +259,19 @@ namespace net_utils break; //check_and_handle_fake_response(); - if((m_cache[0] == '\r' || m_cache[0] == '\n')) + ndel = m_cache.find_first_not_of("\r\n"); + if (ndel != 0) { //some times it could be that before query line cold be few line breaks //so we have to be calm without panic with assers - m_cache.erase(0, 1); + m_newlines += std::string::npos == ndel ? m_cache.size() : ndel; + if (m_newlines > HTTP_MAX_STARTING_NEWLINES) + { + LOG_ERROR("simple_http_connection_handler::handle_buff_out: Too many starting newlines"); + m_state = http_state_error; + return false; + } + m_cache.erase(0, ndel); break; } @@ -268,7 +282,7 @@ namespace net_utils m_is_stop_handling = true; if(m_cache.size() > HTTP_MAX_URI_LEN) { - LOG_ERROR("simple_http_connection_handler::handle_buff_out: Too long URI line"); + LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler::handle_buff_out: Too long URI line"); m_state = http_state_error; return false; } @@ -282,7 +296,7 @@ namespace net_utils m_is_stop_handling = true; if(m_cache.size() > HTTP_MAX_HEADER_LEN) { - LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long header area"); + LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler::handle_buff_in: Too long header area"); m_state = http_state_error; return false; } @@ -297,10 +311,10 @@ namespace net_utils case http_state_connection_close: return false; default: - LOG_ERROR("simple_http_connection_handler::handle_char_out: Wrong state: " << m_state); + LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler::handle_char_out: Wrong state: " << m_state); return false; case http_state_error: - LOG_ERROR("simple_http_connection_handler::handle_char_out: Error state!!!"); + LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler::handle_char_out: Error state!!!"); return false; } @@ -362,7 +376,7 @@ namespace net_utils }else { m_state = http_state_error; - LOG_ERROR("simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(): Failed to match first line: " << m_cache); + LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(): Failed to match first line: " << m_cache); return false; } @@ -393,7 +407,7 @@ namespace net_utils if(!parse_cached_header(m_query_info.m_header_info, m_cache, pos)) { - LOG_ERROR("simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache); + LOG_ERROR_CC(m_conn_context, "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; return false; } @@ -409,7 +423,7 @@ namespace net_utils m_body_transfer_type = http_body_transfer_measure; if(!get_len_from_content_lenght(m_query_info.m_header_info.m_content_length, m_len_summary)) { - LOG_ERROR("simple_http_connection_handler<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); + LOG_ERROR_CC(m_conn_context, "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; return false; } @@ -442,7 +456,7 @@ namespace net_utils case http_body_transfer_multipart: case http_body_transfer_undefined: default: - LOG_ERROR("simple_http_connection_handler<t_connection_context>::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type); + LOG_ERROR_CC(m_conn_context, "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; return false; } @@ -523,7 +537,7 @@ namespace net_utils body_info.m_etc_fields.push_back(std::pair<std::string, std::string>(result[field_etc_name], result[field_val])); else { - LOG_ERROR("simple_http_connection_handler<t_connection_context>::parse_cached_header() not matched last entry in:"<<m_cache_to_process); + LOG_ERROR_CC(m_conn_context, "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; diff --git a/contrib/epee/include/net/local_ip.h b/contrib/epee/include/net/local_ip.h index 0d458963c..52c5855b9 100644 --- a/contrib/epee/include/net/local_ip.h +++ b/contrib/epee/include/net/local_ip.h @@ -48,7 +48,7 @@ namespace epee if( (ip | 0xffffff00) == 0xffffffac) { - uint32_t second_num = (ip << 8) & 0xff000000; + uint32_t second_num = (ip >> 8) & 0xff; if(second_num >= 16 && second_num <= 31 ) return true; } diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index 7087136cc..09087f785 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -156,7 +156,7 @@ namespace epee typename stl_container::value_type* pelem = (typename stl_container::value_type*)buff.data(); CHECK_AND_ASSERT_MES(!(loaded_size%sizeof(typename stl_container::value_type)), false, - "size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type)); + "size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type) << ", type " << typeid(typename stl_container::value_type).name()); size_t count = (loaded_size/sizeof(typename stl_container::value_type)); for(size_t i = 0; i < count; i++) container.insert(container.end(), *(pelem++)); diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp index fb0b4ac2b..0759f5d34 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -116,7 +116,7 @@ static const char *get_default_categories(int level) return categories; } -void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size) +void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size, const std::size_t max_log_files) { el::Configurations c; c.setGlobally(el::ConfigurationType::Filename, filename_base); @@ -134,9 +134,58 @@ void mlog_configure(const std::string &filename_base, bool console, const std::s el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog); el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput); el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck); - el::Helpers::installPreRollOutCallback([filename_base](const char *name, size_t){ + el::Helpers::installPreRollOutCallback([filename_base, max_log_files](const char *name, size_t){ std::string rname = generate_log_filename(filename_base.c_str()); rename(name, rname.c_str()); + if (max_log_files != 0) + { + std::vector<boost::filesystem::path> found_files; + const boost::filesystem::directory_iterator end_itr; + for (boost::filesystem::directory_iterator iter(boost::filesystem::path(filename_base).parent_path()); iter != end_itr; ++iter) + { + const std::string filename = iter->path().string(); + if (filename.size() >= filename_base.size() && std::memcmp(filename.data(), filename_base.data(), filename_base.size()) == 0) + { + found_files.push_back(iter->path()); + } + } + if (found_files.size() >= max_log_files) + { + std::sort(found_files.begin(), found_files.end(), [](const boost::filesystem::path &a, const boost::filesystem::path &b) { + boost::system::error_code ec; + std::time_t ta = boost::filesystem::last_write_time(boost::filesystem::path(a), ec); + if (ec) + { + MERROR("Failed to get timestamp from " << a << ": " << ec); + ta = std::time(nullptr); + } + std::time_t tb = boost::filesystem::last_write_time(boost::filesystem::path(b), ec); + if (ec) + { + MERROR("Failed to get timestamp from " << b << ": " << ec); + tb = std::time(nullptr); + } + static_assert(std::is_integral<time_t>(), "bad time_t"); + return ta < tb; + }); + for (size_t i = 0; i <= found_files.size() - max_log_files; ++i) + { + try + { + boost::system::error_code ec; + boost::filesystem::remove(found_files[i], ec); + if (ec) + { + MERROR("Failed to remove " << found_files[i] << ": " << ec); + } + } + catch (const std::exception &e) + { + MERROR("Failed to remove " << found_files[i] << ": " << e.what()); + } + } + } + } }); mlog_set_common_prefix(); const char *monero_log = getenv("MONERO_LOGS"); |