aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp182
1 files changed, 85 insertions, 97 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 0f49b8ad5a..bee8710062 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Copyright (c) 2009-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,6 +16,7 @@
#include <compat.h>
#include <consensus/consensus.h>
#include <crypto/sha256.h>
+#include <fs.h>
#include <i2p.h>
#include <net_permissions.h>
#include <netaddress.h>
@@ -112,9 +113,9 @@ static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256
//
bool fDiscover = true;
bool fListen = true;
-RecursiveMutex cs_mapLocalHost;
-std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost);
-static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {};
+Mutex g_maplocalhost_mutex;
+std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex);
+static bool vfLimited[NET_MAX] GUARDED_BY(g_maplocalhost_mutex) = {};
std::string strSubVersion;
void CConnman::AddAddrFetch(const std::string& strDest)
@@ -137,7 +138,7 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
int nBestScore = -1;
int nBestReachability = -1;
{
- LOCK(cs_mapLocalHost);
+ LOCK(g_maplocalhost_mutex);
for (const auto& entry : mapLocalHost)
{
int nScore = entry.second.nScore;
@@ -193,7 +194,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
static int GetnScore(const CService& addr)
{
- LOCK(cs_mapLocalHost);
+ LOCK(g_maplocalhost_mutex);
const auto it = mapLocalHost.find(addr);
return (it != mapLocalHost.end()) ? it->second.nScore : 0;
}
@@ -264,7 +265,7 @@ bool AddLocal(const CService& addr_, int nScore)
LogPrintf("AddLocal(%s,%i)\n", addr.ToString(), nScore);
{
- LOCK(cs_mapLocalHost);
+ LOCK(g_maplocalhost_mutex);
const auto [it, is_newly_added] = mapLocalHost.emplace(addr, LocalServiceInfo());
LocalServiceInfo &info = it->second;
if (is_newly_added || nScore >= info.nScore) {
@@ -283,7 +284,7 @@ bool AddLocal(const CNetAddr &addr, int nScore)
void RemoveLocal(const CService& addr)
{
- LOCK(cs_mapLocalHost);
+ LOCK(g_maplocalhost_mutex);
LogPrintf("RemoveLocal(%s)\n", addr.ToString());
mapLocalHost.erase(addr);
}
@@ -292,13 +293,13 @@ void SetReachable(enum Network net, bool reachable)
{
if (net == NET_UNROUTABLE || net == NET_INTERNAL)
return;
- LOCK(cs_mapLocalHost);
+ LOCK(g_maplocalhost_mutex);
vfLimited[net] = !reachable;
}
bool IsReachable(enum Network net)
{
- LOCK(cs_mapLocalHost);
+ LOCK(g_maplocalhost_mutex);
return !vfLimited[net];
}
@@ -310,7 +311,7 @@ bool IsReachable(const CNetAddr &addr)
/** vote for a local address */
bool SeenLocal(const CService& addr)
{
- LOCK(cs_mapLocalHost);
+ LOCK(g_maplocalhost_mutex);
const auto it = mapLocalHost.find(addr);
if (it == mapLocalHost.end()) return false;
++it->second.nScore;
@@ -321,7 +322,7 @@ bool SeenLocal(const CService& addr)
/** check whether a given address is potentially local */
bool IsLocal(const CService& addr)
{
- LOCK(cs_mapLocalHost);
+ LOCK(g_maplocalhost_mutex);
return mapLocalHost.count(addr) > 0;
}
@@ -505,7 +506,16 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (!addr_bind.IsValid()) {
addr_bind = GetBindAddress(sock->Get());
}
- CNode* pnode = new CNode(id, nLocalServices, sock->Release(), addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", conn_type, /* inbound_onion */ false);
+ CNode* pnode = new CNode(id,
+ nLocalServices,
+ std::move(sock),
+ addrConnect,
+ CalculateKeyedNetGroup(addrConnect),
+ nonce,
+ addr_bind,
+ pszDest ? pszDest : "",
+ conn_type,
+ /*inbound_onion=*/false);
pnode->AddRef();
// We're making a new connection, harvest entropy from the time (and our peer count)
@@ -517,11 +527,10 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
- LOCK(cs_hSocket);
- if (hSocket != INVALID_SOCKET)
- {
+ LOCK(m_sock_mutex);
+ if (m_sock) {
LogPrint(BCLog::NET, "disconnecting peer=%d\n", id);
- CloseSocket(hSocket);
+ m_sock.reset();
}
}
@@ -553,12 +562,14 @@ std::string ConnectionTypeAsString(ConnectionType conn_type)
CService CNode::GetAddrLocal() const
{
- LOCK(cs_addrLocal);
+ AssertLockNotHeld(m_addr_local_mutex);
+ LOCK(m_addr_local_mutex);
return addrLocal;
}
void CNode::SetAddrLocal(const CService& addrLocalIn) {
- LOCK(cs_addrLocal);
+ AssertLockNotHeld(m_addr_local_mutex);
+ LOCK(m_addr_local_mutex);
if (addrLocal.IsValid()) {
error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString());
} else {
@@ -595,7 +606,7 @@ void CNode::CopyStats(CNodeStats& stats)
X(m_addr_name);
X(nVersion);
{
- LOCK(cs_SubVer);
+ LOCK(m_subver_mutex);
X(cleanSubVer);
}
stats.fInbound = IsInboundConn();
@@ -657,7 +668,7 @@ bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete)
// Store received bytes per message command
// to prevent a memory DOS, only allow valid commands
- auto i = mapRecvBytesPerMsgCmd.find(msg.m_command);
+ auto i = mapRecvBytesPerMsgCmd.find(msg.m_type);
if (i == mapRecvBytesPerMsgCmd.end()) {
i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER);
}
@@ -747,7 +758,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
CNetMessage msg(std::move(vRecv));
// store command string, time, and sizes
- msg.m_command = hdr.GetCommand();
+ msg.m_type = hdr.GetCommand();
msg.m_time = time;
msg.m_message_size = hdr.nMessageSize;
msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
@@ -760,7 +771,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
// Check checksum and header command string
if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) {
LogPrint(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n",
- SanitizeString(msg.m_command), msg.m_message_size,
+ SanitizeString(msg.m_type), msg.m_message_size,
HexStr(Span{hash}.first(CMessageHeader::CHECKSUM_SIZE)),
HexStr(hdr.pchChecksum),
m_node_id);
@@ -799,10 +810,11 @@ size_t CConnman::SocketSendData(CNode& node) const
assert(data.size() > node.nSendOffset);
int nBytes = 0;
{
- LOCK(node.cs_hSocket);
- if (node.hSocket == INVALID_SOCKET)
+ LOCK(node.m_sock_mutex);
+ if (!node.m_sock) {
break;
- nBytes = send(node.hSocket, reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
+ }
+ nBytes = node.m_sock->Send(reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
}
if (nBytes > 0) {
node.m_last_send = GetTime<std::chrono::seconds>();
@@ -1099,10 +1111,10 @@ bool CConnman::AttemptToEvictConnection()
void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
- SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
+ auto sock = hListenSocket.sock->Accept((struct sockaddr*)&sockaddr, &len);
CAddress addr;
- if (hSocket == INVALID_SOCKET) {
+ if (!sock) {
const int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK) {
LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
@@ -1116,15 +1128,15 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
addr = CAddress{MaybeFlipIPv6toCJDNS(addr), NODE_NONE};
}
- const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(hSocket)), NODE_NONE};
+ const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(sock->Get())), NODE_NONE};
NetPermissionFlags permissionFlags = NetPermissionFlags::None;
hListenSocket.AddSocketPermissionFlags(permissionFlags);
- CreateNodeFromAcceptedSocket(hSocket, permissionFlags, addr_bind, addr);
+ CreateNodeFromAcceptedSocket(std::move(sock), permissionFlags, addr_bind, addr);
}
-void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
+void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
NetPermissionFlags permissionFlags,
const CAddress& addr_bind,
const CAddress& addr)
@@ -1150,27 +1162,24 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
if (!fNetworkActive) {
LogPrint(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToString());
- CloseSocket(hSocket);
return;
}
- if (!IsSelectableSocket(hSocket))
+ if (!IsSelectableSocket(sock->Get()))
{
LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString());
- CloseSocket(hSocket);
return;
}
// According to the internet TCP_NODELAY is not carried into accepted sockets
// on all platforms. Set it again here just to be sure.
- SetSocketNoDelay(hSocket);
+ SetSocketNoDelay(sock->Get());
// Don't accept connections from banned peers.
bool banned = m_banman && m_banman->IsBanned(addr);
if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::NoBan) && banned)
{
LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
- CloseSocket(hSocket);
return;
}
@@ -1179,7 +1188,6 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::NoBan) && nInbound + 1 >= nMaxInbound && discouraged)
{
LogPrint(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToString());
- CloseSocket(hSocket);
return;
}
@@ -1188,7 +1196,6 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
if (!AttemptToEvictConnection()) {
// No connection to evict, disconnect the new connection
LogPrint(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n");
- CloseSocket(hSocket);
return;
}
}
@@ -1202,7 +1209,16 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
}
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
- CNode* pnode = new CNode(id, nodeServices, hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND, inbound_onion);
+ CNode* pnode = new CNode(id,
+ nodeServices,
+ std::move(sock),
+ addr,
+ CalculateKeyedNetGroup(addr),
+ nonce,
+ addr_bind,
+ /*addrNameIn=*/"",
+ ConnectionType::INBOUND,
+ inbound_onion);
pnode->AddRef();
pnode->m_permissionFlags = permissionFlags;
pnode->m_prefer_evict = discouraged;
@@ -1364,7 +1380,7 @@ bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
std::set<SOCKET>& error_set)
{
for (const ListenSocket& hListenSocket : vhListenSocket) {
- recv_set.insert(hListenSocket.socket);
+ recv_set.insert(hListenSocket.sock->Get());
}
for (CNode* pnode : nodes) {
@@ -1386,17 +1402,18 @@ bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
select_send = !pnode->vSendMsg.empty();
}
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
+ LOCK(pnode->m_sock_mutex);
+ if (!pnode->m_sock) {
continue;
+ }
- error_set.insert(pnode->hSocket);
+ error_set.insert(pnode->m_sock->Get());
if (select_send) {
- send_set.insert(pnode->hSocket);
+ send_set.insert(pnode->m_sock->Get());
continue;
}
if (select_recv) {
- recv_set.insert(pnode->hSocket);
+ recv_set.insert(pnode->m_sock->Get());
}
}
@@ -1566,12 +1583,13 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
bool sendSet = false;
bool errorSet = false;
{
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
+ LOCK(pnode->m_sock_mutex);
+ if (!pnode->m_sock) {
continue;
- recvSet = recv_set.count(pnode->hSocket) > 0;
- sendSet = send_set.count(pnode->hSocket) > 0;
- errorSet = error_set.count(pnode->hSocket) > 0;
+ }
+ recvSet = recv_set.count(pnode->m_sock->Get()) > 0;
+ sendSet = send_set.count(pnode->m_sock->Get()) > 0;
+ errorSet = error_set.count(pnode->m_sock->Get()) > 0;
}
if (recvSet || errorSet)
{
@@ -1579,10 +1597,11 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
uint8_t pchBuf[0x10000];
int nBytes = 0;
{
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
+ LOCK(pnode->m_sock_mutex);
+ if (!pnode->m_sock) {
continue;
- nBytes = recv(pnode->hSocket, (char*)pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
+ }
+ nBytes = pnode->m_sock->Recv(pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
}
if (nBytes > 0)
{
@@ -1646,7 +1665,7 @@ void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set)
if (interruptNet) {
return;
}
- if (recv_set.count(listen_socket.socket) > 0) {
+ if (recv_set.count(listen_socket.sock->Get()) > 0) {
AcceptConnection(listen_socket);
}
}
@@ -1883,8 +1902,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
auto start = GetTime<std::chrono::microseconds>();
// Minimum time before next feeler connection (in microseconds).
- auto next_feeler = PoissonNextSend(start, FEELER_INTERVAL);
- auto next_extra_block_relay = PoissonNextSend(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
+ auto next_feeler = GetExponentialRand(start, FEELER_INTERVAL);
+ auto next_extra_block_relay = GetExponentialRand(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);
bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);
@@ -2004,7 +2023,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
//
// This is similar to the logic for trying extra outbound (full-relay)
// peers, except:
- // - we do this all the time on a poisson timer, rather than just when
+ // - we do this all the time on an exponential timer, rather than just when
// our tip is stale
// - we potentially disconnect our next-youngest block-relay-only peer, if our
// newest block-relay-only peer delivers a block more recently.
@@ -2013,10 +2032,10 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// Because we can promote these connections to block-relay-only
// connections, they do not get their own ConnectionType enum
// (similar to how we deal with extra outbound peers).
- next_extra_block_relay = PoissonNextSend(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
+ next_extra_block_relay = GetExponentialRand(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
conn_type = ConnectionType::BLOCK_RELAY;
} else if (now > next_feeler) {
- next_feeler = PoissonNextSend(now, FEELER_INTERVAL);
+ next_feeler = GetExponentialRand(now, FEELER_INTERVAL);
conn_type = ConnectionType::FEELER;
fFeeler = true;
} else {
@@ -2335,7 +2354,7 @@ void CConnman::ThreadI2PAcceptIncoming()
continue;
}
- CreateNodeFromAcceptedSocket(conn.sock->Release(), NetPermissionFlags::None,
+ CreateNodeFromAcceptedSocket(std::move(conn.sock), NetPermissionFlags::None,
CAddress{conn.me, NODE_NONE}, CAddress{conn.peer, NODE_NONE});
}
}
@@ -2397,7 +2416,7 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
return false;
}
- vhListenSocket.push_back(ListenSocket(sock->Release(), permissions));
+ vhListenSocket.emplace_back(std::move(sock), permissions);
return true;
}
@@ -2706,15 +2725,6 @@ void CConnman::StopNodes()
DeleteNode(pnode);
}
- // Close listening sockets.
- for (ListenSocket& hListenSocket : vhListenSocket) {
- if (hListenSocket.socket != INVALID_SOCKET) {
- if (!CloseSocket(hListenSocket.socket)) {
- LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
- }
- }
- }
-
for (CNode* pnode : m_nodes_disconnected) {
DeleteNode(pnode);
}
@@ -2976,8 +2986,9 @@ ServiceFlags CConnman::GetLocalServices() const
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
-CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion)
- : m_connected{GetTime<std::chrono::seconds>()},
+CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> sock, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion)
+ : m_sock{sock},
+ m_connected{GetTime<std::chrono::seconds>()},
addr(addrIn),
addrBind(addrBindIn),
m_addr_name{addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn},
@@ -2989,7 +3000,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const
nLocalServices(nLocalServicesIn)
{
if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
- hSocket = hSocketIn;
if (conn_type_in != ConnectionType::BLOCK_RELAY) {
m_tx_relay = std::make_unique<TxRelay>();
}
@@ -3008,11 +3018,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const
m_serializer = std::make_unique<V1TransportSerializer>(V1TransportSerializer());
}
-CNode::~CNode()
-{
- CloseSocket(hSocket);
-}
-
bool CConnman::NodeFullyConnected(const CNode* pnode)
{
return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect;
@@ -3072,23 +3077,6 @@ bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
return found != nullptr && NodeFullyConnected(found) && func(found);
}
-std::chrono::microseconds CConnman::PoissonNextSendInbound(std::chrono::microseconds now, std::chrono::seconds average_interval)
-{
- if (m_next_send_inv_to_incoming.load() < now) {
- // If this function were called from multiple threads simultaneously
- // it would possible that both update the next send variable, and return a different result to their caller.
- // This is not possible in practice as only the net processing thread invokes this function.
- m_next_send_inv_to_incoming = PoissonNextSend(now, average_interval);
- }
- return m_next_send_inv_to_incoming;
-}
-
-std::chrono::microseconds PoissonNextSend(std::chrono::microseconds now, std::chrono::seconds average_interval)
-{
- double unscaled = -log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */);
- return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us);
-}
-
CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const
{
return CSipHasher(nSeed0, nSeed1).Write(id);
@@ -3120,11 +3108,11 @@ void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Spa
CAutoFile f(fsbridge::fopen(path, "ab"), SER_DISK, CLIENT_VERSION);
ser_writedata64(f, now.count());
- f.write(msg_type.data(), msg_type.length());
+ f.write(MakeByteSpan(msg_type));
for (auto i = msg_type.length(); i < CMessageHeader::COMMAND_SIZE; ++i) {
f << uint8_t{'\0'};
}
uint32_t size = data.size();
ser_writedata32(f, size);
- f.write((const char*)data.data(), data.size());
+ f.write(AsBytes(data));
}