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.
1// Copyright (c) 2021-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <common/system.h>6#include <compat/compat.h>7#include <test/util/common.h>8#include <test/util/setup_common.h>9#include <util/sock.h>10#include <util/threadinterrupt.h>12#include <boost/test/unit_test.hpp>14#include <cassert>15#include <thread>17using namespace std::chrono_literals;19BOOST_FIXTURE_TEST_SUITE(sock_tests, BasicTestingSetup)21static bool SocketIsClosed(const SOCKET& s)22{23// Notice that if another thread is running and creates its own socket after `s` has been24// closed, it may be assigned the same file descriptor number. In this case, our test will25// wrongly pretend that the socket is not closed.26int type;27socklen_t len = sizeof(type);28return getsockopt(s, SOL_SOCKET, SO_TYPE, reinterpret_cast<char*>(&type), &len) == SOCKET_ERROR;29}31static SOCKET CreateSocket()32{33const SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);34BOOST_REQUIRE(s != static_cast<SOCKET>(SOCKET_ERROR));35return s;36}38BOOST_AUTO_TEST_CASE(constructor_and_destructor)39{40const SOCKET s = CreateSocket();41Sock* sock = new Sock(s);42BOOST_CHECK(*sock == s);43BOOST_CHECK(!SocketIsClosed(s));44delete sock;45BOOST_CHECK(SocketIsClosed(s));46}48BOOST_AUTO_TEST_CASE(move_constructor)49{50const SOCKET s = CreateSocket();51Sock* sock1 = new Sock(s);52Sock* sock2 = new Sock(std::move(*sock1));53delete sock1;54BOOST_CHECK(!SocketIsClosed(s));55BOOST_CHECK(*sock2 == s);56delete sock2;57BOOST_CHECK(SocketIsClosed(s));58}60BOOST_AUTO_TEST_CASE(move_assignment)61{62const SOCKET s1 = CreateSocket();63const SOCKET s2 = CreateSocket();64Sock* sock1 = new Sock(s1);65Sock* sock2 = new Sock(s2);67BOOST_CHECK(!SocketIsClosed(s1));68BOOST_CHECK(!SocketIsClosed(s2));70*sock2 = std::move(*sock1);71BOOST_CHECK(!SocketIsClosed(s1));72BOOST_CHECK(SocketIsClosed(s2));73BOOST_CHECK(*sock2 == s1);75delete sock1;76BOOST_CHECK(!SocketIsClosed(s1));77BOOST_CHECK(SocketIsClosed(s2));78BOOST_CHECK(*sock2 == s1);80delete sock2;81BOOST_CHECK(SocketIsClosed(s1));82BOOST_CHECK(SocketIsClosed(s2));83}85struct TcpSocketPair {86Sock sender;87Sock receiver;89TcpSocketPair()90: sender{Sock{CreateSocket()}},91receiver{Sock{CreateSocket()}}92{93connect_pair();94}96TcpSocketPair(const TcpSocketPair&) = delete;97TcpSocketPair& operator= (const TcpSocketPair&) = delete;98TcpSocketPair(TcpSocketPair&&) = default;99TcpSocketPair& operator= (TcpSocketPair&&) = default;101void connect_pair()102{103sockaddr_in addr{};104addr.sin_family = AF_INET;105addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);106addr.sin_port = 0;108BOOST_REQUIRE_EQUAL(receiver.Bind(reinterpret_cast<sockaddr*>(&addr), sizeof(addr)), 0);109BOOST_REQUIRE_EQUAL(receiver.Listen(1), 0);111// Get the address of the listener.112sockaddr_in bound{};113socklen_t blen = sizeof(bound);114BOOST_REQUIRE_EQUAL(receiver.GetSockName(reinterpret_cast<sockaddr*>(&bound), &blen), 0);115BOOST_REQUIRE_EQUAL(blen, sizeof(bound));117BOOST_REQUIRE_EQUAL(sender.Connect(reinterpret_cast<sockaddr*>(&bound), sizeof(bound)), 0);119std::unique_ptr<Sock> accepted = receiver.Accept(nullptr, nullptr);120BOOST_REQUIRE(accepted != nullptr);122receiver = std::move(*accepted);123}125void send_and_receive()126{127const char* msg = "abcd";128constexpr ssize_t msg_len = 4;129char recv_buf[10];131BOOST_CHECK_EQUAL(sender.Send(msg, msg_len, 0), msg_len);132BOOST_CHECK_EQUAL(receiver.Recv(recv_buf, sizeof(recv_buf), 0), msg_len);133BOOST_CHECK_EQUAL(strncmp(msg, recv_buf, msg_len), 0);134}135};137BOOST_AUTO_TEST_CASE(send_and_receive)138{139TcpSocketPair socks{};140socks.send_and_receive();142// Sockets are still connected after being moved.143TcpSocketPair socks_moved = std::move(socks);144socks_moved.send_and_receive();145}147BOOST_AUTO_TEST_CASE(wait)148{149TcpSocketPair socks = TcpSocketPair{};151std::thread waiter([&socks]() { (void)socks.receiver.Wait(24h, Sock::RecvEvent); });153BOOST_REQUIRE_EQUAL(socks.sender.Send("a", 1, 0), 1);155waiter.join();156}158BOOST_AUTO_TEST_CASE(recv_until_terminator_limit)159{160constexpr auto timeout = 1min; // High enough so that it is never hit.161CThreadInterrupt interrupt;163TcpSocketPair socks = TcpSocketPair{};165std::thread receiver([&socks, &timeout, &interrupt]() {166constexpr size_t max_data{10};167bool threw_as_expected{false};168// BOOST_CHECK_EXCEPTION() writes to some variables shared with the main thread which169// creates a data race. So mimic it manually.170try {171(void)socks.receiver.RecvUntilTerminator('\n', timeout, interrupt, max_data);172} catch (const std::runtime_error& e) {173threw_as_expected = HasReason("too many bytes without a terminator")(e);174}175assert(threw_as_expected);176});178BOOST_REQUIRE_NO_THROW(socks.sender.SendComplete("1234567", timeout, interrupt));179BOOST_REQUIRE_NO_THROW(socks.sender.SendComplete("89a\n", timeout, interrupt));181receiver.join();182}184BOOST_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.