Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,17 @@ jobs:
platform: "x64"
version: "vs2022"
tests: "*"
- image: windows-2025-vs2026
configuration: "StaticRelease"
platform: "x64"
version: "vs2026"
tests: "*"

- image: windows-2025-vs2026
configuration: "StaticDebug"
platform: "x64"
version: "vs2026"
tests: "*"

runs-on: ${{ matrix.image }}

Expand Down
4 changes: 2 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ src_libbitcoin_network_la_SOURCES = \
src/net/proxy_actions.cpp \
src/net/proxy_queue.cpp \
src/net/socket.cpp \
src/net/socket_body.cpp \
src/net/socket_connect.cpp \
src/net/socket_http.cpp \
src/net/socket_p2p.cpp \
src/net/socket_raw.cpp \
src/net/socket_rpc.cpp \
src/net/socket_stop.cpp \
src/net/socket_tcp.cpp \
src/net/socket_wait.cpp \
src/net/socket_ws.cpp \
src/protocols/protocol.cpp \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,12 @@
<ClCompile Include="..\..\..\..\src\net\proxy_actions.cpp" />
<ClCompile Include="..\..\..\..\src\net\proxy_queue.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_body.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_connect.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_http.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_p2p.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_raw.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_rpc.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_stop.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_tcp.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_wait.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_ws.cpp" />
<ClCompile Include="..\..\..\..\src\protocols\protocol.cpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,16 +387,13 @@
<ClCompile Include="..\..\..\..\src\net\socket.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_connect.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_http.cpp">
<ClCompile Include="..\..\..\..\src\net\socket_body.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_p2p.cpp">
<ClCompile Include="..\..\..\..\src\net\socket_connect.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_raw.cpp">
<ClCompile Include="..\..\..\..\src\net\socket_http.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_rpc.cpp">
Expand All @@ -405,6 +402,9 @@
<ClCompile Include="..\..\..\..\src\net\socket_stop.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_tcp.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_wait.cpp">
<Filter>src\net</Filter>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@
<ClCompile Include="..\..\..\..\test\channels\channel_http.cpp" />
<ClCompile Include="..\..\..\..\test\channels\channel_peer.cpp" />
<ClCompile Include="..\..\..\..\test\channels\channel_rpc.cpp" />
<ClCompile Include="..\..\..\..\test\channels\channel_ws.cpp" />
<ClCompile Include="..\..\..\..\test\config\address.cpp">
<ObjectFileName>$(IntDir)test_config_address.obj</ObjectFileName>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@
<ClCompile Include="..\..\..\..\test\channels\channel_rpc.cpp">
<Filter>src\channels</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\channels\channel_ws.cpp">
<Filter>src\channels</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\config\address.cpp">
<Filter>src\config</Filter>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@
<ClCompile Include="..\..\..\..\src\channels\channel.cpp" />
<ClCompile Include="..\..\..\..\src\channels\channel_http.cpp" />
<ClCompile Include="..\..\..\..\src\channels\channel_peer.cpp" />
<ClCompile Include="..\..\..\..\src\channels\channel_ws.cpp" />
<ClCompile Include="..\..\..\..\src\config\address.cpp">
<ObjectFileName>$(IntDir)src_config_address.obj</ObjectFileName>
</ClCompile>
Expand Down Expand Up @@ -203,6 +202,7 @@
<ClCompile Include="..\..\..\..\src\net\proxy_actions.cpp" />
<ClCompile Include="..\..\..\..\src\net\proxy_queue.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_body.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_connect.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_http.cpp" />
<ClCompile Include="..\..\..\..\src\net\socket_rpc.cpp" />
Expand Down Expand Up @@ -311,7 +311,6 @@
<ClInclude Include="..\..\..\..\include\bitcoin\network\channels\channel_http.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\channels\channel_peer.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\channels\channel_rpc.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\channels\channel_ws.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\channels\channels.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\config\address.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\config\authority.hpp" />
Expand Down Expand Up @@ -426,7 +425,6 @@
<ClInclude Include="..\..\..\..\include\bitcoin\network\protocols\protocol_version_70001.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\protocols\protocol_version_70002.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\protocols\protocol_version_70016.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\protocols\protocol_ws.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\protocols\protocols.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\sessions\session.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\sessions\session_inbound.hpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,6 @@
<ClCompile Include="..\..\..\..\src\channels\channel_peer.cpp">
<Filter>src\channels</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\channels\channel_ws.cpp">
<Filter>src\channels</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\config\address.cpp">
<Filter>src\config</Filter>
</ClCompile>
Expand Down Expand Up @@ -390,6 +387,9 @@
<ClCompile Include="..\..\..\..\src\net\socket.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_body.cpp">
<Filter>src\net</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\net\socket_connect.cpp">
<Filter>src\net</Filter>
</ClCompile>
Expand Down Expand Up @@ -698,9 +698,6 @@
<ClInclude Include="..\..\..\..\include\bitcoin\network\channels\channel_rpc.hpp">
<Filter>include\bitcoin\network\channels</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\network\channels\channel_ws.hpp">
<Filter>include\bitcoin\network\channels</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\network\channels\channels.hpp">
<Filter>include\bitcoin\network\channels</Filter>
</ClInclude>
Expand Down Expand Up @@ -1043,9 +1040,6 @@
<ClInclude Include="..\..\..\..\include\bitcoin\network\protocols\protocol_version_70016.hpp">
<Filter>include\bitcoin\network\protocols</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\network\protocols\protocol_ws.hpp">
<Filter>include\bitcoin\network\protocols</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\network\protocols\protocols.hpp">
<Filter>include\bitcoin\network\protocols</Filter>
</ClInclude>
Expand Down
3 changes: 1 addition & 2 deletions include/bitcoin/network/channels/channel_rpc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ class channel_rpc
/// Handle send completion, invokes receive() for non-notifications.
template <typename Message>
inline void handle_send(const code& ec, size_t bytes,
const rpc::message_cptr<Message>& message,
const result_handler& handler) NOEXCEPT;
const std::string& method, const result_handler& handler) NOEXCEPT;

