diff --git a/include/bitcoin/network/net/socket.hpp b/include/bitcoin/network/net/socket.hpp index 75950e82c..5f5e5f62b 100644 --- a/include/bitcoin/network/net/socket.hpp +++ b/include/bitcoin/network/net/socket.hpp @@ -360,14 +360,12 @@ class BCT_API socket typedef std::function socket_handler; -// TODO: reimplement as template. #define VARIANT_DISPATCH_METHOD(object, method) \ std::visit([&](auto&& value) NOEXCEPT \ { \ value.get().method; \ }, object) -// TODO: reimplement as template. #define VARIANT_DISPATCH_FUNCTION(function, object, ...) \ std::visit([&](auto&& value) NOEXCEPT \ { \ diff --git a/src/error.cpp b/src/error.cpp index def94cf5e..27f4d63fc 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -534,45 +534,44 @@ code asio_to_error_code(const boost_code& ec) NOEXCEPT // includes json codes code http_to_error_code(const boost_code& ec) NOEXCEPT { - static const auto& category = to_http_code( - boost::beast::http::error::end_of_stream).category(); - if (!ec) return error::success; - if (ec.category() != category) - return json_to_error_code(ec); - - switch (static_cast(ec.value())) + if (ec.category() == to_http_code(http_error_t::end_of_stream).category()) { - case http_error_t::end_of_stream: return error::end_of_stream; - case http_error_t::partial_message: return error::partial_message; - case http_error_t::need_more: return error::need_more; - case http_error_t::unexpected_body: return error::unexpected_body; - case http_error_t::need_buffer: return error::need_buffer; - case http_error_t::end_of_chunk: return error::end_of_chunk; - case http_error_t::buffer_overflow: return error::buffer_overflow; - case http_error_t::header_limit: return error::header_limit; - case http_error_t::body_limit: return error::body_limit; - case http_error_t::bad_alloc: return error::bad_alloc; - case http_error_t::bad_line_ending: return error::bad_line_ending; - case http_error_t::bad_method: return error::bad_method; - case http_error_t::bad_target: return error::bad_target; - case http_error_t::bad_version: return error::bad_version; - case http_error_t::bad_status: return error::bad_status; - case http_error_t::bad_reason: return error::bad_reason; - case http_error_t::bad_field: return error::bad_field; - case http_error_t::bad_value: return error::bad_value; - case http_error_t::bad_content_length: return error::bad_content_length; - case http_error_t::bad_transfer_encoding: return error::bad_transfer_encoding; - case http_error_t::bad_chunk: return error::bad_chunk; - case http_error_t::bad_chunk_extension: return error::bad_chunk_extension; - case http_error_t::bad_obs_fold: return error::bad_obs_fold; - 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; + switch (static_cast(ec.value())) + { + case http_error_t::end_of_stream: return error::end_of_stream; + case http_error_t::partial_message: return error::partial_message; + case http_error_t::need_more: return error::need_more; + case http_error_t::unexpected_body: return error::unexpected_body; + case http_error_t::need_buffer: return error::need_buffer; + case http_error_t::end_of_chunk: return error::end_of_chunk; + case http_error_t::buffer_overflow: return error::buffer_overflow; + case http_error_t::header_limit: return error::header_limit; + case http_error_t::body_limit: return error::body_limit; + case http_error_t::bad_alloc: return error::bad_alloc; + case http_error_t::bad_line_ending: return error::bad_line_ending; + case http_error_t::bad_method: return error::bad_method; + case http_error_t::bad_target: return error::bad_target; + case http_error_t::bad_version: return error::bad_version; + case http_error_t::bad_status: return error::bad_status; + case http_error_t::bad_reason: return error::bad_reason; + case http_error_t::bad_field: return error::bad_field; + case http_error_t::bad_value: return error::bad_value; + case http_error_t::bad_content_length: return error::bad_content_length; + case http_error_t::bad_transfer_encoding: return error::bad_transfer_encoding; + case http_error_t::bad_chunk: return error::bad_chunk; + case http_error_t::bad_chunk_extension: return error::bad_chunk_extension; + case http_error_t::bad_obs_fold: return error::bad_obs_fold; + 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; + } } + + return json_to_error_code(ec); } // includes asio codes @@ -581,8 +580,7 @@ code ssl_to_error_code(const boost_code& ec) NOEXCEPT if (!ec) return error::success; - namespace stream = boost::asio::ssl::error; - if (ec.category() == stream::get_stream_category()) + if (ec.category() == boost::asio::ssl::error::get_stream_category()) { switch (static_cast(ec.value())) { @@ -619,50 +617,49 @@ code ssl_to_error_code(const boost_code& ec) NOEXCEPT // includes json codes code ws_to_error_code(const boost_code& ec) NOEXCEPT { - static const auto& category = to_websocket_code( - boost::beast::websocket::error::closed).category(); - if (!ec) return error::success; - if (ec.category() != category) - return http_to_error_code(ec); - - switch (static_cast(ec.value())) + if (ec.category() == to_websocket_code(ws_error_t::closed).category()) { - case ws_error_t::closed: return error::websocket_closed; - case ws_error_t::buffer_overflow: return error::websocket_buffer_overflow; - case ws_error_t::partial_deflate_block: return error::partial_deflate_block; - case ws_error_t::message_too_big: return error::message_too_big; - case ws_error_t::bad_http_version: return error::bad_http_version; - case ws_error_t::bad_method: return error::websocket_bad_method; - case ws_error_t::no_host: return error::no_host; - case ws_error_t::no_connection: return error::no_connection; - case ws_error_t::no_connection_upgrade: return error::no_connection_upgrade; - case ws_error_t::no_upgrade: return error::no_upgrade; - case ws_error_t::no_upgrade_websocket: return error::no_upgrade_websocket; - case ws_error_t::no_sec_key: return error::no_sec_key; - case ws_error_t::bad_sec_key: return error::bad_sec_key; - case ws_error_t::no_sec_version: return error::no_sec_version; - case ws_error_t::bad_sec_version: return error::bad_sec_version; - case ws_error_t::no_sec_accept: return error::no_sec_accept; - case ws_error_t::bad_sec_accept: return error::bad_sec_accept; - case ws_error_t::upgrade_declined: return error::upgrade_declined; - case ws_error_t::bad_opcode: return error::bad_opcode; - case ws_error_t::bad_data_frame: return error::bad_data_frame; - case ws_error_t::bad_continuation: return error::bad_continuation; - case ws_error_t::bad_reserved_bits: return error::bad_reserved_bits; - case ws_error_t::bad_control_fragment: return error::bad_control_fragment; - case ws_error_t::bad_control_size: return error::bad_control_size; - case ws_error_t::bad_unmasked_frame: return error::bad_unmasked_frame; - case ws_error_t::bad_masked_frame: return error::bad_masked_frame; - case ws_error_t::bad_size: return error::bad_size; - case ws_error_t::bad_frame_payload: return error::bad_frame_payload; - 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; - default: return error::websocket_unknown; + switch (static_cast(ec.value())) + { + case ws_error_t::closed: return error::websocket_closed; + case ws_error_t::buffer_overflow: return error::websocket_buffer_overflow; + case ws_error_t::partial_deflate_block: return error::partial_deflate_block; + case ws_error_t::message_too_big: return error::message_too_big; + case ws_error_t::bad_http_version: return error::bad_http_version; + case ws_error_t::bad_method: return error::websocket_bad_method; + case ws_error_t::no_host: return error::no_host; + case ws_error_t::no_connection: return error::no_connection; + case ws_error_t::no_connection_upgrade: return error::no_connection_upgrade; + case ws_error_t::no_upgrade: return error::no_upgrade; + case ws_error_t::no_upgrade_websocket: return error::no_upgrade_websocket; + case ws_error_t::no_sec_key: return error::no_sec_key; + case ws_error_t::bad_sec_key: return error::bad_sec_key; + case ws_error_t::no_sec_version: return error::no_sec_version; + case ws_error_t::bad_sec_version: return error::bad_sec_version; + case ws_error_t::no_sec_accept: return error::no_sec_accept; + case ws_error_t::bad_sec_accept: return error::bad_sec_accept; + case ws_error_t::upgrade_declined: return error::upgrade_declined; + case ws_error_t::bad_opcode: return error::bad_opcode; + case ws_error_t::bad_data_frame: return error::bad_data_frame; + case ws_error_t::bad_continuation: return error::bad_continuation; + case ws_error_t::bad_reserved_bits: return error::bad_reserved_bits; + case ws_error_t::bad_control_fragment: return error::bad_control_fragment; + case ws_error_t::bad_control_size: return error::bad_control_size; + case ws_error_t::bad_unmasked_frame: return error::bad_unmasked_frame; + case ws_error_t::bad_masked_frame: return error::bad_masked_frame; + case ws_error_t::bad_size: return error::bad_size; + case ws_error_t::bad_frame_payload: return error::bad_frame_payload; + 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; + default: return error::websocket_unknown; + } } + + return http_to_error_code(ec); } // includes asio codes @@ -671,52 +668,54 @@ code json_to_error_code(const boost_code& ec) NOEXCEPT if (!ec) return error::success; - if (ec.category() != boost::json::detail::error_code_category) - return asio_to_error_code(ec); - - switch (static_cast(ec.value())) + if (ec.category() == boost::json::detail::error_code_category) { - case json_error_t::syntax: return error::syntax; - case json_error_t::extra_data: return error::extra_data; - case json_error_t::incomplete: return error::incomplete; - case json_error_t::exponent_overflow: return error::exponent_overflow; - case json_error_t::too_deep: return error::too_deep; - case json_error_t::illegal_leading_surrogate: return error::illegal_leading_surrogate; - case json_error_t::illegal_trailing_surrogate: return error::illegal_trailing_surrogate; - case json_error_t::expected_hex_digit: return error::expected_hex_digit; - case json_error_t::expected_utf16_escape: return error::expected_utf16_escape; - case json_error_t::object_too_large: return error::object_too_large; - case json_error_t::array_too_large: return error::array_too_large; - case json_error_t::key_too_large: return error::key_too_large; - case json_error_t::string_too_large: return error::string_too_large; - case json_error_t::number_too_large: return error::number_too_large; - case json_error_t::input_error: return error::input_error; - case json_error_t::exception: return error::exception; - case json_error_t::out_of_range: return error::out_of_range; - case json_error_t::test_failure: return error::test_failure; - case json_error_t::missing_slash: return error::missing_slash; - case json_error_t::invalid_escape: return error::invalid_escape; - case json_error_t::token_not_number: return error::token_not_number; - case json_error_t::value_is_scalar: return error::value_is_scalar; - case json_error_t::not_found: return error::not_found; - case json_error_t::token_overflow: return error::token_overflow; - case json_error_t::past_the_end: return error::past_the_end; - case json_error_t::not_number: return error::not_number; - case json_error_t::not_exact: return error::not_exact; - case json_error_t::not_null: return error::not_null; - case json_error_t::not_bool: return error::not_bool; - case json_error_t::not_array: return error::not_array; - case json_error_t::not_object: return error::not_object; - case json_error_t::not_string: return error::not_string; - case json_error_t::not_int64: return error::not_int64; - case json_error_t::not_uint64: return error::not_uint64; - case json_error_t::not_double: return error::not_double; - case json_error_t::not_integer: return error::not_integer; - 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; - default: return error::json_unknown; + switch (static_cast(ec.value())) + { + case json_error_t::syntax: return error::syntax; + case json_error_t::extra_data: return error::extra_data; + case json_error_t::incomplete: return error::incomplete; + case json_error_t::exponent_overflow: return error::exponent_overflow; + case json_error_t::too_deep: return error::too_deep; + case json_error_t::illegal_leading_surrogate: return error::illegal_leading_surrogate; + case json_error_t::illegal_trailing_surrogate: return error::illegal_trailing_surrogate; + case json_error_t::expected_hex_digit: return error::expected_hex_digit; + case json_error_t::expected_utf16_escape: return error::expected_utf16_escape; + case json_error_t::object_too_large: return error::object_too_large; + case json_error_t::array_too_large: return error::array_too_large; + case json_error_t::key_too_large: return error::key_too_large; + case json_error_t::string_too_large: return error::string_too_large; + case json_error_t::number_too_large: return error::number_too_large; + case json_error_t::input_error: return error::input_error; + case json_error_t::exception: return error::exception; + case json_error_t::out_of_range: return error::out_of_range; + case json_error_t::test_failure: return error::test_failure; + case json_error_t::missing_slash: return error::missing_slash; + case json_error_t::invalid_escape: return error::invalid_escape; + case json_error_t::token_not_number: return error::token_not_number; + case json_error_t::value_is_scalar: return error::value_is_scalar; + case json_error_t::not_found: return error::not_found; + case json_error_t::token_overflow: return error::token_overflow; + case json_error_t::past_the_end: return error::past_the_end; + case json_error_t::not_number: return error::not_number; + case json_error_t::not_exact: return error::not_exact; + case json_error_t::not_null: return error::not_null; + case json_error_t::not_bool: return error::not_bool; + case json_error_t::not_array: return error::not_array; + case json_error_t::not_object: return error::not_object; + case json_error_t::not_string: return error::not_string; + case json_error_t::not_int64: return error::not_int64; + case json_error_t::not_uint64: return error::not_uint64; + case json_error_t::not_double: return error::not_double; + case json_error_t::not_integer: return error::not_integer; + 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; + default: return error::json_unknown; + } } + + return asio_to_error_code(ec); } // includes http codes @@ -725,9 +724,10 @@ code rpc_to_error_code(const boost_code& ec) NOEXCEPT if (!ec) return error::success; - // These are libbitcoin-category-in-boost codes, for simplified transport. - if (ec.category() == network::error::error_category::singleton) - return { static_cast(ec.value()) }; + // libbitcoin-category-in-boost codes, for portability via boost_code. + if (const auto portable = static_cast(ec); + portable.category() == network::error::error_category::singleton) + return portable; return http_to_error_code(ec); } diff --git a/src/net/socket_rpc.cpp b/src/net/socket_rpc.cpp index f3a9fd017..30a877188 100644 --- a/src/net/socket_rpc.cpp +++ b/src/net/socket_rpc.cpp @@ -66,6 +66,7 @@ void socket::do_rpc_read(boost_code ec, size_t total, const read_rpc::ptr& in, return; } + // async_read_some allows variable sized or empty reads into fixed buffer. VARIANT_DISPATCH_METHOD(get_tcp(), async_read_some(in->buffer.prepare(size), std::bind(&socket::handle_rpc_read, @@ -110,6 +111,7 @@ void socket::handle_rpc_read(boost_code ec, size_t size, size_t total, } } + // Handle error condition or incomplete message. do_rpc_read(ec, total, in, handler); } @@ -145,10 +147,13 @@ void socket::do_rpc_write(boost_code ec, size_t total, } BC_ASSERT(buffer.has_value()); - VARIANT_DISPATCH_METHOD(get_tcp(), - async_write_some(buffer.value().first, + + // Internally this may compose multiple async_write_some to consume buffer. + // Writes one buffer from writer, must still iterator until writer is done. + VARIANT_DISPATCH_FUNCTION(boost::asio::async_write, get_tcp(), + buffer.value().first, std::bind(&socket::handle_rpc_write, - shared_from_this(), _1, _2, total, out, handler))); + shared_from_this(), _1, _2, total, out, handler)); } void socket::handle_rpc_write(boost_code ec, size_t size, size_t total, @@ -169,6 +174,7 @@ void socket::handle_rpc_write(boost_code ec, size_t size, size_t total, return; } + // Handle error condition or incomplete message. do_rpc_write(ec, total, out, handler); }