mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-17 13:22:03 +01:00
net: split CConnman::BindListenPort() off CConnman
Introduce a new low-level socket managing class `SockMan` and move the `CConnman::BindListenPort()` method to it.
This commit is contained in:
parent
69ac6802ba
commit
98ba5c7965
@ -123,6 +123,7 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL
|
||||
common/run_command.cpp
|
||||
common/settings.cpp
|
||||
common/signmessage.cpp
|
||||
common/sockman.cpp
|
||||
common/system.cpp
|
||||
common/url.cpp
|
||||
compressor.cpp
|
||||
|
85
src/common/sockman.cpp
Normal file
85
src/common/sockman.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2024-present The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://opensource.org/license/mit/.
|
||||
|
||||
#include <bitcoin-build-config.h> // IWYU pragma: keep
|
||||
|
||||
#include <common/sockman.h>
|
||||
#include <logging.h>
|
||||
#include <netbase.h>
|
||||
#include <util/sock.h>
|
||||
|
||||
bool SockMan::BindListenPort(const CService& addrBind, bilingual_str& strError)
|
||||
{
|
||||
int nOne = 1;
|
||||
|
||||
// Create socket for listening for incoming connections
|
||||
struct sockaddr_storage sockaddr;
|
||||
socklen_t len = sizeof(sockaddr);
|
||||
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
|
||||
{
|
||||
strError = Untranslated(strprintf("Bind address family for %s not supported", addrBind.ToStringAddrPort()));
|
||||
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<Sock> sock = CreateSock(addrBind.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP);
|
||||
if (!sock) {
|
||||
strError = Untranslated(strprintf("Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError())));
|
||||
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow binding if the port is still in TIME_WAIT state after
|
||||
// the program was closed and restarted.
|
||||
if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) {
|
||||
strError = Untranslated(strprintf("Error setting SO_REUSEADDR on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
|
||||
LogPrintf("%s\n", strError.original);
|
||||
}
|
||||
|
||||
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
|
||||
// and enable it by default or not. Try to enable it, if possible.
|
||||
if (addrBind.IsIPv6()) {
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) {
|
||||
strError = Untranslated(strprintf("Error setting IPV6_V6ONLY on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
|
||||
LogPrintf("%s\n", strError.original);
|
||||
}
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
|
||||
if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)) == SOCKET_ERROR) {
|
||||
strError = Untranslated(strprintf("Error setting IPV6_PROTECTION_LEVEL on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
|
||||
LogPrintf("%s\n", strError.original);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sock->Bind(reinterpret_cast<struct sockaddr*>(&sockaddr), len) == SOCKET_ERROR) {
|
||||
int nErr = WSAGetLastError();
|
||||
if (nErr == WSAEADDRINUSE)
|
||||
strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToStringAddrPort(), CLIENT_NAME);
|
||||
else
|
||||
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToStringAddrPort(), NetworkErrorString(nErr));
|
||||
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
|
||||
return false;
|
||||
}
|
||||
LogPrintf("Bound to %s\n", addrBind.ToStringAddrPort());
|
||||
|
||||
// Listen for incoming connections
|
||||
if (sock->Listen(SOMAXCONN) == SOCKET_ERROR)
|
||||
{
|
||||
strError = strprintf(_("Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
|
||||
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_listen.emplace_back(std::move(sock));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SockMan::StopListening()
|
||||
{
|
||||
m_listen.clear();
|
||||
}
|
44
src/common/sockman.h
Normal file
44
src/common/sockman.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2024-present The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://opensource.org/license/mit/.
|
||||
|
||||
#ifndef BITCOIN_COMMON_SOCKMAN_H
|
||||
#define BITCOIN_COMMON_SOCKMAN_H
|
||||
|
||||
#include <netaddress.h>
|
||||
#include <util/sock.h>
|
||||
#include <util/translation.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* A socket manager class which handles socket operations.
|
||||
* To use this class, inherit from it and implement the pure virtual methods.
|
||||
* Handled operations:
|
||||
* - binding and listening on sockets
|
||||
*/
|
||||
class SockMan
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Bind to a new address:port, start listening and add the listen socket to `m_listen`.
|
||||
* @param[in] addrBind Where to bind.
|
||||
* @param[out] strError Error string if an error occurs.
|
||||
* @retval true Success.
|
||||
* @retval false Failure, `strError` will be set.
|
||||
*/
|
||||
bool BindListenPort(const CService& addrBind, bilingual_str& strError);
|
||||
|
||||
/**
|
||||
* Stop listening by closing all listening sockets.
|
||||
*/
|
||||
void StopListening();
|
||||
|
||||
/**
|
||||
* List of listening sockets.
|
||||
*/
|
||||
std::vector<std::shared_ptr<Sock>> m_listen;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_COMMON_SOCKMAN_H
|
72
src/net.cpp
72
src/net.cpp
@ -3114,76 +3114,6 @@ void CConnman::ThreadI2PAcceptIncoming()
|
||||
}
|
||||
}
|
||||
|
||||
bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError)
|
||||
{
|
||||
int nOne = 1;
|
||||
|
||||
// Create socket for listening for incoming connections
|
||||
struct sockaddr_storage sockaddr;
|
||||
socklen_t len = sizeof(sockaddr);
|
||||
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
|
||||
{
|
||||
strError = Untranslated(strprintf("Bind address family for %s not supported", addrBind.ToStringAddrPort()));
|
||||
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<Sock> sock = CreateSock(addrBind.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP);
|
||||
if (!sock) {
|
||||
strError = Untranslated(strprintf("Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError())));
|
||||
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow binding if the port is still in TIME_WAIT state after
|
||||
// the program was closed and restarted.
|
||||
if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) {
|
||||
strError = Untranslated(strprintf("Error setting SO_REUSEADDR on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
|
||||
LogPrintf("%s\n", strError.original);
|
||||
}
|
||||
|
||||
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
|
||||
// and enable it by default or not. Try to enable it, if possible.
|
||||
if (addrBind.IsIPv6()) {
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) {
|
||||
strError = Untranslated(strprintf("Error setting IPV6_V6ONLY on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
|
||||
LogPrintf("%s\n", strError.original);
|
||||
}
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
|
||||
if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)) == SOCKET_ERROR) {
|
||||
strError = Untranslated(strprintf("Error setting IPV6_PROTECTION_LEVEL on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
|
||||
LogPrintf("%s\n", strError.original);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sock->Bind(reinterpret_cast<struct sockaddr*>(&sockaddr), len) == SOCKET_ERROR) {
|
||||
int nErr = WSAGetLastError();
|
||||
if (nErr == WSAEADDRINUSE)
|
||||
strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToStringAddrPort(), CLIENT_NAME);
|
||||
else
|
||||
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToStringAddrPort(), NetworkErrorString(nErr));
|
||||
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
|
||||
return false;
|
||||
}
|
||||
LogPrintf("Bound to %s\n", addrBind.ToStringAddrPort());
|
||||
|
||||
// Listen for incoming connections
|
||||
if (sock->Listen(SOMAXCONN) == SOCKET_ERROR)
|
||||
{
|
||||
strError = strprintf(_("Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
|
||||
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_listen.emplace_back(std::move(sock));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Discover()
|
||||
{
|
||||
if (!fDiscover)
|
||||
@ -3489,7 +3419,7 @@ void CConnman::StopNodes()
|
||||
}
|
||||
m_nodes_disconnected.clear();
|
||||
m_listen_permissions.clear();
|
||||
m_listen.clear();
|
||||
StopListening();
|
||||
semOutbound.reset();
|
||||
semAddnode.reset();
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <bip324.h>
|
||||
#include <chainparams.h>
|
||||
#include <common/bloom.h>
|
||||
#include <common/sockman.h>
|
||||
#include <compat/compat.h>
|
||||
#include <consensus/amount.h>
|
||||
#include <crypto/siphash.h>
|
||||
@ -1048,7 +1049,7 @@ protected:
|
||||
~NetEventsInterface() = default;
|
||||
};
|
||||
|
||||
class CConnman
|
||||
class CConnman : private SockMan
|
||||
{
|
||||
public:
|
||||
|
||||
@ -1277,7 +1278,6 @@ private:
|
||||
//! in case of no limit, it will always return 0
|
||||
std::chrono::seconds GetMaxOutboundTimeLeftInCycle_() const EXCLUSIVE_LOCKS_REQUIRED(m_total_bytes_sent_mutex);
|
||||
|
||||
bool BindListenPort(const CService& bindAddr, bilingual_str& strError);
|
||||
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
|
||||
bool InitBinds(const Options& options);
|
||||
|
||||
@ -1417,11 +1417,6 @@ private:
|
||||
unsigned int nSendBufferMaxSize{0};
|
||||
unsigned int nReceiveFloodSize{0};
|
||||
|
||||
/**
|
||||
* List of listening sockets.
|
||||
*/
|
||||
std::vector<std::shared_ptr<Sock>> m_listen;
|
||||
|
||||
/**
|
||||
* Permissions that incoming peers get based on our listening address they connected to.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user