std::vector<std::string> DNSResolver::get_record(const std::string& url, int record_type, boost::optional<std::string> (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid) { std::vector<std::string> addresses; dnssec_available = false; dnssec_valid = false; if (!check_address_syntax(url.c_str())) { return addresses; } // destructor takes care of cleanup ub_result_ptr result; // call DNS resolver, blocking. if return value not zero, something went wrong if (!ub_resolve(m_data->m_ub_context, string_copy(url.c_str()), record_type, DNS_CLASS_IN, &result)) { dnssec_available = (result->secure || result->bogus); dnssec_valid = result->secure && !result->bogus; if (result->havedata) { for (size_t i=0; result->data[i] != NULL; i++) { boost::optional<std::string> res = (*reader)(result->data[i], result->len[i]); if (res) { MINFO("Found \"" << *res << "\" in " << get_record_name(record_type) << " record for " << url); addresses.push_back(*res); } } } } return addresses; }
virtual bool on_header(const epee::net_utils::http::http_response_info &headers) { ssize_t length; if (epee::string_tools::get_xtype_from_string(length, headers.m_header_info.m_content_length) && length >= 0) { MINFO("Content-Length: " << length); content_length = length; boost::filesystem::path path(control->path); boost::filesystem::space_info si = boost::filesystem::space(path); if (si.available < (size_t)content_length) { const uint64_t avail = (si.available + 1023) / 1024, needed = (content_length + 1023) / 1024; MERROR("Not enough space to download " << needed << " kB to " << path << " (" << avail << " kB available)"); return false; } } return true; }
DNSResolver::DNSResolver() : m_data(new DNSResolverData()) { int use_dns_public = 0; std::vector<std::string> dns_public_addr; if (auto res = getenv("DNS_PUBLIC")) { dns_public_addr = tools::dns_utils::parse_dns_public(res); if (!dns_public_addr.empty()) { MGINFO("Using public DNS server(s): " << boost::join(dns_public_addr, ", ") << " (TCP)"); use_dns_public = 1; } else { MERROR("Failed to parse DNS_PUBLIC"); } } // init libunbound context m_data->m_ub_context = ub_ctx_create(); if (use_dns_public) { for (const auto &ip: dns_public_addr) ub_ctx_set_fwd(m_data->m_ub_context, string_copy(ip.c_str())); ub_ctx_set_option(m_data->m_ub_context, string_copy("do-udp:"), string_copy("no")); ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes")); } else { // look for "/etc/resolv.conf" and "/etc/hosts" or platform equivalent ub_ctx_resolvconf(m_data->m_ub_context, NULL); ub_ctx_hosts(m_data->m_ub_context, NULL); } const char * const *ds = ::get_builtin_ds(); while (*ds) { MINFO("adding trust anchor: " << *ds); ub_ctx_add_ta(m_data->m_ub_context, string_copy(*ds++)); } }
static void download_thread(download_async_handle control) { static std::atomic<unsigned int> thread_id(0); MLOG_SET_THREAD_NAME("DL" + std::to_string(thread_id++)); struct stopped_setter { stopped_setter(const download_async_handle &control): control(control) {} ~stopped_setter() { control->stopped = true; } download_async_handle control; } stopped_setter(control); try { boost::unique_lock<boost::mutex> lock(control->mutex); MINFO("Downloading " << control->uri << " to " << control->path); std::ofstream f; f.open(control->path, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); if (!f.good()) { MERROR("Failed to open file " << control->path); control->result_cb(control->path, control->uri, control->success); return; } class download_client: public epee::net_utils::http::http_simple_client { public: download_client(download_async_handle control, std::ofstream &f): control(control), f(f), content_length(-1), total(0) {} virtual ~download_client() { f.close(); } virtual bool on_header(const epee::net_utils::http::http_response_info &headers) { ssize_t length; if (epee::string_tools::get_xtype_from_string(length, headers.m_header_info.m_content_length) && length >= 0) { MINFO("Content-Length: " << length); content_length = length; boost::filesystem::path path(control->path); boost::filesystem::space_info si = boost::filesystem::space(path); if (si.available < (size_t)content_length) { const uint64_t avail = (si.available + 1023) / 1024, needed = (content_length + 1023) / 1024; MERROR("Not enough space to download " << needed << " kB to " << path << " (" << avail << " kB available)"); return false; } } return true; } virtual bool handle_target_data(std::string &piece_of_transfer) { try { boost::lock_guard<boost::mutex> lock(control->mutex); if (control->stop) return false; f << piece_of_transfer; total += piece_of_transfer.size(); if (control->progress_cb && !control->progress_cb(control->path, control->uri, total, content_length)) return false; return f.good(); } catch (const std::exception &e) { MERROR("Error writing data: " << e.what()); return false; } } private: download_async_handle control; std::ofstream &f; ssize_t content_length; size_t total; } client(control, f); epee::net_utils::http::url_content u_c; if (!epee::net_utils::parse_url(control->uri, u_c)) { MERROR("Failed to parse URL " << control->uri); control->result_cb(control->path, control->uri, control->success); return; } if (u_c.host.empty()) { MERROR("Failed to determine address from URL " << control->uri); control->result_cb(control->path, control->uri, control->success); return; } lock.unlock(); uint16_t port = u_c.port ? u_c.port : 80; MDEBUG("Connecting to " << u_c.host << ":" << port); client.set_server(u_c.host, std::to_string(port), boost::none); if (!client.connect(std::chrono::seconds(30))) { boost::lock_guard<boost::mutex> lock(control->mutex); MERROR("Failed to connect to " << control->uri); control->result_cb(control->path, control->uri, control->success); return; } MDEBUG("GETting " << u_c.uri); const epee::net_utils::http::http_response_info *info = NULL; if (!client.invoke_get(u_c.uri, std::chrono::seconds(30), "", &info)) { boost::lock_guard<boost::mutex> lock(control->mutex); MERROR("Failed to connect to " << control->uri); client.disconnect(); control->result_cb(control->path, control->uri, control->success); return; } if (control->stop) { boost::lock_guard<boost::mutex> lock(control->mutex); MDEBUG("Download cancelled"); client.disconnect(); control->result_cb(control->path, control->uri, control->success); return; } if (!info) { boost::lock_guard<boost::mutex> lock(control->mutex); MERROR("Failed invoking GET command to " << control->uri << ", no status info returned"); client.disconnect(); control->result_cb(control->path, control->uri, control->success); return; } MDEBUG("response code: " << info->m_response_code); MDEBUG("response length: " << info->m_header_info.m_content_length); MDEBUG("response comment: " << info->m_response_comment); MDEBUG("response body: " << info->m_body); for (const auto &f: info->m_additional_fields) MDEBUG("additional field: " << f.first << ": " << f.second); if (info->m_response_code != 200) { boost::lock_guard<boost::mutex> lock(control->mutex); MERROR("Status code " << info->m_response_code); client.disconnect(); control->result_cb(control->path, control->uri, control->success); return; } client.disconnect(); f.close(); MDEBUG("Download complete"); lock.lock(); control->success = true; control->result_cb(control->path, control->uri, control->success); return; } catch (const std::exception &e) { MERROR("Exception in download thread: " << e.what()); // fall through and call result_cb not from the catch block to avoid another exception } boost::lock_guard<boost::mutex> lock(control->mutex); control->result_cb(control->path, control->uri, control->success); }
std::pair<boost::optional<boost::program_options::variables_map>, bool> main( int argc, char** argv, const char* const usage, const char* const notice, boost::program_options::options_description desc_params, const boost::program_options::positional_options_description& positional_options, const std::function<void(const std::string&, bool)> &print, const char *default_log_name, bool log_to_console) { namespace bf = boost::filesystem; namespace po = boost::program_options; #ifdef WIN32 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""}; const command_line::arg_descriptor<std::size_t> arg_max_log_file_size = {"max-log-file-size", "Specify maximum log file size [B]", MAX_LOG_FILE_SIZE}; const command_line::arg_descriptor<std::size_t> arg_max_log_files = {"max-log-files", "Specify maximum number of rotated log files to be saved (no limit by setting to 0)", MAX_LOG_FILES}; const command_line::arg_descriptor<uint32_t> arg_max_concurrency = {"max-concurrency", wallet_args::tr("Max number of threads to use for a parallel job"), DEFAULT_MAX_CONCURRENCY}; const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", wallet_args::tr("Specify log file"), ""}; const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", wallet_args::tr("Config file"), "", true}; std::string lang = i18n_get_language(); tools::on_startup(); tools::set_strict_default_file_permissions(true); epee::string_tools::set_module_name_and_folder(argv[0]); po::options_description desc_general(wallet_args::tr("General options")); command_line::add_arg(desc_general, command_line::arg_help); command_line::add_arg(desc_general, command_line::arg_version); command_line::add_arg(desc_params, arg_log_file); command_line::add_arg(desc_params, arg_log_level); command_line::add_arg(desc_params, arg_max_log_file_size); command_line::add_arg(desc_params, arg_max_log_files); command_line::add_arg(desc_params, arg_max_concurrency); command_line::add_arg(desc_params, arg_config_file); i18n_set_language("translations", "monero", lang); po::options_description desc_all; desc_all.add(desc_general).add(desc_params); po::variables_map vm; bool should_terminate = false; bool r = command_line::handle_error_helper(desc_all, [&]() { auto parser = po::command_line_parser(argc, argv).options(desc_all).positional(positional_options); po::store(parser.run(), vm); if (command_line::get_arg(vm, command_line::arg_help)) { Print(print) << "Aeon '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL; Print(print) << wallet_args::tr("This is the command line Aeon wallet. It needs to connect to a Aeon\n" "daemon to work correctly.") << ENDL; Print(print) << wallet_args::tr("Usage:") << ENDL << " " << usage; Print(print) << desc_all; should_terminate = true; return true; } else if (command_line::get_arg(vm, command_line::arg_version)) { Print(print) << "Aeon '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; should_terminate = true; return true; } if(command_line::has_arg(vm, arg_config_file)) { std::string config = command_line::get_arg(vm, arg_config_file); bf::path config_path(config); boost::system::error_code ec; if (bf::exists(config_path, ec)) { po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), desc_params), vm); } else { MERROR(wallet_args::tr("Can't find config file ") << config); return false; } } po::notify(vm); return true; }); if (!r) return {boost::none, true}; if (should_terminate) return {std::move(vm), should_terminate}; std::string log_path; if (!command_line::is_arg_defaulted(vm, arg_log_file)) log_path = command_line::get_arg(vm, arg_log_file); else log_path = mlog_get_default_log_path(default_log_name); mlog_configure(log_path, log_to_console, command_line::get_arg(vm, arg_max_log_file_size), command_line::get_arg(vm, arg_max_log_files)); if (!command_line::is_arg_defaulted(vm, arg_log_level)) { mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str()); } else if (!log_to_console) { mlog_set_categories(""); } if (notice) Print(print) << notice << ENDL; if (!command_line::is_arg_defaulted(vm, arg_max_concurrency)) tools::set_max_concurrency(command_line::get_arg(vm, arg_max_concurrency)); Print(print) << "Aeon '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"; if (!command_line::is_arg_defaulted(vm, arg_log_level)) MINFO("Setting log level = " << command_line::get_arg(vm, arg_log_level)); else MINFO("Setting log levels = " << getenv("AEON_LOGS")); MINFO(wallet_args::tr("Logging to: ") << log_path); Print(print) << boost::format(wallet_args::tr("Logging to %s")) % log_path; return {std::move(vm), should_terminate}; }
void network_throttle::set_target_speed( network_speed_kbps target ) { m_target_speed = target * 1024; MINFO("Setting LIMIT: " << target << " kbps"); set_real_target_speed(target); }