diff options
Diffstat (limited to 'contrib/epee')
-rw-r--r-- | contrib/epee/include/file_io_utils.h | 8 | ||||
-rw-r--r-- | contrib/epee/include/misc_log_ex.h | 3 | ||||
-rw-r--r-- | contrib/epee/include/net/abstract_tcp_server2.h | 10 | ||||
-rw-r--r-- | contrib/epee/include/net/abstract_tcp_server2.inl | 80 | ||||
-rw-r--r-- | contrib/epee/include/net/http_protocol_handler.h | 9 | ||||
-rw-r--r-- | contrib/epee/include/net/http_protocol_handler.inl | 30 | ||||
-rw-r--r-- | contrib/epee/include/net/local_ip.h | 2 | ||||
-rw-r--r-- | contrib/epee/include/net/net_utils_base.h | 1 | ||||
-rw-r--r-- | contrib/epee/include/serialization/keyvalue_serialization_overloads.h | 2 | ||||
-rw-r--r-- | contrib/epee/src/mlog.cpp | 53 |
10 files changed, 152 insertions, 46 deletions
diff --git a/contrib/epee/include/file_io_utils.h b/contrib/epee/include/file_io_utils.h index 196610674..4434f7383 100644 --- a/contrib/epee/include/file_io_utils.h +++ b/contrib/epee/include/file_io_utils.h @@ -28,7 +28,7 @@ #ifndef _FILE_IO_UTILS_H_ #define _FILE_IO_UTILS_H_ -#include <iostream> +#include <fstream> #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp> #ifdef WIN32 @@ -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 2f7325be5..7ca6ac872 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -119,6 +119,7 @@ namespace net_utils //----------------- i_service_endpoint --------------------- virtual bool do_send(const void* ptr, size_t cb); ///< (see do_send from i_service_endpoint) virtual bool do_send_chunk(const void* ptr, size_t cb); ///< will send (or queue) a part of data + virtual bool send_done(); virtual bool close(); virtual bool call_run_once_service_io(); virtual bool request_callback(); @@ -137,8 +138,11 @@ namespace net_utils /// 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; + boost::posix_time::milliseconds get_default_timeout(); + boost::posix_time::milliseconds get_timeout_from_bytes_read(size_t bytes); + + /// host connection count tracking + unsigned int host_count(const std::string &host, int delta = 0); /// Buffer for incoming data. boost::array<char, 8192> buffer_; @@ -165,6 +169,8 @@ namespace net_utils boost::asio::deadline_timer m_timer; bool m_local; + bool m_ready_to_close; + std::string m_host; public: void setRpcStation(); diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 91a94c21e..134bb4199 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -56,8 +56,8 @@ #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 DEFAULT_TIMEOUT_MS_LOCAL 1800000 // 30 minutes +#define DEFAULT_TIMEOUT_MS_REMOTE 300000 // 5 minutes #define TIMEOUT_EXTRA_MS_PER_BYTE 0.2 PRAGMA_WARNING_PUSH @@ -86,7 +86,8 @@ PRAGMA_WARNING_DISABLE_VS(4355) m_throttle_speed_in("speed_in", "throttle_speed_in"), m_throttle_speed_out("speed_out", "throttle_speed_out"), m_timer(io_service), - m_local(false) + m_local(false), + m_ready_to_close(false) { MDEBUG("test, connection constructor set m_connection_type="<<m_connection_type); } @@ -146,7 +147,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_); + m_local = epee::net_utils::is_ip_loopback(ip_) || epee::net_utils::is_ip_local(ip_); // create a random uuid boost::uuids::uuid random_uuid; @@ -165,9 +166,12 @@ PRAGMA_WARNING_DISABLE_VS(4355) return false; } + m_host = context.m_remote_address.host_str(); + try { host_count(m_host, 1); } catch(...) { /* ignore */ } + m_protocol_handler.after_init_connection(); - reset_timer(get_default_time(), false); + reset_timer(get_default_timeout(), false); socket_.async_read_some(boost::asio::buffer(buffer_), strand_.wrap( @@ -324,6 +328,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) logger_handle_net_read(bytes_transferred); context.m_last_recv = time(NULL); context.m_recv_cnt += bytes_transferred; + m_ready_to_close = false; bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred); if(!recv_res) { @@ -356,6 +361,13 @@ PRAGMA_WARNING_DISABLE_VS(4355) _dbg3("[sock " << socket_.native_handle() << "] Some problems at read: " << e.message() << ':' << e.value()); shutdown(); } + else + { + _dbg3("[sock " << socket_.native_handle() << "] peer closed connection"); + if (m_ready_to_close) + shutdown(); + } + m_ready_to_close = true; } // If an error occurs then no new asynchronous operations are started. This // means that all shared_ptr references to the connection object will @@ -531,7 +543,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) if(m_send_que.size() > 1) { // active operation should be in progress, nothing to do, just wait last operation callback auto size_now = cb; - MDEBUG("do_send() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size()); + MDEBUG("do_send_chunk() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size()); //do_send_handler_delayed( ptr , size_now ); // (((H))) // empty function LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size()); @@ -546,12 +558,12 @@ PRAGMA_WARNING_DISABLE_VS(4355) } auto size_now = m_send_que.front().size(); - MDEBUG("do_send() NOW SENSD: packet="<<size_now<<" B"); + MDEBUG("do_send_chunk() NOW SENSD: packet="<<size_now<<" B"); if (speed_limit_is_enabled()) 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); + reset_timer(get_default_timeout(), 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) @@ -566,29 +578,51 @@ PRAGMA_WARNING_DISABLE_VS(4355) return true; - CATCH_ENTRY_L0("connection<t_protocol_handler>::do_send", false); + CATCH_ENTRY_L0("connection<t_protocol_handler>::do_send_chunk", false); } // do_send_chunk //--------------------------------------------------------------------------------- template<class t_protocol_handler> - boost::posix_time::milliseconds connection<t_protocol_handler>::get_default_time() const + boost::posix_time::milliseconds connection<t_protocol_handler>::get_default_timeout() { + unsigned count; + try { count = host_count(m_host); } catch (...) { count = 0; } + const unsigned shift = std::min(std::max(count, 1u) - 1, 8u); + boost::posix_time::milliseconds timeout(0); if (m_local) - return DEFAULT_TIMEOUT_MS_LOCAL; + timeout = boost::posix_time::milliseconds(DEFAULT_TIMEOUT_MS_LOCAL >> shift); else - return DEFAULT_TIMEOUT_MS_REMOTE; + timeout = boost::posix_time::milliseconds(DEFAULT_TIMEOUT_MS_REMOTE >> shift); + return timeout; } //--------------------------------------------------------------------------------- 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 connection<t_protocol_handler>::get_timeout_from_bytes_read(size_t bytes) { 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(); + if (ms > get_default_timeout()) + ms = get_default_timeout(); return ms; } //--------------------------------------------------------------------------------- template<class t_protocol_handler> + unsigned int connection<t_protocol_handler>::host_count(const std::string &host, int delta) + { + static boost::mutex hosts_mutex; + CRITICAL_REGION_LOCAL(hosts_mutex); + static std::map<std::string, unsigned int> hosts; + unsigned int &val = hosts[host]; + if (delta > 0) + MTRACE("New connection from host " << host << ": " << val); + else if (delta < 0) + MTRACE("Closed connection from host " << host << ": " << val); + CHECK_AND_ASSERT_THROW_MES(delta >= 0 || val >= (unsigned)-delta, "Count would go negative"); + CHECK_AND_ASSERT_THROW_MES(delta <= 0 || val <= std::numeric_limits<unsigned int>::max() - (unsigned)delta, "Count would wrap"); + val += delta; + return val; + } + //--------------------------------------------------------------------------------- + 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) @@ -621,6 +655,11 @@ PRAGMA_WARNING_DISABLE_VS(4355) socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); m_was_shutdown = true; m_protocol_handler.release_protocol(); + if (!m_host.empty()) + { + try { host_count(m_host, -1); } catch (...) { /* ignore */ } + m_host = ""; + } return true; } //--------------------------------------------------------------------------------- @@ -645,6 +684,15 @@ PRAGMA_WARNING_DISABLE_VS(4355) } //--------------------------------------------------------------------------------- template<class t_protocol_handler> + bool connection<t_protocol_handler>::send_done() + { + if (m_ready_to_close) + return close(); + m_ready_to_close = true; + return true; + } + //--------------------------------------------------------------------------------- + template<class t_protocol_handler> bool connection<t_protocol_handler>::cancel() { return close(); @@ -687,7 +735,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) }else { //have more data to send - reset_timer(get_default_time(), false); + reset_timer(get_default_timeout(), 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 e602fac2b..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() @@ -144,6 +144,7 @@ namespace net_utils size_t m_newlines; protected: i_service_endpoint* m_psnd_hndlr; + t_connection_context& m_conn_context; }; template<class t_connection_context> @@ -175,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) @@ -197,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() @@ -219,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 f1da5067a..0bdba0bfe 100644 --- a/contrib/epee/include/net/http_protocol_handler.inl +++ b/contrib/epee/include/net/http_protocol_handler.inl @@ -196,16 +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_newlines(0), - m_psnd_hndlr(psnd_hndlr) + m_psnd_hndlr(psnd_hndlr), + m_conn_context(conn_context) { } @@ -281,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; } @@ -295,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; } @@ -310,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; } @@ -375,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; } @@ -399,14 +400,14 @@ namespace net_utils 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_L3("HTTP HEAD:\r\n" << m_cache.substr(0, pos)); m_query_info.m_full_request_buf_size = pos; m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos); if(!parse_cached_header(m_query_info.m_header_info, m_cache, pos)) { - LOG_ERROR("simple_http_connection_handler<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; } @@ -422,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; } @@ -455,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; } @@ -536,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; @@ -582,6 +583,7 @@ namespace net_utils m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size()); if ((response.m_body.size() && (query_info.m_http_method != http::http_method_head)) || (query_info.m_http_method == http::http_method_options)) m_psnd_hndlr->do_send((void*)response.m_body.data(), response.m_body.size()); + m_psnd_hndlr->send_done(); return res; } //----------------------------------------------------------------------------------- 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/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index 7615786be..a133942fb 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -281,6 +281,7 @@ namespace net_utils { virtual bool do_send(const void* ptr, size_t cb)=0; virtual bool close()=0; + virtual bool send_done()=0; virtual bool call_run_once_service_io()=0; virtual bool request_callback()=0; virtual boost::asio::io_service& get_io_service()=0; 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 0c810729d..e8248c958 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -117,7 +117,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); @@ -135,9 +135,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"); |