diff --git a/builds/msvc/vs2022/libbitcoin-system.import.props b/builds/msvc/vs2022/libbitcoin-system.import.props index 58f802c10..59ce698bc 100644 --- a/builds/msvc/vs2022/libbitcoin-system.import.props +++ b/builds/msvc/vs2022/libbitcoin-system.import.props @@ -49,7 +49,7 @@ - WITH_ICU;WIN32_LEAN_AND_MEAN;NOMINMAX;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + WITH_ICU;WIN32_LEAN_AND_MEAN;NOMINMAX;_WIN32_WINNT=0x0602;%(PreprocessorDefinitions) BOOST_JSON_NO_LIB;BOOST_CONTAINER_NO_LIB;%(PreprocessorDefinitions) BC_STATIC;%(PreprocessorDefinitions) diff --git a/console/main.cpp b/console/main.cpp index f0decbf52..0a4a45c0f 100644 --- a/console/main.cpp +++ b/console/main.cpp @@ -79,15 +79,17 @@ BC_USE_LIBBITCOIN_MAIN int bc::system::main(int argc, char* argv[]) { using namespace bc; - using namespace bc::node; using namespace bc::system; + using namespace bc::network; + using namespace bc::node; + using namespace bc::server; // en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio std::ios_base::sync_with_stdio(false); set_utf8_stdio(); - const server::web_pages web_server{}; - const server::explore_pages block_explorer{}; + const web_pages web_server{}; + const explore_pages block_explorer{}; parser metadata(chain::selection::mainnet, block_explorer, web_server); const auto& args = const_cast(argv); @@ -99,18 +101,7 @@ int bc::system::main(int argc, char* argv[]) symbols_path = metadata.configured.log.symbols; #endif -// Requires _WIN32_WINNT set to 0x0602 (defaults 0x0602 in vc++ 2022). -#if defined(HAVE_MSC) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - - // Set low memory priority on the current process (testing). - MEMORY_PRIORITY_INFORMATION priority{ MEMORY_PRIORITY_LOW }; - SetProcessInformation( - GetCurrentProcess(), - ProcessMemoryPriority, - &priority, - sizeof(priority)); - -#endif + set_memory_priority(metadata.configured.node.memory_priority_()); executor host(metadata, cin, cout, cerr); return host.dispatch() ? 0 : -1; diff --git a/include/bitcoin/node/protocols/protocol_explore.hpp b/include/bitcoin/node/protocols/protocol_explore.hpp index 376e7c81a..ceefabc0d 100644 --- a/include/bitcoin/node/protocols/protocol_explore.hpp +++ b/include/bitcoin/node/protocols/protocol_explore.hpp @@ -48,13 +48,9 @@ class BCN_API protocol_explore } protected: - /// Receivers. - void handle_receive_get(const code& ec, - const network::http::method::get& request) NOEXCEPT override; - /// Dispatch. - virtual bool dispatch_object( - const network::http::request& request) NOEXCEPT; + bool try_dispatch_object( + const network::http::request& request) NOEXCEPT override; }; } // namespace node diff --git a/include/bitcoin/node/protocols/protocol_html.hpp b/include/bitcoin/node/protocols/protocol_html.hpp index aea4b7efc..8cd616925 100644 --- a/include/bitcoin/node/protocols/protocol_html.hpp +++ b/include/bitcoin/node/protocols/protocol_html.hpp @@ -52,7 +52,11 @@ class BCN_API protocol_html const network::http::method::get& request) NOEXCEPT override; /// Dispatch. - virtual bool dispatch_embedded( + virtual bool try_dispatch_object( + const network::http::request& request) NOEXCEPT; + virtual void dispatch_file( + const network::http::request& request) NOEXCEPT; + virtual void dispatch_embedded( const network::http::request& request) NOEXCEPT; /// Senders. diff --git a/include/bitcoin/node/settings.hpp b/include/bitcoin/node/settings.hpp index ccb38e61e..57c300eb9 100644 --- a/include/bitcoin/node/settings.hpp +++ b/include/bitcoin/node/settings.hpp @@ -70,9 +70,10 @@ class BCN_API settings settings(system::chain::selection context) NOEXCEPT; /// Properties. - bool priority; bool delay_inbound; bool headers_first; + bool thread_priority; + bool memory_priority; float allowed_deviation; uint16_t announcement_cache; uint16_t allocation_multiple; @@ -91,7 +92,8 @@ class BCN_API settings virtual size_t maximum_concurrency_() const NOEXCEPT; virtual network::steady_clock::duration sample_period() const NOEXCEPT; virtual network::wall_clock::duration currency_window() const NOEXCEPT; - virtual network::thread_priority priority_() const NOEXCEPT; + virtual network::processing_priority thread_priority_() const NOEXCEPT; + virtual network::memory_priority memory_priority_() const NOEXCEPT; }; } // namespace node diff --git a/src/chasers/chaser_validate.cpp b/src/chasers/chaser_validate.cpp index 4ac114b4d..a6f5ad0aa 100644 --- a/src/chasers/chaser_validate.cpp +++ b/src/chasers/chaser_validate.cpp @@ -37,7 +37,8 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) // Independent threadpool and strand (base class strand uses network pool). chaser_validate::chaser_validate(full_node& node) NOEXCEPT : chaser(node), - threadpool_(node.config().node.threads_(), node.config().node.priority_()), + threadpool_(node.config().node.threads_(), + node.config().node.thread_priority_()), independent_strand_(threadpool_.service().get_executor()), subsidy_interval_(node.config().bitcoin.subsidy_interval_blocks), initial_subsidy_(node.config().bitcoin.initial_subsidy()), diff --git a/src/parser.cpp b/src/parser.cpp index c5d161f7e..8f336ce91 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1004,9 +1004,14 @@ options_metadata parser::load_settings() THROWS "The number of threads in the validation threadpool, defaults to '32'." ) ( - "node.priority", - value(&configured.node.priority), - "Set the validation threadpool to high priority, defaults to 'true'." + "node.thread_priority", + value(&configured.node.thread_priority), + "Set validation threads to high processing priority, defaults to 'true'." + ) + ( + "node.memory_priority", + value(&configured.node.memory_priority), + "Set the process to high memory priority, defaults to 'true'." ) ( "node.delay_inbound", diff --git a/src/protocols/protocol_explore.cpp b/src/protocols/protocol_explore.cpp index 7d332fb3a..016b7fe79 100644 --- a/src/protocols/protocol_explore.cpp +++ b/src/protocols/protocol_explore.cpp @@ -24,95 +24,19 @@ namespace libbitcoin { namespace node { #define CLASS protocol_explore - -using namespace boost::json; -using namespace std::placeholders; -using namespace network::http; + using namespace system; +using namespace network::http; BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) -// Handle get method. -// ---------------------------------------------------------------------------- - -void protocol_explore::handle_receive_get(const code& ec, - const method::get& request) NOEXCEPT -{ - BC_ASSERT(stranded()); - - if (stopped(ec)) - return; - - // Enforce http origin policy (requires configured hosts). - if (!is_allowed_origin(*request, request->version())) - { - send_forbidden(*request); - return; - } - - // Enforce http host header (if any hosts are configured). - if (!is_allowed_host(*request, request->version())) - { - send_bad_host(*request); - return; - } - - // Dispatch object with specified encoding. - if (dispatch_object(*request)) - return; - - // Embedded page site. - if (dispatch_embedded(*request)) - return; - - // Empty path implies malformed target (terminal). - auto path = to_local_path(request->target()); - if (path.empty()) - { - send_bad_target(*request); - return; - } - - // If no file extension it's REST on the single/default html page. - if (!path.has_extension()) - { - path = to_local_path(); - - // Default html page (e.g. index.html) is not configured. - if (path.empty()) - { - send_not_implemented(*request); - return; - } - } - - // Get the single/default or explicitly requested page. - auto file = get_file_body(path); - if (!file.is_open()) - { - send_not_found(*request); - return; - } - - send_file(*request, std::move(file), - file_mime_type(path, mime_type::application_octet_stream)); -} - // Dispatch. // ---------------------------------------------------------------------------- -bool protocol_explore::dispatch_object( - const network::http::request& request) NOEXCEPT +bool protocol_explore::try_dispatch_object(const request& request) NOEXCEPT { - const auto target = request.target(); - if (!is_origin_form(target)) - { - send_bad_target(request); - return true; - } - wallet::uri uri{}; - if (!uri.decode(target)) + if (!uri.decode(request.target())) { send_bad_target(request); return true; diff --git a/src/protocols/protocol_html.cpp b/src/protocols/protocol_html.cpp index 22bcb125d..d7477cb0e 100644 --- a/src/protocols/protocol_html.cpp +++ b/src/protocols/protocol_html.cpp @@ -41,7 +41,14 @@ void protocol_html::handle_receive_get(const code& ec, if (stopped(ec)) return; - // Enforce http origin policy (requires configured hosts). + // Enforce http origin form for get. + if (!is_origin_form(request->target())) + { + send_bad_target(*request); + return; + } + + // Enforce http origin policy (if any origins are configured). if (!is_allowed_origin(*request, request->version())) { send_forbidden(*request); @@ -55,67 +62,99 @@ void protocol_html::handle_receive_get(const code& ec, return; } - // Embedded page site. - if (dispatch_embedded(*request)) + // Always try API dispatch, false if unhandled. + if (try_dispatch_object(*request)) return; - // Empty path implies malformed target (terminal). - const auto path = to_local_path(request->target()); - if (path.empty()) + // Require file system dispatch if path is configured (always handles). + if (!options_.path.empty()) { - // TODO: split out sanitize from canonicalize so that this can return - // send_not_found() when the request is sanitary but not found. - send_bad_target(*request); + dispatch_file(*request); return; } - // Not open implies file not found (non-terminal). - auto file = get_file_body(path); - if (!file.is_open()) + // Require embedded dispatch if site is configured (always handles). + if (options_.pages.enabled()) { - send_not_found(*request); + dispatch_embedded(*request); return; } - send_file(*request, std::move(file), - file_mime_type(path, mime_type::application_octet_stream)); + // Neither site is enabled and object dispatch doesn't support. + send_not_implemented(*request); } // Dispatch. // ---------------------------------------------------------------------------- -bool protocol_html::dispatch_embedded(const request& request) NOEXCEPT +bool protocol_html::try_dispatch_object(const request&) NOEXCEPT { - // False only if not enabled, otherwise handled below. - if (!options_.pages.enabled()) - return false; + return false; +} +void protocol_html::dispatch_embedded(const request& request) NOEXCEPT +{ const auto& pages = config().server.explore.pages; switch (const auto mime = file_mime_type(to_path(request.target()))) { case mime_type::text_css: send_span(request, pages.css(), mime); - return true; + break; case mime_type::text_html: send_span(request, pages.html(), mime); - return true; + break; case mime_type::application_javascript: send_span(request, pages.ecma(), mime); - return true; + break; case mime_type::font_woff: case mime_type::font_woff2: send_span(request, pages.font(), mime); - return true; + break; case mime_type::image_png: case mime_type::image_gif: case mime_type::image_jpeg: send_span(request, pages.icon(), mime); - return true; + break; default: - return false; + send_not_found(request); } } +void protocol_html::dispatch_file(const request& request) NOEXCEPT +{ + // Empty path implies malformed target (terminal). + auto path = to_local_path(request.target()); + if (path.empty()) + { + send_bad_target(request); + return; + } + + // If no file extension it's REST on the single/default html page. + if (!path.has_extension()) + { + path = to_local_path(); + + // Default html page (e.g. index.html) is not configured. + if (path.empty()) + { + send_not_implemented(request); + return; + } + } + + // Get the single/default or explicitly requested page. + auto file = get_file_body(path); + if (!file.is_open()) + { + send_not_found(request); + return; + } + + const auto octet_stream = mime_type::application_octet_stream; + send_file(request, std::move(file), file_mime_type(path, octet_stream)); +} + // Senders. // ---------------------------------------------------------------------------- diff --git a/src/settings.cpp b/src/settings.cpp index 21d5584a9..bec9292f4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -81,9 +81,10 @@ std::filesystem::path settings::events_file() const NOEXCEPT namespace node { settings::settings() NOEXCEPT - : priority{ true }, - delay_inbound{ true }, + : delay_inbound{ true }, headers_first{ true }, + memory_priority{ true }, + thread_priority{ true }, allowed_deviation{ 1.5 }, announcement_cache{ 42 }, allocation_multiple{ 20 }, @@ -129,10 +130,20 @@ network::wall_clock::duration settings::currency_window() const NOEXCEPT return network::minutes(currency_window_minutes); } -network::thread_priority settings::priority_() const NOEXCEPT +network::processing_priority settings::thread_priority_() const NOEXCEPT { - return priority ? network::thread_priority::high : - network::thread_priority::normal; + // medium is "normal" (os default), so true is a behavior change. + // highest is too much, as it makes the opreating system UI unresponsive. + return thread_priority ? network::processing_priority::high : + network::processing_priority::medium; +} + +network::memory_priority settings::memory_priority_() const NOEXCEPT +{ + // highest is "normal" (os default), so false is a behavior change. + // highest is the OS default, so far low does not have a noticeable effect. + return memory_priority ? network::memory_priority::highest : + network::memory_priority::low; } } // namespace node diff --git a/test/settings.cpp b/test/settings.cpp index 3dba405b2..119f2eb8b 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(settings__node__default_context__expected) using namespace network; const node::settings node{}; - BOOST_REQUIRE_EQUAL(node.priority, true); + BOOST_REQUIRE_EQUAL(node.thread_priority, true); BOOST_REQUIRE_EQUAL(node.delay_inbound, true); BOOST_REQUIRE_EQUAL(node.headers_first, true); BOOST_REQUIRE_EQUAL(node.allowed_deviation, 1.5); @@ -77,7 +77,8 @@ BOOST_AUTO_TEST_CASE(settings__node__default_context__expected) BOOST_REQUIRE_EQUAL(node.maximum_concurrency_(), 50'000_size); BOOST_REQUIRE(node.sample_period() == steady_clock::duration(seconds(10))); BOOST_REQUIRE(node.currency_window() == steady_clock::duration(minutes(60))); - BOOST_REQUIRE(node.priority_() == network::thread_priority::high); + BOOST_REQUIRE(node.thread_priority_() == network::processing_priority::high); + BOOST_REQUIRE(node.memory_priority_() == network::memory_priority::highest); } // [server]