From a1ccfaafabb8ef4cfb759b6e44e37a795d63c834 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 30 Jan 2026 03:14:01 -0500 Subject: [PATCH 1/4] Clean up error translations and utils. --- include/bitcoin/network/error.hpp | 115 +++-- src/error.cpp | 711 ++++++++++++------------------ src/messages/http_body.cpp | 14 +- test/error.cpp | 67 ++- 4 files changed, 433 insertions(+), 474 deletions(-) diff --git a/include/bitcoin/network/error.hpp b/include/bitcoin/network/error.hpp index c996eb2cd..3f760b835 100644 --- a/include/bitcoin/network/error.hpp +++ b/include/bitcoin/network/error.hpp @@ -29,28 +29,13 @@ namespace network { /// std::error_code "network" category holds network::error::error_t. typedef std::error_code code; -/// Alias boost code. -/// Asio implements an equivalent to std::error_code. +/// Alias boost code - analagous to, but incompatible with, std::error_code. /// boost::system::error_code "system" category holds boost::asio::basic_errors. typedef boost::system::error_code boost_code; namespace error { -/// Alias asio code error enumeration. -/// boost::system::error_code "system" category holds boost::asio::basic_errors. -/// These are platform-specific error codes, for which we have seen variance. -/// boost::system::errc::errc_t is the boost::system error condition enum. -/// By comparing against conditions we obtain platform-independent error codes. -typedef boost::json::error json_error_t; -typedef boost::beast::http::error http_error_t; -typedef boost::beast::websocket::error ws_error_t; -typedef boost::system::errc::errc_t boost_error_t; -typedef boost::asio::error::misc_errors asio_misc_error_t; -typedef boost::asio::error::netdb_errors asio_netdb_error_t; -typedef boost::asio::error::basic_errors asio_system_error_t; -typedef boost::asio::ssl::error::stream_errors asio_ssl_stream_error_t; - -/// Asio failures are normalized to the error codes below. +/// Boost codes are translated to the system error codes below. /// Stop by explicit call is mapped to channel_stopped or service_stopped /// depending on the context. Asio errors returned on cancel calls are ignored. enum error_t : uint8_t @@ -144,7 +129,13 @@ enum error_t : uint8_t socks_unassigned_failure, socks_response_invalid, - // tls + // boost + system_unknown, + misc_unknown, + errc_unknown, + ssl_unknown, + + // boost tls tls_set_options, tls_use_certificate, tls_use_private_key, @@ -154,8 +145,9 @@ enum error_t : uint8_t tls_stream_truncated, tls_unspecified_system_error, tls_unexpected_result, + tls_unknown, - ////// http 4xx client error + // boost beast http 4xx client error bad_request, ////unauthorized, ////payment_required, @@ -186,7 +178,7 @@ enum error_t : uint8_t ////request_header_fields_too_large, ////unavailable_for_legal_reasons, - ////// http 5xx server error + // boost beast http 5xx server error internal_server_error, not_implemented, ////bad_gateway, @@ -226,6 +218,7 @@ enum error_t : uint8_t multiple_content_length, stale_parser, short_read, + http_unknown, // boost beast websocket error websocket_closed, @@ -259,6 +252,7 @@ enum error_t : uint8_t bad_close_code, bad_close_size, bad_close_payload, + websocket_unknown, // boost json error syntax, @@ -300,6 +294,7 @@ enum error_t : uint8_t size_mismatch, exhausted_variants, unknown_name, + json_unknown, // query string parse error message_overflow, @@ -326,57 +321,97 @@ enum error_t : uint8_t // No current need for error_code equivalence mapping. DECLARE_ERROR_T_CODE_CATEGORY(error); -inline boost_code to_system_code(boost_error_t ec) NOEXCEPT +/// Unfortunately std::error_code and boost::system::error_code are distinct +/// types, so they do not compare as would be expected across distinct +/// categories of one or the other type. One solution is to rely exclusively on +/// boost::system::error_code, but we prefer to normalize the public interface +/// on std::error_code, and eventually phase out boost codes. Also we prefer to +/// propagate only errors in library categories. To bridge the gap we map other +/// codes to network::error_t codes. This cannot be done using the equivalence +/// operator overloads of either, since the error_code types are distinct, +/// despite being effectively identical. So we provide this explicit mapping. + +/// Alias asio code error enumerations. +/// These are platform-specific error codes, for which we have seen variance. +/// boost::system::errc::errc_t is the boost::system error condition enum. +/// By comparing against conditions we obtain platform-independent error codes. +/// boost::system::error_code "system" category holds boost::asio::basic_errors. + +typedef boost::system::errc::errc_t boost_errc_t; +typedef boost::asio::error::basic_errors asio_basic_error_t; +typedef boost::asio::error::netdb_errors asio_netdb_error_t; +typedef boost::asio::error::addrinfo_errors asio_addrinfo_error_t; +typedef boost::asio::error::misc_errors asio_misc_error_t; +typedef boost::asio::ssl::error::stream_errors asio_ssl_stream_error_t; +typedef boost::beast::websocket::error ws_error_t; +typedef boost::beast::http::error http_error_t; +typedef boost::json::error json_error_t; + +inline boost_code to_asio_basic_code(asio_basic_error_t ec) NOEXCEPT { - return boost::system::errc::make_error_code(ec); + return { ec, boost::asio::error::get_system_category() }; } inline boost_code to_http_code(http_error_t ec) NOEXCEPT { + // no public category. + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) return boost::beast::http::make_error_code(ec); + BC_POP_WARNING() } -inline boost_code to_ws_code(ws_error_t ec) NOEXCEPT +inline boost_code to_ssl_stream_code(asio_ssl_stream_error_t ec) NOEXCEPT { + // boost::asio::ssl::error::stream::get_stream_category() + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + return boost::asio::ssl::error::make_error_code(ec); + BC_POP_WARNING() +} + +inline boost_code to_websocket_code(ws_error_t ec) NOEXCEPT +{ + // no public category. + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) return boost::beast::websocket::make_error_code(ec); + BC_POP_WARNING() } inline boost_code to_json_code(json_error_t ec) NOEXCEPT { + // boost::json::detail::error_code_category; return boost::json::make_error_code(ec); } -/// Unfortunately std::error_code and boost::system::error_code are distinct -/// types, so they do not compare as would be expected across distinct -/// categories of one or the other type. One solution is to rely exclusively on -/// boost::system::error_code, but we prefer to normalize the public interface -/// on std::error_code, and eventually phase out boost codes. Also we prefer to -/// propagate only errors in library categories. To bridge the gap we map other -/// codes to network::error_t codes. This cannot be done using the equivalence -/// operator overloads of either, since the error_code types are distinct, -/// despite being effectively identical. So we provide this explicit mapping. +inline boost_code to_errc_code(boost_errc_t ec) NOEXCEPT +{ + // boost::system::generic_category(); + return boost::system::errc::make_error_code(ec); +} /// Shortcircuit common boost code mapping. BCT_API bool asio_is_canceled(const boost_code& ec) NOEXCEPT; -/// mapping of boost::asio::ssl stream error codes to network (or error::unknown). -BCT_API code ssl_to_error_code(const boost_code& ec) NOEXCEPT; - -/// mapping of boost::asio error codes to network (or error::unknown). +/// mapping of boost::asio error codes to network. BCT_API code asio_to_error_code(const boost_code& ec) NOEXCEPT; -/// 1:1 mapping of boost::beast:http::error to network (or error::unknown). +/// 1:1 mapping of boost::beast:http::error to network. BCT_API code http_to_error_code(const boost_code& ec) NOEXCEPT; -/// 1:1 mapping of boost::beast::websocket::error to network (or error::unknown). +/// mapping of boost::asio::ssl stream error codes to network. +BCT_API code ssl_to_error_code(const boost_code& ec) NOEXCEPT; + +/// 1:1 mapping of boost::beast::websocket::error to network. BCT_API code ws_to_error_code(const boost_code& ec) NOEXCEPT; -/// 1:1 mapping of boost::json::error to network (or error::unknown). +/// 1:1 mapping of boost::json::error to network. BCT_API code json_to_error_code(const boost_code& ec) NOEXCEPT; -/// 1:1 mapping of wrapped json-rpc codes back to network (or error::unknown). +/// 1:1 mapping of wrapped json-rpc codes back to network. BCT_API code rpc_to_error_code(const boost_code& ec) NOEXCEPT; +/// mapping of boost::system::errc codes to network. +BCT_API code errc_to_error_code(const boost_code& ec) NOEXCEPT; + } // namespace error } // namespace network } // namespace libbitcoin diff --git a/src/error.cpp b/src/error.cpp index b8b98ff99..a1f0742b6 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -24,6 +24,8 @@ namespace libbitcoin { namespace network { namespace error { +BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + DEFINE_ERROR_T_MESSAGE_MAP(error) { { success, "success" }, @@ -115,7 +117,13 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { socks_unassigned_failure, "socks unassigned failure" }, { socks_response_invalid, "socks response invalid" }, - // tls + // boost + { system_unknown, "system error" }, + { misc_unknown, "misc error" }, + { errc_unknown, "errc error" }, + { ssl_unknown, "ssl error" }, + + // boost tls { tls_set_options, "failed to set tls options" }, { tls_use_certificate, "failed to set tls certificate" }, { tls_use_private_key, "failed to set tls private key" }, @@ -126,7 +134,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { tls_unspecified_system_error, "tls unspecified system error" }, { tls_unexpected_result, "tls unexpected result" }, - ////// http 4xx client error + // boost beast http 4xx client error { bad_request, "bad request" }, ////{ unauthorized, "unauthorized" }, ////{ payment_required, "payment required" }, @@ -157,7 +165,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) ////{ request_header_fields_too_large, "request header fields too large" }, ////{ unavailable_for_legal_reasons, "unavailable for legal reasons" }, - ////// http 5xx server error + // boost beast http 5xx server error { internal_server_error, "internal server error" }, { not_implemented, "not implemented" }, ////{ bad_gateway, "bad gateway" }, @@ -170,7 +178,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) ////{ not_extended, "not extended" }, ////{ network_authentication_required, "network authentication required" }, - // boost beast error + // boost beast http error { end_of_stream, "end of stream" }, { partial_message, "partial message" }, { need_more, "need more" }, @@ -197,6 +205,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { multiple_content_length, "multiple content length" }, { stale_parser, "stale parser" }, { short_read, "short read" }, + { http_unknown, "http error" }, // boost beast websocket error { websocket_closed, "websocket closed" }, @@ -230,6 +239,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { bad_close_code, "bad close code" }, { bad_close_size, "bad close size" }, { bad_close_payload, "bad close payload" }, + { websocket_unknown, "websocket error" }, // boost json error { syntax, "syntax error" }, @@ -271,6 +281,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) { size_mismatch, "size mismatch" }, { exhausted_variants, "exhausted variants" }, { unknown_name, "unknown name" }, + { json_unknown, "json error" }, // query string parse error { message_overflow, "message overflow" }, @@ -296,190 +307,130 @@ DEFINE_ERROR_T_MESSAGE_MAP(error) DEFINE_ERROR_T_CATEGORY(error, "network", "network code") -// boost_code overloads the `==` operator to include category. bool asio_is_canceled(const boost_code& ec) NOEXCEPT { - // self termination - return ec == boost_error_t::operation_canceled - || ec == boost::asio::error::operation_aborted; + return ec == asio_basic_error_t::operation_aborted + || ec == boost::system::errc::errc_t::operation_canceled; } -// TODO: change to cast model (like others). -// The success and operation_canceled codes are the only expected in normal -// operation, so these are first, to optimize the case where asio_is_canceled -// is not used. boost_code overloads the `==` operator to include category. +// includes asio_is_canceled code asio_to_error_code(const boost_code& ec) NOEXCEPT { if (!ec) return error::success; - // self termination - if (ec == boost_error_t::connection_aborted || - ec == boost_error_t::operation_canceled) + if (asio_is_canceled(ec)) return error::operation_canceled; - // peer termination - // stackoverflow.com/a/19891985/1172329 - if (ec == asio_misc_error_t::eof || - ec == boost_error_t::connection_reset) - return error::peer_disconnect; - - // learn.microsoft.com/en-us/troubleshoot/windows-client/networking/ - // connect-tcp-greater-than-5000-error-wsaenobufs-10055 - if (ec == asio_system_error_t::no_buffer_space) - return error::invalid_configuration; - - // network - if (ec == boost_error_t::operation_not_permitted || - ec == boost_error_t::operation_not_supported || - ec == boost_error_t::owner_dead || - ec == boost_error_t::permission_denied) - return error::not_allowed; - - // connect-resolve - if (ec == boost_error_t::address_family_not_supported || - ec == boost_error_t::bad_address || - ec == boost_error_t::destination_address_required || - ec == asio_netdb_error_t::host_not_found || - ec == asio_netdb_error_t::host_not_found_try_again) - return error::resolve_failed; - - // connect-connect - if (ec == boost_error_t::address_not_available || - ec == boost_error_t::not_connected || - ec == boost_error_t::connection_refused || - ec == boost_error_t::broken_pipe || - ec == boost_error_t::host_unreachable || - ec == boost_error_t::network_down || - ec == boost_error_t::network_reset || - ec == boost_error_t::network_unreachable || - ec == boost_error_t::no_link || - ec == boost_error_t::no_protocol_option || - ec == boost_error_t::no_such_file_or_directory || - ec == boost_error_t::not_a_socket || - ec == boost_error_t::protocol_not_supported || - ec == boost_error_t::wrong_protocol_type) - return error::connect_failed; - - // connect-address - if (ec == boost_error_t::address_in_use || - ec == boost_error_t::already_connected || - ec == boost_error_t::connection_already_in_progress || - ec == boost_error_t::operation_in_progress) - return error::address_in_use; - - // I/O (bad_file_descriptor if socket is not initialized) - if (ec == boost_error_t::bad_file_descriptor || - ec == boost_error_t::bad_message || - ec == boost_error_t::illegal_byte_sequence || - ec == boost_error_t::io_error || - ec == boost_error_t::message_size || - ec == boost_error_t::no_message_available || - ec == boost_error_t::no_message || - ec == boost_error_t::no_stream_resources || - ec == boost_error_t::not_a_stream || - ec == boost_error_t::protocol_error) - return error::bad_stream; - - // timeout - if (ec == boost_error_t::stream_timeout || - ec == boost_error_t::timed_out) - return error::channel_timeout; - - // file system errors (bad_file_descriptor used in I/O) - if (ec == boost_error_t::cross_device_link || - ec == boost_error_t::device_or_resource_busy || - ec == boost_error_t::directory_not_empty || - ec == boost_error_t::executable_format_error || - ec == boost_error_t::file_exists || - ec == boost_error_t::file_too_large || - ec == boost_error_t::filename_too_long || - ec == boost_error_t::invalid_seek || - ec == boost_error_t::is_a_directory || - ec == boost_error_t::no_space_on_device || - ec == boost_error_t::no_such_device || - ec == boost_error_t::no_such_device_or_address || - ec == boost_error_t::read_only_file_system || - ec == boost_error_t::resource_unavailable_try_again || - ec == boost_error_t::text_file_busy || - ec == boost_error_t::too_many_files_open || - ec == boost_error_t::too_many_files_open_in_system || - ec == boost_error_t::too_many_links || - ec == boost_error_t::too_many_symbolic_link_levels) - return error::file_system; - - ////// unknown - ////if (ec == boost_error_t::argument_list_too_long || - //// ec == boost_error_t::argument_out_of_domain || - //// ec == boost_error_t::function_not_supported || - //// ec == boost_error_t::identifier_removed || - //// ec == boost_error_t::inappropriate_io_control_operation || - //// ec == boost_error_t::interrupted || - //// ec == boost_error_t::invalid_argument || - //// ec == boost_error_t::no_buffer_space || - //// ec == boost_error_t::no_child_process || - //// ec == boost_error_t::no_lock_available || - //// ec == boost_error_t::no_such_process || - //// ec == boost_error_t::not_a_directory || - //// ec == boost_error_t::not_enough_memory || - //// ec == boost_error_t::operation_would_block || - //// ec == boost_error_t::resource_deadlock_would_occur || - //// ec == boost_error_t::result_out_of_range || - //// ec == boost_error_t::state_not_recoverable || - //// ec == boost_error_t::value_too_large) - - // TODO: return asio category generic error. - return error::unknown; -} - -// Boost defines this for error numbers produced by openssl. But we get generic -// error codes because WOLFSSL_HAVE_ERROR_QUEUE is not defined. This is because -// otherwise in some cases we fail to get failure results when necessary. -////typedef boost::asio::error::ssl_errors asio_ssl_error_t; -////const auto& category = boost::asio::error::get_ssl_category(); - -// includes asio codes -code ssl_to_error_code(const boost_code& ec) NOEXCEPT -{ - const auto& category = boost::asio::ssl::error::get_stream_category(); - - if (!ec) - return error::success; - - if (ec.category() != category) - return asio_to_error_code(ec); - - switch (static_cast(ec.value())) + // boost::system::system_category() is aliased for netdb and addrinfo. + if (ec.category() == boost::asio::error::get_system_category()) { - case asio_ssl_stream_error_t::stream_truncated: - return error::tls_stream_truncated; - case asio_ssl_stream_error_t::unspecified_system_error: - return error::tls_unspecified_system_error; - case asio_ssl_stream_error_t::unexpected_result: - return error::tls_unexpected_result; - - // TODO: return ssl category generic error. - default: return error::unknown; + switch (static_cast(ec.value())) + { + case asio_basic_error_t::connection_aborted: + return error::operation_canceled; + + case asio_basic_error_t::operation_aborted: + return error::operation_failed; + + case asio_basic_error_t::address_family_not_supported: + return error::resolve_failed; + + case asio_basic_error_t::address_in_use: + case asio_basic_error_t::already_connected: + case asio_basic_error_t::already_started: + case asio_basic_error_t::in_progress: + return error::address_in_use; + + case asio_basic_error_t::shut_down: + case asio_basic_error_t::would_block: + case asio_basic_error_t::broken_pipe: + case asio_basic_error_t::connection_refused: + case asio_basic_error_t::host_unreachable: + case asio_basic_error_t::network_down: + case asio_basic_error_t::network_reset: + case asio_basic_error_t::network_unreachable: + case asio_basic_error_t::no_protocol_option: + case asio_basic_error_t::not_connected: + case asio_basic_error_t::not_socket: + return error::connect_failed; + + case asio_basic_error_t::connection_reset: + return error::peer_disconnect; + + case asio_basic_error_t::bad_descriptor: + case asio_basic_error_t::message_size: + return error::bad_stream; + + case asio_basic_error_t::no_memory: + case asio_basic_error_t::fault: + case asio_basic_error_t::interrupted: + case asio_basic_error_t::invalid_argument: + case asio_basic_error_t::name_too_long: + case asio_basic_error_t::no_descriptors: + case asio_basic_error_t::no_buffer_space: + return error::invalid_configuration; + + case asio_basic_error_t::try_again: + case asio_basic_error_t::no_such_device: + return error::file_system; + + case asio_basic_error_t::access_denied: + case asio_basic_error_t::no_permission: + case asio_basic_error_t::operation_not_supported: + return error::not_allowed; + + case asio_basic_error_t::timed_out: + return error::channel_timeout; + } + + switch (static_cast(ec.value())) + { + // connect-resolve + case asio_netdb_error_t::host_not_found: + case asio_netdb_error_t::host_not_found_try_again: + return error::resolve_failed; + + case asio_netdb_error_t::no_data: + case asio_netdb_error_t::no_recovery: + return error::operation_failed; + } + + switch (static_cast(ec.value())) + { + // connect-resolve + case asio_addrinfo_error_t::service_not_found: + case asio_addrinfo_error_t::socket_type_not_supported: + return error::resolve_failed; + } } -} - -// includes http codes -code rpc_to_error_code(const boost_code& ec) NOEXCEPT -{ - if (!ec) - return error::success; - if (ec.category() == network::error::error_category::singleton) - return { static_cast(ec.value()) }; + // Independent category. + if (ec.category() == boost::asio::error::get_misc_category()) + { + switch (static_cast(ec.value())) + { + // peer termination + // stackoverflow.com/a/19891985/1172329 + case asio_misc_error_t::eof: + return error::peer_disconnect; + case asio_misc_error_t::already_open: + return error::connect_failed; + case asio_misc_error_t::not_found: + return error::resolve_failed; + case asio_misc_error_t::fd_set_failure: + return error::file_system; + } + } - return http_to_error_code(ec); + return error::system_unknown; } // includes json codes code http_to_error_code(const boost_code& ec) NOEXCEPT { - // TODO: use boost static initializer. - static boost::beast::http::detail::http_error_category category{}; + static const auto& category = to_http_code( + boost::beast::http::error::end_of_stream).category(); if (!ec) return error::success; @@ -515,17 +466,57 @@ code http_to_error_code(const boost_code& ec) NOEXCEPT case http_error_t::multiple_content_length: return error::multiple_content_length; case http_error_t::stale_parser: return error::stale_parser; case http_error_t::short_read: return error::short_read; + default: return error::http_unknown; + } +} + +// includes asio codes +code ssl_to_error_code(const boost_code& ec) NOEXCEPT +{ + if (!ec) + return error::success; - // TODO: return http category generic error. - default: return error::unknown; + namespace stream = boost::asio::ssl::error; + if (ec.category() == stream::get_stream_category()) + { + switch (static_cast(ec.value())) + { + case asio_ssl_stream_error_t::stream_truncated: + return error::tls_stream_truncated; + case asio_ssl_stream_error_t::unspecified_system_error: + return error::tls_unspecified_system_error; + case asio_ssl_stream_error_t::unexpected_result: + return error::tls_unexpected_result; + default: return error::tls_unknown; + } } + + // Boost defines this for error numbers produced by openssl. But we get + // generic error codes because WOLFSSL_HAVE_ERROR_QUEUE is not defined. + // This is because otherwise in some cases we fail to get failure results + // when necessary. These are openssl-in-boost-category codes, for + // simplified transport. + + if (ec.category() == boost::asio::error::get_ssl_category()) + { + // TODO: map openssl native code values to network. + ////switch (ec.value()) + ////{ + //// default: return error::ssl_unknown; + ////} + + return error::ssl_unknown; + } + + return asio_to_error_code(ec); } + // includes json codes code ws_to_error_code(const boost_code& ec) NOEXCEPT { - // TODO: use boost static initializer. - static boost::beast::websocket::detail::error_codes category{}; + static const auto& category = to_websocket_code( + boost::beast::websocket::error::closed).category(); if (!ec) return error::success; @@ -566,21 +557,17 @@ code ws_to_error_code(const boost_code& ec) NOEXCEPT case ws_error_t::bad_close_code: return error::bad_close_code; case ws_error_t::bad_close_size: return error::bad_close_size; case ws_error_t::bad_close_payload: return error::bad_close_payload; - - // TODO: return ws category generic error. - default: return error::unknown; + default: return error::websocket_unknown; } } +// includes asio codes code json_to_error_code(const boost_code& ec) NOEXCEPT { - // TODO: use boost static initializer. - static boost::json::detail::error_code_category_t category{}; - if (!ec) return error::success; - if (ec.category() != category) + if (ec.category() != boost::json::detail::error_code_category) return asio_to_error_code(ec); switch (static_cast(ec.value())) @@ -624,262 +611,134 @@ code json_to_error_code(const boost_code& ec) NOEXCEPT case json_error_t::size_mismatch: return error::size_mismatch; case json_error_t::exhausted_variants: return error::exhausted_variants; case json_error_t::unknown_name: return error::unknown_name; - - // TODO: return json category generic error. - default: return error::unknown; + default: return error::json_unknown; } } -} // namespace error -} // namespace network -} // namespace libbitcoin - -// Just for reference. -#ifdef BOOST_CODES_AND_CONDITIONS - -// Boost: asio error enum (basic subset, platform specific codes). -enum boost::asio::error::basic_errors -{ - /// Permission denied. - access_denied = BOOST_ASIO_SOCKET_ERROR(EACCES), - - /// Address family not supported by protocol. - address_family_not_supported = BOOST_ASIO_SOCKET_ERROR(EAFNOSUPPORT), - - /// Address already in use. - address_in_use = BOOST_ASIO_SOCKET_ERROR(EADDRINUSE), - - /// Transport endpoint is already connected. - already_connected = BOOST_ASIO_SOCKET_ERROR(EISCONN), - - /// Operation already in progress. - already_started = BOOST_ASIO_SOCKET_ERROR(EALREADY), - - /// Broken pipe. - broken_pipe = BOOST_ASIO_WIN_OR_POSIX( - BOOST_ASIO_NATIVE_ERROR(ERROR_BROKEN_PIPE), - BOOST_ASIO_NATIVE_ERROR(EPIPE)), - - /// A connection has been aborted. - connection_aborted = BOOST_ASIO_SOCKET_ERROR(ECONNABORTED), - - /// Connection refused. - connection_refused = BOOST_ASIO_SOCKET_ERROR(ECONNREFUSED), - - /// Connection reset by peer. - connection_reset = BOOST_ASIO_SOCKET_ERROR(ECONNRESET), - - /// Bad file descriptor. - bad_descriptor = BOOST_ASIO_SOCKET_ERROR(EBADF), - - /// Bad address. - fault = BOOST_ASIO_SOCKET_ERROR(EFAULT), - - /// No route to host. - host_unreachable = BOOST_ASIO_SOCKET_ERROR(EHOSTUNREACH), - - /// Operation now in progress. - in_progress = BOOST_ASIO_SOCKET_ERROR(EINPROGRESS), - - /// Interrupted system call. - interrupted = BOOST_ASIO_SOCKET_ERROR(EINTR), - - /// Invalid argument. - invalid_argument = BOOST_ASIO_SOCKET_ERROR(EINVAL), - - /// Message too long. - message_size = BOOST_ASIO_SOCKET_ERROR(EMSGSIZE), - - /// The name was too long. - name_too_long = BOOST_ASIO_SOCKET_ERROR(ENAMETOOLONG), - - /// Network is down. - network_down = BOOST_ASIO_SOCKET_ERROR(ENETDOWN), - - /// Network dropped connection on reset. - network_reset = BOOST_ASIO_SOCKET_ERROR(ENETRESET), - - /// Network is unreachable. - network_unreachable = BOOST_ASIO_SOCKET_ERROR(ENETUNREACH), - - /// Too many open files. - no_descriptors = BOOST_ASIO_SOCKET_ERROR(EMFILE), - - /// No buffer space available. - no_buffer_space = BOOST_ASIO_SOCKET_ERROR(ENOBUFS), - - /// Cannot allocate memory. - no_memory = BOOST_ASIO_WIN_OR_POSIX( - BOOST_ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY), - BOOST_ASIO_NATIVE_ERROR(ENOMEM)), - - /// Operation not permitted. - no_permission = BOOST_ASIO_WIN_OR_POSIX( - BOOST_ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED), - BOOST_ASIO_NATIVE_ERROR(EPERM)), - - /// Protocol not available. - no_protocol_option = BOOST_ASIO_SOCKET_ERROR(ENOPROTOOPT), - - /// No such device. - no_such_device = BOOST_ASIO_WIN_OR_POSIX( - BOOST_ASIO_NATIVE_ERROR(ERROR_BAD_UNIT), - BOOST_ASIO_NATIVE_ERROR(ENODEV)), - - /// Transport endpoint is not connected. - not_connected = BOOST_ASIO_SOCKET_ERROR(ENOTCONN), - - /// Socket operation on non-socket. - not_socket = BOOST_ASIO_SOCKET_ERROR(ENOTSOCK), - - /// Operation canceled. - operation_aborted = BOOST_ASIO_WIN_OR_POSIX( - BOOST_ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED), - BOOST_ASIO_NATIVE_ERROR(ECANCELED)), - - /// Operation not supported. - operation_not_supported = BOOST_ASIO_SOCKET_ERROR(EOPNOTSUPP), - - /// Cannot send after transport endpoint shutdown. - shut_down = BOOST_ASIO_SOCKET_ERROR(ESHUTDOWN), - - /// Connection timed out. - timed_out = BOOST_ASIO_SOCKET_ERROR(ETIMEDOUT), - - /// Resource temporarily unavailable. - try_again = BOOST_ASIO_WIN_OR_POSIX( - BOOST_ASIO_NATIVE_ERROR(ERROR_RETRY), - BOOST_ASIO_NATIVE_ERROR(EAGAIN)), - - /// Socket is marked non-blocking and requested operation would block. - would_block = BOOST_ASIO_SOCKET_ERROR(EWOULDBLOCK) -}; - -// Boost: system error enum for error_conditions (platform-independent codes). -enum boost::system::errc::errc_t -{ - success = 0, - address_family_not_supported = EAFNOSUPPORT, - address_in_use = EADDRINUSE, - address_not_available = EADDRNOTAVAIL, - already_connected = EISCONN, - argument_list_too_long = E2BIG, - argument_out_of_domain = EDOM, - bad_address = EFAULT, - bad_file_descriptor = EBADF, - bad_message = EBADMSG, - broken_pipe = EPIPE, - connection_aborted = ECONNABORTED, - connection_already_in_progress = EALREADY, - connection_refused = ECONNREFUSED, - connection_reset = ECONNRESET, - cross_device_link = EXDEV, - destination_address_required = EDESTADDRREQ, - device_or_resource_busy = EBUSY, - directory_not_empty = ENOTEMPTY, - executable_format_error = ENOEXEC, - file_exists = EEXIST, - file_too_large = EFBIG, - filename_too_long = ENAMETOOLONG, - function_not_supported = ENOSYS, - host_unreachable = EHOSTUNREACH, - identifier_removed = EIDRM, - illegal_byte_sequence = EILSEQ, - inappropriate_io_control_operation = ENOTTY, - interrupted = EINTR, - invalid_argument = EINVAL, - invalid_seek = ESPIPE, - io_error = EIO, - is_a_directory = EISDIR, - message_size = EMSGSIZE, - network_down = ENETDOWN, - network_reset = ENETRESET, - network_unreachable = ENETUNREACH, - no_buffer_space = ENOBUFS, - no_child_process = ECHILD, - no_link = ENOLINK, - no_lock_available = ENOLCK, - no_message_available = ENODATA, - no_message = ENOMSG, - no_protocol_option = ENOPROTOOPT, - no_space_on_device = ENOSPC, - no_stream_resources = ENOSR, - no_such_device_or_address = ENXIO, - no_such_device = ENODEV, - no_such_file_or_directory = ENOENT, - no_such_process = ESRCH, - not_a_directory = ENOTDIR, - not_a_socket = ENOTSOCK, - not_a_stream = ENOSTR, - not_connected = ENOTCONN, - not_enough_memory = ENOMEM, - not_supported = ENOTSUP, - operation_canceled = ECANCELED, - operation_in_progress = EINPROGRESS, - operation_not_permitted = EPERM, - operation_not_supported = EOPNOTSUPP, - operation_would_block = EWOULDBLOCK, - owner_dead = EOWNERDEAD, - permission_denied = EACCES, - protocol_error = EPROTO, - protocol_not_supported = EPROTONOSUPPORT, - read_only_file_system = EROFS, - resource_deadlock_would_occur = EDEADLK, - resource_unavailable_try_again = EAGAIN, - result_out_of_range = ERANGE, - state_not_recoverable = ENOTRECOVERABLE, - stream_timeout = ETIME, - text_file_busy = ETXTBSY, - timed_out = ETIMEDOUT, - too_many_files_open_in_system = ENFILE, - too_many_files_open = EMFILE, - too_many_links = EMLINK, - too_many_symbolic_link_levels = ELOOP, - value_too_large = EOVERFLOW, - wrong_protocol_type = EPROTOTYPE -}; - -enum netdb_errors +// includes http codes +code rpc_to_error_code(const boost_code& ec) NOEXCEPT { - /// Host not found (authoritative). - host_not_found = BOOST_ASIO_NETDB_ERROR(HOST_NOT_FOUND), - - /// Host not found (non-authoritative). - host_not_found_try_again = BOOST_ASIO_NETDB_ERROR(TRY_AGAIN), - - /// The query is valid but does not have associated address data. - no_data = BOOST_ASIO_NETDB_ERROR(NO_DATA), + if (!ec) + return error::success; - /// A non-recoverable error occurred. - no_recovery = BOOST_ASIO_NETDB_ERROR(NO_RECOVERY) -}; + // These are libbitcoin-category-in-boost codes, for simplified transport. + if (ec.category() == network::error::error_category::singleton) + return { static_cast(ec.value()) }; -enum addrinfo_errors -{ - /// The service is not supported for the given socket type. - service_not_found = BOOST_ASIO_WIN_OR_POSIX( - BOOST_ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND), - BOOST_ASIO_GETADDRINFO_ERROR(EAI_SERVICE)), - - /// The socket type is not supported. - socket_type_not_supported = BOOST_ASIO_WIN_OR_POSIX( - BOOST_ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT), - BOOST_ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)) -}; + return http_to_error_code(ec); +} -enum misc_errors +// Boost cross platform codes (not asio). +code errc_to_error_code(const boost_code& ec) NOEXCEPT { - /// Already open. - already_open = 1, + if (!ec) + return error::success; - /// End of file or stream. - eof, + if (ec.category() == boost::system::generic_category()) + { + switch (static_cast(ec.value())) + { + case boost_errc_t::connection_aborted: + case boost_errc_t::operation_canceled: + return error::operation_canceled; + + // peer termination + // stackoverflow.com/a/19891985/1172329 + case boost_errc_t::connection_reset: + return error::peer_disconnect; + + // learn.microsoft.com/en-us/troubleshoot/windows-client/networking/ + // connect-tcp-greater-than-5000-error-wsaenobufs-10055 + case boost_errc_t::no_buffer_space: + return error::invalid_configuration; + + // network + case boost_errc_t::operation_not_permitted: + case boost_errc_t::operation_not_supported: + case boost_errc_t::owner_dead: + case boost_errc_t::permission_denied: + return error::not_allowed; + + // connect-resolve + case boost_errc_t::address_family_not_supported: + case boost_errc_t::bad_address: + case boost_errc_t::destination_address_required: + return error::resolve_failed; + + // connect-connect + case boost_errc_t::address_not_available: + case boost_errc_t::not_connected: + case boost_errc_t::connection_refused: + case boost_errc_t::broken_pipe: + case boost_errc_t::host_unreachable: + case boost_errc_t::network_down: + case boost_errc_t::network_reset: + case boost_errc_t::network_unreachable: + case boost_errc_t::no_link: + case boost_errc_t::no_protocol_option: + case boost_errc_t::no_such_file_or_directory: + case boost_errc_t::not_a_socket: + case boost_errc_t::protocol_not_supported: + case boost_errc_t::wrong_protocol_type: + return error::connect_failed; + + // connect-address + case boost_errc_t::address_in_use: + case boost_errc_t::already_connected: + case boost_errc_t::connection_already_in_progress: + case boost_errc_t::operation_in_progress: + return error::address_in_use; + + // I/O (bad_file_descriptor if socket is not initialized) + case boost_errc_t::bad_file_descriptor: + case boost_errc_t::bad_message: + case boost_errc_t::illegal_byte_sequence: + case boost_errc_t::io_error: + case boost_errc_t::message_size: + case boost_errc_t::no_message_available: + case boost_errc_t::no_message: + case boost_errc_t::no_stream_resources: + case boost_errc_t::not_a_stream: + case boost_errc_t::protocol_error: + return error::bad_stream; + + // timeout + case boost_errc_t::stream_timeout: + case boost_errc_t::timed_out: + return error::channel_timeout; + + // file system errors (bad_file_descriptor used in I/O) + case boost_errc_t::cross_device_link: + case boost_errc_t::device_or_resource_busy: + case boost_errc_t::directory_not_empty: + case boost_errc_t::executable_format_error: + case boost_errc_t::file_exists: + case boost_errc_t::file_too_large: + case boost_errc_t::filename_too_long: + case boost_errc_t::invalid_seek: + case boost_errc_t::is_a_directory: + case boost_errc_t::no_space_on_device: + case boost_errc_t::no_such_device: + case boost_errc_t::no_such_device_or_address: + case boost_errc_t::read_only_file_system: + case boost_errc_t::resource_unavailable_try_again: + case boost_errc_t::text_file_busy: + case boost_errc_t::too_many_files_open: + case boost_errc_t::too_many_files_open_in_system: + case boost_errc_t::too_many_links: + case boost_errc_t::too_many_symbolic_link_levels: + return error::file_system; + + default: + return error::errc_unknown; + } + } - /// Element not found. - not_found, + return error::unknown; +} - /// The descriptor cannot fit into the select system call's fd_set. - fd_set_failure -}; +BC_POP_WARNING() -#endif // BOOST_CODES_AND_CONDITIONS \ No newline at end of file +} // namespace error +} // namespace network +} // namespace libbitcoin diff --git a/src/messages/http_body.cpp b/src/messages/http_body.cpp index e77167d97..72c5c7ff4 100644 --- a/src/messages/http_body.cpp +++ b/src/messages/http_body.cpp @@ -39,7 +39,7 @@ void body::reader::init(const length_type& length, boost_code& ec) NOEXCEPT { [&](std::monostate&) NOEXCEPT { - ec = to_system_code(boost_error_t::io_error); + ec = to_http_code(http_error_t::end_of_stream); }, [&](auto& read) NOEXCEPT { @@ -49,7 +49,7 @@ void body::reader::init(const length_type& length, boost_code& ec) NOEXCEPT } catch (...) { - ec = to_system_code(boost_error_t::io_error); + ec = to_http_code(http_error_t::end_of_stream); } } }, reader_); @@ -61,7 +61,7 @@ size_t body::reader::put(const buffer_type& buffer, boost_code& ec) NOEXCEPT { [&](std::monostate&) NOEXCEPT { - ec = to_system_code(boost_error_t::io_error); + ec = to_http_code(http_error_t::end_of_stream); return size_t{}; }, [&](auto& read) NOEXCEPT @@ -72,7 +72,7 @@ size_t body::reader::put(const buffer_type& buffer, boost_code& ec) NOEXCEPT } catch (...) { - ec = to_system_code(boost_error_t::io_error); + ec = to_http_code(http_error_t::end_of_stream); return size_t{}; } } @@ -96,7 +96,7 @@ void body::reader::finish(boost_code& ec) NOEXCEPT } catch (...) { - ec = to_system_code(boost_error_t::io_error); + ec = to_http_code(http_error_t::end_of_stream); } } }, reader_); @@ -120,7 +120,7 @@ void body::writer::init(boost_code& ec) NOEXCEPT } catch (...) { - ec = to_system_code(boost_error_t::io_error); + ec = to_http_code(http_error_t::end_of_stream); } } }, writer_); @@ -142,7 +142,7 @@ body::writer::out_buffer body::writer::get(boost_code& ec) NOEXCEPT } catch (...) { - ec = to_system_code(boost_error_t::io_error); + ec = to_http_code(http_error_t::end_of_stream); return out_buffer{}; } } diff --git a/test/error.cpp b/test/error.cpp index c9960b8dc..af0d29fab 100644 --- a/test/error.cpp +++ b/test/error.cpp @@ -637,7 +637,45 @@ BOOST_AUTO_TEST_CASE(error_t__code__socks_response_invalid__true_expected_messag BOOST_REQUIRE_EQUAL(ec.message(), "socks response invalid"); } -// tls +// boost + +BOOST_AUTO_TEST_CASE(error_t__code__system_unknown__true_expected_message) +{ + constexpr auto value = error::system_unknown; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "system error"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__misc_unknown__true_expected_message) +{ + constexpr auto value = error::misc_unknown; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "misc error"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__errc_unknown__true_expected_message) +{ + constexpr auto value = error::errc_unknown; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "errc error"); +} + +BOOST_AUTO_TEST_CASE(error_t__code__ssl_unknown__true_expected_message) +{ + constexpr auto value = error::ssl_unknown; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "ssl error"); +} + +// boost tls BOOST_AUTO_TEST_CASE(error_t__code__tls_set_options__true_expected_message) { @@ -1320,6 +1358,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__short_read__true_expected_message) BOOST_REQUIRE_EQUAL(ec.message(), "short read"); } +BOOST_AUTO_TEST_CASE(error_t__code__http_unknown__true_expected_message) +{ + constexpr auto value = error::http_unknown; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "http error"); +} + // boost beast websocket error BOOST_AUTO_TEST_CASE(error_t__code__websocket_closed__true_expected_message) @@ -1601,6 +1648,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__bad_close_payload__true_expected_message) BOOST_REQUIRE_EQUAL(ec.message(), "bad close payload"); } +BOOST_AUTO_TEST_CASE(error_t__code__websocket_unknown__true_expected_message) +{ + constexpr auto value = error::websocket_unknown; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "websocket error"); +} + // boost json error BOOST_AUTO_TEST_CASE(error_t__code__syntax__true_expected_message) @@ -1954,6 +2010,15 @@ BOOST_AUTO_TEST_CASE(error_t__code__unknown_name__true_expected_message) BOOST_REQUIRE_EQUAL(ec.message(), "unknown name"); } +BOOST_AUTO_TEST_CASE(error_t__code__json_unknown__true_expected_message) +{ + constexpr auto value = error::json_unknown; + const auto ec = code(value); + BOOST_REQUIRE(ec); + BOOST_REQUIRE(ec == value); + BOOST_REQUIRE_EQUAL(ec.message(), "json error"); +} + // query string parse error BOOST_AUTO_TEST_CASE(error_t__code__message_overflow__true_expected_message) From 0d48f1b69185cf56842d3104d8c1514ca0457f7c Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 31 Jan 2026 01:33:34 -0500 Subject: [PATCH 2/4] Disable duplicated error case condition. --- src/error.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/error.cpp b/src/error.cpp index a1f0742b6..6025ee898 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -371,7 +371,8 @@ code asio_to_error_code(const boost_code& ec) NOEXCEPT case asio_basic_error_t::no_buffer_space: return error::invalid_configuration; - case asio_basic_error_t::try_again: + // This duplicates would_block except on MSVC. + ////case asio_basic_error_t::try_again: case asio_basic_error_t::no_such_device: return error::file_system; From 53c1546583ff8cfcf6a9a6641406664d0c06b454 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 31 Jan 2026 03:00:13 -0500 Subject: [PATCH 3/4] Integrate boost errc codes into asio code translation. --- src/error.cpp | 230 ++++++++++++++++++++++++-------------------------- 1 file changed, 112 insertions(+), 118 deletions(-) diff --git a/src/error.cpp b/src/error.cpp index 6025ee898..83ed61e52 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -313,26 +313,130 @@ bool asio_is_canceled(const boost_code& ec) NOEXCEPT || ec == boost::system::errc::errc_t::operation_canceled; } -// includes asio_is_canceled -code asio_to_error_code(const boost_code& ec) NOEXCEPT +// Boost cross platform codes (not asio). +code errc_to_error_code(const boost_code& ec) NOEXCEPT { if (!ec) return error::success; - if (asio_is_canceled(ec)) - return error::operation_canceled; + if (ec.category() == boost::system::generic_category()) + { + switch (static_cast(ec.value())) + { + case boost_errc_t::connection_aborted: + case boost_errc_t::operation_canceled: + return error::operation_canceled; + + // peer termination + // stackoverflow.com/a/19891985/1172329 + case boost_errc_t::connection_reset: + return error::peer_disconnect; + + // learn.microsoft.com/en-us/troubleshoot/windows-client/networking/ + // connect-tcp-greater-than-5000-error-wsaenobufs-10055 + case boost_errc_t::no_buffer_space: + return error::invalid_configuration; + + // network + case boost_errc_t::operation_not_permitted: + case boost_errc_t::operation_not_supported: + case boost_errc_t::owner_dead: + case boost_errc_t::permission_denied: + return error::not_allowed; + + // connect-resolve + case boost_errc_t::address_family_not_supported: + case boost_errc_t::bad_address: + case boost_errc_t::destination_address_required: + return error::resolve_failed; + + // connect-connect + case boost_errc_t::address_not_available: + case boost_errc_t::not_connected: + case boost_errc_t::connection_refused: + case boost_errc_t::broken_pipe: + case boost_errc_t::host_unreachable: + case boost_errc_t::network_down: + case boost_errc_t::network_reset: + case boost_errc_t::network_unreachable: + case boost_errc_t::no_link: + case boost_errc_t::no_protocol_option: + case boost_errc_t::no_such_file_or_directory: + case boost_errc_t::not_a_socket: + case boost_errc_t::protocol_not_supported: + case boost_errc_t::wrong_protocol_type: + return error::connect_failed; + + // connect-address + case boost_errc_t::address_in_use: + case boost_errc_t::already_connected: + case boost_errc_t::connection_already_in_progress: + case boost_errc_t::operation_in_progress: + return error::address_in_use; + + // I/O (bad_file_descriptor if socket is not initialized) + case boost_errc_t::bad_file_descriptor: + case boost_errc_t::bad_message: + case boost_errc_t::illegal_byte_sequence: + case boost_errc_t::io_error: + case boost_errc_t::message_size: + case boost_errc_t::no_message_available: + case boost_errc_t::no_message: + case boost_errc_t::no_stream_resources: + case boost_errc_t::not_a_stream: + case boost_errc_t::protocol_error: + return error::bad_stream; + + // timeout + case boost_errc_t::stream_timeout: + case boost_errc_t::timed_out: + return error::channel_timeout; + + // file system errors (bad_file_descriptor used in I/O) + case boost_errc_t::cross_device_link: + case boost_errc_t::device_or_resource_busy: + case boost_errc_t::directory_not_empty: + case boost_errc_t::executable_format_error: + case boost_errc_t::file_exists: + case boost_errc_t::file_too_large: + case boost_errc_t::filename_too_long: + case boost_errc_t::invalid_seek: + case boost_errc_t::is_a_directory: + case boost_errc_t::no_space_on_device: + case boost_errc_t::no_such_device: + case boost_errc_t::no_such_device_or_address: + case boost_errc_t::read_only_file_system: + case boost_errc_t::resource_unavailable_try_again: + case boost_errc_t::text_file_busy: + case boost_errc_t::too_many_files_open: + case boost_errc_t::too_many_files_open_in_system: + case boost_errc_t::too_many_links: + case boost_errc_t::too_many_symbolic_link_levels: + return error::file_system; + + default: + return error::errc_unknown; + } + } + + return error::unknown; +} + +// includes errc_to_error_code +code asio_to_error_code(const boost_code& ec) NOEXCEPT +{ + if (!ec) + return error::success; // boost::system::system_category() is aliased for netdb and addrinfo. if (ec.category() == boost::asio::error::get_system_category()) { switch (static_cast(ec.value())) { + case asio_basic_error_t::operation_aborted: case asio_basic_error_t::connection_aborted: return error::operation_canceled; - case asio_basic_error_t::operation_aborted: - return error::operation_failed; - case asio_basic_error_t::address_family_not_supported: return error::resolve_failed; @@ -424,7 +528,7 @@ code asio_to_error_code(const boost_code& ec) NOEXCEPT } } - return error::system_unknown; + return errc_to_error_code(ec); } // includes json codes @@ -512,7 +616,6 @@ code ssl_to_error_code(const boost_code& ec) NOEXCEPT return asio_to_error_code(ec); } - // includes json codes code ws_to_error_code(const boost_code& ec) NOEXCEPT { @@ -629,115 +732,6 @@ code rpc_to_error_code(const boost_code& ec) NOEXCEPT return http_to_error_code(ec); } -// Boost cross platform codes (not asio). -code errc_to_error_code(const boost_code& ec) NOEXCEPT -{ - if (!ec) - return error::success; - - if (ec.category() == boost::system::generic_category()) - { - switch (static_cast(ec.value())) - { - case boost_errc_t::connection_aborted: - case boost_errc_t::operation_canceled: - return error::operation_canceled; - - // peer termination - // stackoverflow.com/a/19891985/1172329 - case boost_errc_t::connection_reset: - return error::peer_disconnect; - - // learn.microsoft.com/en-us/troubleshoot/windows-client/networking/ - // connect-tcp-greater-than-5000-error-wsaenobufs-10055 - case boost_errc_t::no_buffer_space: - return error::invalid_configuration; - - // network - case boost_errc_t::operation_not_permitted: - case boost_errc_t::operation_not_supported: - case boost_errc_t::owner_dead: - case boost_errc_t::permission_denied: - return error::not_allowed; - - // connect-resolve - case boost_errc_t::address_family_not_supported: - case boost_errc_t::bad_address: - case boost_errc_t::destination_address_required: - return error::resolve_failed; - - // connect-connect - case boost_errc_t::address_not_available: - case boost_errc_t::not_connected: - case boost_errc_t::connection_refused: - case boost_errc_t::broken_pipe: - case boost_errc_t::host_unreachable: - case boost_errc_t::network_down: - case boost_errc_t::network_reset: - case boost_errc_t::network_unreachable: - case boost_errc_t::no_link: - case boost_errc_t::no_protocol_option: - case boost_errc_t::no_such_file_or_directory: - case boost_errc_t::not_a_socket: - case boost_errc_t::protocol_not_supported: - case boost_errc_t::wrong_protocol_type: - return error::connect_failed; - - // connect-address - case boost_errc_t::address_in_use: - case boost_errc_t::already_connected: - case boost_errc_t::connection_already_in_progress: - case boost_errc_t::operation_in_progress: - return error::address_in_use; - - // I/O (bad_file_descriptor if socket is not initialized) - case boost_errc_t::bad_file_descriptor: - case boost_errc_t::bad_message: - case boost_errc_t::illegal_byte_sequence: - case boost_errc_t::io_error: - case boost_errc_t::message_size: - case boost_errc_t::no_message_available: - case boost_errc_t::no_message: - case boost_errc_t::no_stream_resources: - case boost_errc_t::not_a_stream: - case boost_errc_t::protocol_error: - return error::bad_stream; - - // timeout - case boost_errc_t::stream_timeout: - case boost_errc_t::timed_out: - return error::channel_timeout; - - // file system errors (bad_file_descriptor used in I/O) - case boost_errc_t::cross_device_link: - case boost_errc_t::device_or_resource_busy: - case boost_errc_t::directory_not_empty: - case boost_errc_t::executable_format_error: - case boost_errc_t::file_exists: - case boost_errc_t::file_too_large: - case boost_errc_t::filename_too_long: - case boost_errc_t::invalid_seek: - case boost_errc_t::is_a_directory: - case boost_errc_t::no_space_on_device: - case boost_errc_t::no_such_device: - case boost_errc_t::no_such_device_or_address: - case boost_errc_t::read_only_file_system: - case boost_errc_t::resource_unavailable_try_again: - case boost_errc_t::text_file_busy: - case boost_errc_t::too_many_files_open: - case boost_errc_t::too_many_files_open_in_system: - case boost_errc_t::too_many_links: - case boost_errc_t::too_many_symbolic_link_levels: - return error::file_system; - - default: - return error::errc_unknown; - } - } - - return error::unknown; -} - BC_POP_WARNING() } // namespace error From 78cf8053e062a1c729f054c2ff81e7e1792f8a1f Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 31 Jan 2026 03:00:21 -0500 Subject: [PATCH 4/4] Style, delint. --- include/bitcoin/network/error.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/bitcoin/network/error.hpp b/include/bitcoin/network/error.hpp index 3f760b835..d70aaa451 100644 --- a/include/bitcoin/network/error.hpp +++ b/include/bitcoin/network/error.hpp @@ -347,9 +347,17 @@ typedef boost::beast::websocket::error ws_error_t; typedef boost::beast::http::error http_error_t; typedef boost::json::error json_error_t; +inline boost_code to_errc_code(boost_errc_t ec) NOEXCEPT +{ + // boost::system::generic_category(); + return boost::system::errc::make_error_code(ec); +} + inline boost_code to_asio_basic_code(asio_basic_error_t ec) NOEXCEPT { + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) return { ec, boost::asio::error::get_system_category() }; + BC_POP_WARNING() } inline boost_code to_http_code(http_error_t ec) NOEXCEPT @@ -382,12 +390,6 @@ inline boost_code to_json_code(json_error_t ec) NOEXCEPT return boost::json::make_error_code(ec); } -inline boost_code to_errc_code(boost_errc_t ec) NOEXCEPT -{ - // boost::system::generic_category(); - return boost::system::errc::make_error_code(ec); -} - /// Shortcircuit common boost code mapping. BCT_API bool asio_is_canceled(const boost_code& ec) NOEXCEPT;