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.
501default: {502LogError("Error: malformed proxy response\n");503return false;504}505}506if (recvr != IntrRecvError::OK) {507LogError("Error reading from proxy\n");508return false;509}510if (InterruptibleRecv(pchRet3, 2, g_socks5_recv_timeout, sock) != IntrRecvError::OK) {511LogError("Error reading from proxy\n");512return false;513}514LogDebug(BCLog::NET, "SOCKS5 connected %s\n", strDest);515return true;516} catch (const std::runtime_error& e) {517LogError("Error during SOCKS5 proxy handshake: %s\n", e.what());518return false;519}520}522std::unique_ptr<Sock> CreateSockOS(int domain, int type, int protocol)523{524// Not IPv4, IPv6 or UNIX525if (domain == AF_UNSPEC) return nullptr;527// Create a socket in the specified address family.528SOCKET hSocket = socket(domain, type, protocol);529if (hSocket == INVALID_SOCKET) {530return nullptr;531}533auto sock = std::make_unique<Sock>(hSocket);535if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNIX) {536return sock;537}539// Ensure that waiting for I/O on this socket won't result in undefined540// behavior.541if (!sock->IsSelectable()) {542LogInfo("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");543return nullptr;544}546#ifdef SO_NOSIGPIPE547int set = 1;548// Set the no-sigpipe option on the socket for BSD systems, other UNIXes549// should use the MSG_NOSIGNAL flag for every send.550if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(int)) == SOCKET_ERROR) {551LogInfo("Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n",552NetworkErrorString(WSAGetLastError()));553}554#endif556// Set the non-blocking option on the socket.557if (!sock->SetNonBlocking()) {558LogInfo("Error setting socket to non-blocking: %s\n", NetworkErrorString(WSAGetLastError()));559return nullptr;560}562#ifdef HAVE_SOCKADDR_UN563if (domain == AF_UNIX) return sock;564#endif566if (protocol == IPPROTO_TCP) {567// Set the no-delay option (disable Nagle's algorithm) on the TCP socket.568const int on{1};569if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) {570LogDebug(BCLog::NET, "Unable to set TCP_NODELAY on a newly created socket, continuing anyway\n");571}572}574return sock;575}577std::function<std::unique_ptr<Sock>(int, int, int)> CreateSock = CreateSockOS;579template<typename... Args>580static void LogConnectFailure(bool manual_connection, util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)581{582std::string error_message = tfm::format(fmt, args...);583if (manual_connection) {584LogInfo("%s\n", error_message);585} else {586LogDebug(BCLog::NET, "%s\n", error_message);587}588}590static bool ConnectToSocket(const Sock& sock,591struct sockaddr* sockaddr,592socklen_t len,593const std::string& dest_str,594bool manual_connection,595std::chrono::milliseconds timeout)596{597// Connect to `sockaddr` using `sock`.598if (sock.Connect(sockaddr, len) == SOCKET_ERROR) {599int nErr = WSAGetLastError();600// WSAEINVAL is here because some legacy version of winsock uses it601if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)602{603// Connection didn't actually fail, but is being established604// asynchronously. Thus, use async I/O api (select/poll)605// synchronously to check for successful connection with a timeout.606const Sock::Event requested = Sock::RecvEvent | Sock::SendEvent;607Sock::Event occurred;608if (!sock.Wait(timeout, requested, &occurred)) {609LogInfo("wait for connect to %s failed: %s\n",610dest_str,611NetworkErrorString(WSAGetLastError()));612return false;613} else if (occurred == 0) {614LogDebug(BCLog::NET, "connection attempt to %s timed out\n", dest_str);615return false;616}618// Even if the wait was successful, the connect might not619// have been successful. The reason for this failure is hidden away620// in the SO_ERROR for the socket in modern systems. We read it into621// sockerr here.622int sockerr;623socklen_t sockerr_len = sizeof(sockerr);624if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, &sockerr, &sockerr_len) ==625SOCKET_ERROR) {626LogInfo("getsockopt() for %s failed: %s\n", dest_str, NetworkErrorString(WSAGetLastError()));627return false;628}629if (sockerr != 0) {630LogConnectFailure(manual_connection,631"connect() to %s failed after wait: %s",632dest_str,633NetworkErrorString(sockerr));634return false;635}636}637#ifdef WIN32638else if (WSAGetLastError() != WSAEISCONN)639#else640else641#endif642{643LogConnectFailure(manual_connection, "connect() to %s failed: %s", dest_str, NetworkErrorString(WSAGetLastError()));644return false;645}646}647return true;648}650std::unique_ptr<Sock> ConnectDirectly(const CService& dest, bool manual_connection)651{652return ConnectDirectly(dest, manual_connection, std::chrono::milliseconds{nConnectTimeout});653}655std::unique_ptr<Sock> ConnectDirectly(const CService& dest,656bool manual_connection,657std::chrono::milliseconds timeout)658{659auto sock = CreateSock(dest.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP);660if (!sock) {661LogError("Cannot create a socket for connecting to %s\n", dest.ToStringAddrPort());662return {};663}665// Create a sockaddr from the specified service.666struct sockaddr_storage sockaddr;667socklen_t len = sizeof(sockaddr);668if (!dest.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {669LogInfo("Cannot get sockaddr for %s: unsupported network\n", dest.ToStringAddrPort());670return {};671}673if (!ConnectToSocket(*sock, (struct sockaddr*)&sockaddr, len, dest.ToStringAddrPort(), manual_connection, timeout)) {674return {};675}677return sock;678}680std::unique_ptr<Sock> Proxy::Connect() const681{682if (!IsValid()) return {};684if (!m_is_unix_socket) return ConnectDirectly(proxy, /*manual_connection=*/true);686#ifdef HAVE_SOCKADDR_UN687auto sock = CreateSock(AF_UNIX, SOCK_STREAM, 0);688if (!sock) {689LogError("Cannot create a socket for connecting to %s\n", m_unix_socket_path);690return {};691}693const std::string path{m_unix_socket_path.substr(ADDR_PREFIX_UNIX.length())};695struct sockaddr_un addrun;696memset(&addrun, 0, sizeof(addrun));697addrun.sun_family = AF_UNIX;698// leave the last char in addrun.sun_path[] to be always '\0'699memcpy(addrun.sun_path, path.c_str(), std::min(sizeof(addrun.sun_path) - 1, path.length()));700socklen_t len = sizeof(addrun);702if (!ConnectToSocket(*sock,703(struct sockaddr*)&addrun,704len,705path,706/*manual_connection=*/true,707std::chrono::milliseconds{nConnectTimeout})) {708return {};709}711return sock;712#else713return {};714#endif715}717bool SetProxy(enum Network net, const Proxy &addrProxy) {718assert(net >= 0 && net < NET_MAX);719if (!addrProxy.IsValid())720return false;721LOCK(g_proxyinfo_mutex);722proxyInfo[net] = addrProxy;723return true;724}726std::optional<Proxy> GetProxy(enum Network net)727{728assert(net >= 0 && net < NET_MAX);729LOCK(g_proxyinfo_mutex);730if (!proxyInfo[net].IsValid()) {731return std::nullopt;732}733return proxyInfo[net];734}736bool SetNameProxy(const Proxy &addrProxy) {737if (!addrProxy.IsValid())738return false;739LOCK(g_proxyinfo_mutex);740nameProxy = addrProxy;741return true;742}744std::optional<Proxy> GetNameProxy()745{746LOCK(g_proxyinfo_mutex);747if (!nameProxy.IsValid()) {748return std::nullopt;749}750return nameProxy;