Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1001ConnectClient<ErrorSock>(std::as_bytes(std::span(all_requests)))1002};1004// Wait up to one minute for the last reply from the server1005std::string actual;1006char buf[0x10000] = {};1007int attempts = 6000;1008while (attempts > 0)1009{1010ssize_t bytes_read = mock_client_socket_pipes->send.GetBytes(buf, sizeof(buf), 0);1011if (bytes_read > 0) {1012actual.append(buf, bytes_read);1013if (actual.find(strprintf("height: %d", num_requests - 1)) != std::string::npos) {1014break;1015}1016}1017std::this_thread::sleep_for(10ms);1018--attempts;1019}1021// Send the third request.1022// If there was a race between WriteReply() in the worker thread setting m_send_ready=true1023// and SocketHandlerConnected() in the I/O thread flushing the send buffer,1024// then the socket would be stuck in write mode with nothing to write,1025// the server would never read from the socket, and this request would time out.1026// Wait a second to ensure both the worker thread and I/O thread are idle.1027// If we send the next request too soon it might get accepted by the server before1028// it gets wedged shut.1029std::this_thread::sleep_for(1000ms);1030mock_client_socket_pipes->recv.PushBytes(keepalive_request.data(), keepalive_request.size());1031num_requests++;1033// Wait up to one minute for reply1034attempts = 6000;1035while (attempts > 0)1036{1037ssize_t bytes_read = mock_client_socket_pipes->send.GetBytes(buf, sizeof(buf), 0);1038if (bytes_read > 0) {1039actual.append(buf, bytes_read);1040if (actual.find(strprintf("height: %d", num_requests - 1)) != std::string::npos) {1041break;1042}1043}1044std::this_thread::sleep_for(10ms);1045--attempts;1046}1048// All replies were received1049for (int i = 0; i < num_requests; i++) {1050BOOST_REQUIRE(actual.find(strprintf("height: %d", i)) != std::string::npos);1051}1053// Close the keep-alive connection1054server.DisconnectAllClients();1056workers.Stop();1058server.InterruptNet();1059server.JoinSocketsThreads();1060server.StopListening();1061}1063BOOST_AUTO_TEST_CASE(http_server_rejects_disallowed_client_before_read)1064{1065// DynSock reports accepted connections as coming from 5.5.5.5.1066gArgs.ForceSetArg("-rpcallowip", "4.4.4.4");1068std::atomic_bool request_dispatched{false};1069HTTPServer server{[&request_dispatched](std::unique_ptr<HTTPRequest>&&) {1070request_dispatched = true;1071}};1072BOOST_REQUIRE(server.InitHTTPAllowList());1074CService addr_bind{Lookup("0.0.0.0", /*portDefault=*/0, /*fAllowLookup=*/false).value()};1075BOOST_REQUIRE(server.BindAndStartListening(addr_bind));1076server.StartSocketsThreads();1078// Queue a complete request; the server should never read from it.1079std::shared_ptr<DynSock::Pipes> client_pipes{1080ConnectClient(std::as_bytes(std::span(full_request)))};1082// Wait for the socket to close with an EOF (bytes_read == 0)1083// 'bytes_read > 0' means the server replied to the prohibited client1084// 'bytes_read < 0' is an error, expected until the connection is fully processed by the I/O loop1085ssize_t bytes_read{};1086char buf[0x10000]{};1087for (int attempts{0}; attempts != 1'000; ++attempts) {1088bytes_read = client_pipes->send.GetBytes(&buf, sizeof(buf), MSG_PEEK);1089if (bytes_read >= 0) break;1090std::this_thread::sleep_for(10ms);1091}1093BOOST_CHECK_EQUAL(bytes_read, 0);1094BOOST_CHECK(!request_dispatched);1095BOOST_CHECK_EQUAL(server.GetConnectionsCount(), 0);1097server.InterruptNet();1098server.JoinSocketsThreads();1099server.StopListening();1101// 'recv' buffer still holds the client's request untouched which1102// proves the server never called Recv()1103const ssize_t recv_bytes{client_pipes->recv.GetBytes(&buf, sizeof(buf))};1104BOOST_REQUIRE_EQUAL(recv_bytes, static_cast<ssize_t>(full_request.size()));1105BOOST_CHECK_EQUAL(std::string_view(buf, recv_bytes), full_request);1106}1108BOOST_AUTO_TEST_SUITE_END()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.