diff options
Diffstat (limited to 'src/net.cpp')
-rw-r--r-- | src/net.cpp | 182 |
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)); } |