Inside Bitcoin
Opening the selected file…
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) 2020-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 <util/sock.h>7#include <compat/compat.h>8#include <span.h>9#include <tinyformat.h>10#include <util/check.h>11#include <util/log.h>12#include <util/syserror.h>13#include <util/threadinterrupt.h>14#include <util/time.h>16#include <algorithm>17#include <compare>18#include <exception>19#include <limits>20#include <memory>21#include <stdexcept>22#include <string>23#include <utility>24#include <vector>26#ifdef USE_POLL27#include <poll.h>28#endif30Sock::Sock(SOCKET s) : m_socket(s) {}32Sock::Sock(Sock&& other)33{34m_socket = other.m_socket;35other.m_socket = INVALID_SOCKET;36}38Sock::~Sock() { Close(); }40Sock& Sock::operator=(Sock&& other)41{42Close();43m_socket = other.m_socket;44other.m_socket = INVALID_SOCKET;45return *this;46}48ssize_t Sock::Send(const void* data, size_t len, int flags) const49{50return send(m_socket, static_cast<const char*>(data), len, flags);51}53ssize_t Sock::Recv(void* buf, size_t len, int flags) const54{55return recv(m_socket, static_cast<char*>(buf), len, flags);56}58int Sock::Connect(const sockaddr* addr, socklen_t addr_len) const59{60return connect(m_socket, addr, addr_len);61}63int Sock::Bind(const sockaddr* addr, socklen_t addr_len) const64{65return bind(m_socket, addr, addr_len);66}68int Sock::Listen(int backlog) const69{70return listen(m_socket, backlog);71}73std::unique_ptr<Sock> Sock::Accept(sockaddr* addr, socklen_t* addr_len) const74{75#ifdef WIN3276static constexpr auto accept_error = INVALID_SOCKET;77#else78static constexpr auto accept_error = SOCKET_ERROR;79#endif81std::unique_ptr<Sock> sock;83const auto socket = accept(m_socket, addr, addr_len);84if (socket != accept_error) {85try {86sock = std::make_unique<Sock>(socket);87} catch (const std::exception&) {88#ifdef WIN3289closesocket(socket);90#else91close(socket);92#endif93}94}96return sock;97}99int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const100{101return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len);102}104int Sock::SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const105{106return setsockopt(m_socket, level, opt_name, static_cast<const char*>(opt_val), opt_len);107}109int Sock::GetSockName(sockaddr* name, socklen_t* name_len) const110{111return getsockname(m_socket, name, name_len);112}114bool Sock::SetNonBlocking() const115{116#ifdef WIN32117u_long on{1};118if (ioctlsocket(m_socket, FIONBIO, &on) == SOCKET_ERROR) {119return false;120}121#else122const int flags{fcntl(m_socket, F_GETFL, 0)};123if (flags == SOCKET_ERROR) {124return false;125}126if (fcntl(m_socket, F_SETFL, flags | O_NONBLOCK) == SOCKET_ERROR) {127return false;128}129#endif130return true;131}133bool Sock::IsSelectable() const134{135#if defined(USE_POLL) || defined(WIN32)136return true;137#else138return m_socket < FD_SETSIZE;139#endif140}142bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const143{144// We need a `shared_ptr` holding `this` for `WaitMany()`, but don't want145// `this` to be destroyed when the `shared_ptr` goes out of scope at the146// end of this function.147// Create it with an aliasing shared_ptr that points to `this` without148// owning it.149std::shared_ptr<const Sock> shared{std::shared_ptr<const Sock>{}, this};151EventsPerSock events_per_sock{std::make_pair(shared, Events{requested})};153if (!WaitMany(timeout, events_per_sock)) {154return false;155}157if (occurred != nullptr) {158*occurred = events_per_sock.begin()->second.occurred;159}161return true;162}164bool Sock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const165{166// poll() takes the timeout as an int and select() rejects very large values on167// some systems (e.g. macOS), so cap it at INT_MAX milliseconds (~24.8 days).168timeout = std::min(timeout, std::chrono::milliseconds{std::numeric_limits<int>::max()});170#ifdef USE_POLL171std::vector<pollfd> pfds;172for (const auto& [sock, events] : events_per_sock) {173pfds.emplace_back();174auto& pfd = pfds.back();175pfd.fd = sock->m_socket;176if (events.requested & RecvEvent) {177pfd.events |= POLLIN;178}179if (events.requested & SendEvent) {180pfd.events |= POLLOUT;181}182}184if (poll(pfds.data(), pfds.size(), count_milliseconds(timeout)) == SOCKET_ERROR) {185return false;186}188assert(pfds.size() == events_per_sock.size());189size_t i{0};190for (auto& [sock, events] : events_per_sock) {191assert(sock->m_socket == static_cast<SOCKET>(pfds[i].fd));192events.occurred = 0;193if (pfds[i].revents & POLLIN) {194events.occurred |= RecvEvent;195}196if (pfds[i].revents & POLLOUT) {197events.occurred |= SendEvent;198}199if (pfds[i].revents & (POLLERR | POLLHUP)) {200events.occurred |= ErrorEvent;201}202++i;203}205return true;206#else207fd_set recv;208fd_set send;209fd_set err;210FD_ZERO(&recv);211FD_ZERO(&send);212FD_ZERO(&err);213SOCKET socket_max{0};215for (const auto& [sock, events] : events_per_sock) {216if (!sock->IsSelectable()) {217return false;218}219const auto& s = sock->m_socket;220if (events.requested & RecvEvent) {221FD_SET(s, &recv);222FD_SET(s, &err);223}224if (events.requested & SendEvent) {225FD_SET(s, &send);226}227if (events.requested & (RecvEvent | SendEvent)) {228socket_max = std::max(socket_max, s);229}230}232timeval tv = MillisToTimeval(timeout);234if (select(socket_max + 1, &recv, &send, &err, &tv) == SOCKET_ERROR) {235return false;236}238for (auto& [sock, events] : events_per_sock) {239const auto& s = sock->m_socket;240events.occurred = 0;241if (FD_ISSET(s, &recv)) {242events.occurred |= RecvEvent;243}244if (FD_ISSET(s, &send)) {245events.occurred |= SendEvent;246}247if (FD_ISSET(s, &err)) {248events.occurred |= ErrorEvent;249}250}
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.