/// Stranded handler invoked from stop().
inline void stopping(const code& ec) NOEXCEPT override;
Expand Down
1 change: 0 additions & 1 deletion include/bitcoin/network/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,6 @@ enum error_t : uint8_t
jsonrpc_v1_requires_array_params,
jsonrpc_v1_requires_id,
jsonrpc_params_not_collection,
jsonrpc_reader_bad_buffer,
jsonrpc_reader_stall,
jsonrpc_reader_exception,
jsonrpc_writer_exception
Expand Down
68 changes: 26 additions & 42 deletions include/bitcoin/network/impl/channels/channel_rpc.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ inline void CLASS::resume() NOEXCEPT

// Read cycle.
// ----------------------------------------------------------------------------
// Failure to call receive() after successful message handling stalls channel.

// Failure to call after successful message handling causes stalled channel.
TEMPLATE
inline void CLASS::receive() NOEXCEPT
{
Expand All @@ -69,19 +69,8 @@ inline void CLASS::receive() NOEXCEPT
return;

reading_ = true;
const auto in = emplace_shared<rpc::request>
(
// default json model, unused size_hint, unused serialization buffer.
json::json_value{},
const auto in = to_shared<rpc::request>();

// default incoming rpc message.
rpc::request_t{},

// !strict allows params singleton to be accepted as array (Electrum).
false
);

// Post handle_read to strand upon stop, error, or buffer full.
read(request_buffer(), *in,
std::bind(&channel_rpc::handle_receive,
shared_from_base<channel_rpc>(), _1, _2, in));
Expand Down Expand Up @@ -149,6 +138,15 @@ inline http::flat_buffer& CLASS::request_buffer() NOEXCEPT
// Send.
// ----------------------------------------------------------------------------

template <typename Message>
std::string extract_method(const Message& message) NOEXCEPT
{
if constexpr (is_same_type<Message, rpc::response_t>)
return "response: " + message.error.value_or(rpc::result_t{}).message;
else
return "request: " + message.method;
}

// protected
TEMPLATE
template <typename Message>
Expand All @@ -157,53 +155,39 @@ inline void CLASS::send(Message&& message, size_t size_hint,
{
BC_ASSERT(stranded());
using namespace std::placeholders;
using namespace system;

// Templated message due to notification sending request_t.
const auto out = emplace_shared<rpc::message_value<Message>>
(
// default json model, buffer size_hint, default serialization buffer.
json::json_value{ {}, size_hint, {} },

// outgoing rpc message (request_t or response_t).
std::forward<Message>(message),
auto complete = std::bind(&CLASS::handle_send<Message>,
shared_from_base<CLASS>(), _1, _2, extract_method(message),
std::move(handler));

// unused strict json-rpc.
true
);

// Write message to socket, capture its pointer for lifetime.
write(*out, std::bind(&CLASS::handle_send<Message>,
shared_from_base<CLASS>(), _1, _2, out, std::move(handler)));
// Write message (response or notification) to socket.
write(
{
json::json_value{ .size_hint = size_hint },
std::forward<Message>(message)
}, std::move(complete));
}

// protected
TEMPLATE
template <typename Message>
inline void CLASS::handle_send(const code& ec, size_t bytes,
const rpc::message_cptr<Message>& message,
const result_handler& handler) NOEXCEPT
const std::string& method, const result_handler& handler) NOEXCEPT
{
BC_ASSERT(stranded());
if (ec) stop(ec);
if (ec)
stop(ec);

LOGA("Rpc " << method << " (" << bytes << ") bytes [" << endpoint() << "] ");

// Typically a noop, but handshake may pause channel here.
handler(ec);

// Only invoke continuation for a request response (not notification).
// Restart the listener (following response to request only).
if constexpr (is_same_type<Message, rpc::response_t>)
{
LOGA("Rpc response: (" << bytes << ") bytes [" << endpoint() << "] "
<< message->message.error.value_or(rpc::result_t{}).message);

// Continue the read loop (does not unpause or restart).
receive();
}
else
{
LOGA("Rpc notification: (" << bytes << ") bytes [" << endpoint() << "] "
<< message->message.method);
}
}

TEMPLATE
Expand Down
51 changes: 40 additions & 11 deletions include/bitcoin/network/impl/messages/json_body.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ size_t CLASS::reader::put(const buffer_type& buffer, boost_code& ec) NOEXCEPT
using namespace system;
using namespace network::error;

const auto size = buffer.size();
if (is_zero(size))
{
ec.clear();
return {};
}

if (is_null(buffer.data()))
{
ec = to_http_code(http_error_t::bad_alloc);
return {};
}

try
{
const auto data = pointer_cast<const char>(buffer.data());
Expand Down Expand Up @@ -89,21 +102,32 @@ size_t CLASS::reader::put(const buffer_type& buffer, boost_code& ec) NOEXCEPT
TEMPLATE
void CLASS::reader::finish(boost_code& ec) NOEXCEPT
{
ec.clear();
// Finishing can be very confusing. The derived rpc body calls this base
// method, and then the virtual done() is tested to determine whether the
// logical object is fully read (including optionally required terminator).
// Any error code here signals the beast reader (and any reader that
// terminates based on the end of the framed data, such as websockets) that
// the parse has failed (terminal error). However for custom stream readers
// that may not be aware of byte termination, the `need_more` implies that
// the parse has not failed and that more bytes may be parsed. In either
// case, when this is called and the parse is complete, then the parsed
// json object is moved to the model and the parser is released. In the
// case of the derived json-rpc reader, the json is also then converted to
// the rpc model if valid, otherwise returning a failure code. In no case
// is the underlying parser_.finish(ec) ever called, as that would preclude
// use in the unbounded scenario.

// Calling parser.finish() when parser.done() results in error::incomplete.
if (!parser_.done())
using namespace network::error;
if (!done())
{
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
parser_.finish(ec);
BC_POP_WARNING()

if (ec) return;
ec = to_http_code(http_error_t::need_more);
return;
}

try
{
value_.model = parser_.release();
ec.clear();
value_.model = parser_.release();
}
catch (const boost::system::system_error& e)
{
Expand All @@ -113,7 +137,6 @@ void CLASS::reader::finish(boost_code& ec) NOEXCEPT
catch (...)
{
// As a catch-all we blame alloc.
using namespace network::error;
ec = to_http_code(http_error_t::bad_alloc);
}

Expand Down Expand Up @@ -158,12 +181,18 @@ CLASS::writer::out_buffer
CLASS::writer::get(boost_code& ec) NOEXCEPT
{
using namespace network::error;
if (serializer_.done())
if (done())
{
ec = to_http_code(http_error_t::end_of_stream);
return {};
}

if (!value_.buffer)
{
ec = to_http_code(http_error_t::bad_alloc);
return {};
}

const auto size = value_.buffer->max_size();
if (is_zero(size))
{
Expand Down
Loading
Loading