aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp645
1 files changed, 169 insertions, 476 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 5a0c057c3e..c4aaac4986 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -13,15 +13,16 @@
#include <addrman.h>
#include <banman.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <consensus/consensus.h>
#include <crypto/sha256.h>
+#include <node/eviction.h>
#include <fs.h>
#include <i2p.h>
#include <net_permissions.h>
#include <netaddress.h>
#include <netbase.h>
-#include <node/ui_interface.h>
+#include <node/interface_ui.h>
#include <protocol.h>
#include <random.h>
#include <scheduler.h>
@@ -84,8 +85,8 @@ static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" pe
/** The default timeframe for -maxuploadtarget. 1 day. */
static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24};
-// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
-#define FEELER_SLEEP_WINDOW 1
+// A random time period (0 to 1 seconds) is added to feeler connections to prevent synchronization.
+static constexpr auto FEELER_SLEEP_WINDOW{1s};
/** Used to pass flags to the Bind() function */
enum BindFlags {
@@ -103,7 +104,7 @@ enum BindFlags {
// The sleep time needs to be small to avoid new sockets stalling
static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50;
-const std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
+const std::string NET_MESSAGE_TYPE_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
@@ -113,7 +114,7 @@ static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256
//
bool fDiscover = true;
bool fListen = true;
-Mutex g_maplocalhost_mutex;
+GlobalMutex 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;
@@ -186,7 +187,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
// it'll get a pile of addresses with newer timestamps.
// Seed nodes are given a random 'last seen time' of between one and two
// weeks ago.
- const int64_t nOneWeek = 7*24*60*60;
+ const auto one_week{7 * 24h};
std::vector<CAddress> vSeedsOut;
FastRandomContext rng;
CDataStream s(vSeedsIn, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
@@ -194,7 +195,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
CService endpoint;
s >> endpoint;
CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)};
- addr.nTime = GetTime() - rng.randrange(nOneWeek) - nOneWeek;
+ addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week);
LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToString());
vSeedsOut.push_back(addr);
}
@@ -205,15 +206,13 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
// Otherwise, return the unroutable 0.0.0.0 but filled in with
// the normal parameters, since the IP may be changed to a useful
// one by discovery.
-CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
+CService GetLocalAddress(const CNetAddr& addrPeer)
{
- CAddress ret(CService(CNetAddr(),GetListenPort()), nLocalServices);
+ CService ret{CNetAddr(), GetListenPort()};
CService addr;
- if (GetLocal(addr, paddrPeer))
- {
- ret = CAddress(addr, nLocalServices);
+ if (GetLocal(addr, &addrPeer)) {
+ ret = CService{addr};
}
- ret.nTime = GetAdjustedTime();
return ret;
}
@@ -232,35 +231,35 @@ bool IsPeerAddrLocalGood(CNode *pnode)
IsReachable(addrLocal.GetNetwork());
}
-std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
+std::optional<CService> GetLocalAddrForPeer(CNode& node)
{
- CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices());
+ CService addrLocal{GetLocalAddress(node.addr)};
if (gArgs.GetBoolArg("-addrmantest", false)) {
// use IPv4 loopback during addrmantest
- addrLocal = CAddress(CService(LookupNumeric("127.0.0.1", GetListenPort())), pnode->GetLocalServices());
+ addrLocal = CService(LookupNumeric("127.0.0.1", GetListenPort()));
}
// If discovery is enabled, sometimes give our peer the address it
// tells us that it sees us as in case it has a better idea of our
// address than we do.
FastRandomContext rng;
- if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
+ if (IsPeerAddrLocalGood(&node) && (!addrLocal.IsRoutable() ||
rng.randbits((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3 : 1) == 0))
{
- if (pnode->IsInboundConn()) {
+ if (node.IsInboundConn()) {
// For inbound connections, assume both the address and the port
// as seen from the peer.
- addrLocal = CAddress{pnode->GetAddrLocal(), addrLocal.nServices};
+ addrLocal = CService{node.GetAddrLocal()};
} else {
// For outbound connections, assume just the address as seen from
// the peer and leave the port in `addrLocal` as returned by
// `GetLocalAddress()` above. The peer has no way to observe our
// listening port when we have initiated the connection.
- addrLocal.SetIP(pnode->GetAddrLocal());
+ addrLocal.SetIP(node.GetAddrLocal());
}
}
if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false))
{
- LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), pnode->GetId());
+ LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), node.GetId());
return addrLocal;
}
// Address is unroutable. Don't advertise.
@@ -421,16 +420,16 @@ bool CConnman::CheckIncomingNonce(uint64_t nonce)
}
/** Get the bind address for a socket as CAddress */
-static CAddress GetBindAddress(SOCKET sock)
+static CAddress GetBindAddress(const Sock& sock)
{
CAddress addr_bind;
struct sockaddr_storage sockaddr_bind;
socklen_t sockaddr_bind_len = sizeof(sockaddr_bind);
- if (sock != INVALID_SOCKET) {
- if (!getsockname(sock, (struct sockaddr*)&sockaddr_bind, &sockaddr_bind_len)) {
+ if (sock.Get() != INVALID_SOCKET) {
+ if (!sock.GetSockName((struct sockaddr*)&sockaddr_bind, &sockaddr_bind_len)) {
addr_bind.SetSockAddr((const struct sockaddr*)&sockaddr_bind);
} else {
- LogPrint(BCLog::NET, "Warning: getsockname failed\n");
+ LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "getsockname failed\n");
}
}
return addr_bind;
@@ -453,10 +452,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
}
}
- /// debug print
- LogPrint(BCLog::NET, "trying connection %s lastseen=%.1fhrs\n",
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying connection %s lastseen=%.1fhrs\n",
pszDest ? pszDest : addrConnect.ToString(),
- pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
+ Ticks<HoursDouble>(pszDest ? 0h : AdjustedTime() - addrConnect.nTime));
// Resolve
const uint16_t default_port{pszDest != nullptr ? Params().GetDefaultPort(pszDest) :
@@ -539,10 +537,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
if (!addr_bind.IsValid()) {
- addr_bind = GetBindAddress(sock->Get());
+ addr_bind = GetBindAddress(*sock);
}
CNode* pnode = new CNode(id,
- nLocalServices,
std::move(sock),
addrConnect,
CalculateKeyedNetGroup(addrConnect),
@@ -575,26 +572,6 @@ void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNet
}
}
-std::string ConnectionTypeAsString(ConnectionType conn_type)
-{
- switch (conn_type) {
- case ConnectionType::INBOUND:
- return "inbound";
- case ConnectionType::MANUAL:
- return "manual";
- case ConnectionType::FEELER:
- return "feeler";
- case ConnectionType::OUTBOUND_FULL_RELAY:
- return "outbound-full-relay";
- case ConnectionType::BLOCK_RELAY:
- return "block-relay-only";
- case ConnectionType::ADDR_FETCH:
- return "addr-fetch";
- } // no default case, so the compiler can warn about missing cases
-
- assert(false);
-}
-
CService CNode::GetAddrLocal() const
{
AssertLockNotHeld(m_addr_local_mutex);
@@ -622,7 +599,6 @@ Network CNode::ConnectedThroughNetwork() const
void CNode::CopyStats(CNodeStats& stats)
{
stats.nodeid = this->GetId();
- X(nServices);
X(addr);
X(addrBind);
stats.m_network = ConnectedThroughNetwork();
@@ -643,12 +619,12 @@ void CNode::CopyStats(CNodeStats& stats)
X(m_bip152_highbandwidth_from);
{
LOCK(cs_vSend);
- X(mapSendBytesPerMsgCmd);
+ X(mapSendBytesPerMsgType);
X(nSendBytes);
}
{
LOCK(cs_vRecv);
- X(mapRecvBytesPerMsgCmd);
+ X(mapRecvBytesPerMsgType);
X(nRecvBytes);
}
X(m_permissionFlags);
@@ -684,19 +660,19 @@ bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete)
bool reject_message{false};
CNetMessage msg = m_deserializer->GetMessage(time, reject_message);
if (reject_message) {
- // Message deserialization failed. Drop the message but don't disconnect the peer.
+ // Message deserialization failed. Drop the message but don't disconnect the peer.
// store the size of the corrupt message
- mapRecvBytesPerMsgCmd.at(NET_MESSAGE_COMMAND_OTHER) += msg.m_raw_message_size;
+ mapRecvBytesPerMsgType.at(NET_MESSAGE_TYPE_OTHER) += msg.m_raw_message_size;
continue;
}
- // Store received bytes per message command
- // to prevent a memory DOS, only allow valid commands
- auto i = mapRecvBytesPerMsgCmd.find(msg.m_type);
- if (i == mapRecvBytesPerMsgCmd.end()) {
- i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER);
+ // Store received bytes per message type.
+ // To prevent a memory DOS, only allow known message types.
+ auto i = mapRecvBytesPerMsgType.find(msg.m_type);
+ if (i == mapRecvBytesPerMsgType.end()) {
+ i = mapRecvBytesPerMsgType.find(NET_MESSAGE_TYPE_OTHER);
}
- assert(i != mapRecvBytesPerMsgCmd.end());
+ assert(i != mapRecvBytesPerMsgType.end());
i->second += msg.m_raw_message_size;
// push the message to the process queue,
@@ -781,7 +757,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
// decompose a single CNetMessage from the TransportDeserializer
CNetMessage msg(std::move(vRecv));
- // store command string, time, and sizes
+ // store message type string, time, and sizes
msg.m_type = hdr.GetCommand();
msg.m_time = time;
msg.m_message_size = hdr.nMessageSize;
@@ -792,7 +768,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds
// We just received a message off the wire, harvest entropy from the time (and the message checksum)
RandAddEvent(ReadLE32(hash.begin()));
- // Check checksum and header command string
+ // Check checksum and header message type 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_type), msg.m_message_size,
@@ -876,210 +852,6 @@ size_t CConnman::SocketSendData(CNode& node) const
return nSentSize;
}
-static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
-{
- return a.m_min_ping_time > b.m_min_ping_time;
-}
-
-static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
-{
- return a.m_connected > b.m_connected;
-}
-
-static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) {
- return a.nKeyedNetGroup < b.nKeyedNetGroup;
-}
-
-static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
-{
- // There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.
- if (a.m_last_block_time != b.m_last_block_time) return a.m_last_block_time < b.m_last_block_time;
- if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;
- return a.m_connected > b.m_connected;
-}
-
-static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
-{
- // There is a fall-through here because it is common for a node to have more than a few peers that have not yet relayed txn.
- if (a.m_last_tx_time != b.m_last_tx_time) return a.m_last_tx_time < b.m_last_tx_time;
- if (a.m_relay_txs != b.m_relay_txs) return b.m_relay_txs;
- if (a.fBloomFilter != b.fBloomFilter) return a.fBloomFilter;
- return a.m_connected > b.m_connected;
-}
-
-// Pick out the potential block-relay only peers, and sort them by last block time.
-static bool CompareNodeBlockRelayOnlyTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
-{
- if (a.m_relay_txs != b.m_relay_txs) return a.m_relay_txs;
- if (a.m_last_block_time != b.m_last_block_time) return a.m_last_block_time < b.m_last_block_time;
- if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices;
- return a.m_connected > b.m_connected;
-}
-
-/**
- * Sort eviction candidates by network/localhost and connection uptime.
- * Candidates near the beginning are more likely to be evicted, and those
- * near the end are more likely to be protected, e.g. less likely to be evicted.
- * - First, nodes that are not `is_local` and that do not belong to `network`,
- * sorted by increasing uptime (from most recently connected to connected longer).
- * - Then, nodes that are `is_local` or belong to `network`, sorted by increasing uptime.
- */
-struct CompareNodeNetworkTime {
- const bool m_is_local;
- const Network m_network;
- CompareNodeNetworkTime(bool is_local, Network network) : m_is_local(is_local), m_network(network) {}
- bool operator()(const NodeEvictionCandidate& a, const NodeEvictionCandidate& b) const
- {
- if (m_is_local && a.m_is_local != b.m_is_local) return b.m_is_local;
- if ((a.m_network == m_network) != (b.m_network == m_network)) return b.m_network == m_network;
- return a.m_connected > b.m_connected;
- };
-};
-
-//! Sort an array by the specified comparator, then erase the last K elements where predicate is true.
-template <typename T, typename Comparator>
-static void EraseLastKElements(
- std::vector<T>& elements, Comparator comparator, size_t k,
- std::function<bool(const NodeEvictionCandidate&)> predicate = [](const NodeEvictionCandidate& n) { return true; })
-{
- std::sort(elements.begin(), elements.end(), comparator);
- size_t eraseSize = std::min(k, elements.size());
- elements.erase(std::remove_if(elements.end() - eraseSize, elements.end(), predicate), elements.end());
-}
-
-void ProtectEvictionCandidatesByRatio(std::vector<NodeEvictionCandidate>& eviction_candidates)
-{
- // Protect the half of the remaining nodes which have been connected the longest.
- // This replicates the non-eviction implicit behavior, and precludes attacks that start later.
- // To favorise the diversity of our peer connections, reserve up to half of these protected
- // spots for Tor/onion, localhost, I2P, and CJDNS peers, even if they're not longest uptime
- // overall. This helps protect these higher-latency peers that tend to be otherwise
- // disadvantaged under our eviction criteria.
- const size_t initial_size = eviction_candidates.size();
- const size_t total_protect_size{initial_size / 2};
-
- // Disadvantaged networks to protect. In the case of equal counts, earlier array members
- // have the first opportunity to recover unused slots from the previous iteration.
- struct Net { bool is_local; Network id; size_t count; };
- std::array<Net, 4> networks{
- {{false, NET_CJDNS, 0}, {false, NET_I2P, 0}, {/*localhost=*/true, NET_MAX, 0}, {false, NET_ONION, 0}}};
-
- // Count and store the number of eviction candidates per network.
- for (Net& n : networks) {
- n.count = std::count_if(eviction_candidates.cbegin(), eviction_candidates.cend(),
- [&n](const NodeEvictionCandidate& c) {
- return n.is_local ? c.m_is_local : c.m_network == n.id;
- });
- }
- // Sort `networks` by ascending candidate count, to give networks having fewer candidates
- // the first opportunity to recover unused protected slots from the previous iteration.
- std::stable_sort(networks.begin(), networks.end(), [](Net a, Net b) { return a.count < b.count; });
-
- // Protect up to 25% of the eviction candidates by disadvantaged network.
- const size_t max_protect_by_network{total_protect_size / 2};
- size_t num_protected{0};
-
- while (num_protected < max_protect_by_network) {
- // Count the number of disadvantaged networks from which we have peers to protect.
- auto num_networks = std::count_if(networks.begin(), networks.end(), [](const Net& n) { return n.count; });
- if (num_networks == 0) {
- break;
- }
- const size_t disadvantaged_to_protect{max_protect_by_network - num_protected};
- const size_t protect_per_network{std::max(disadvantaged_to_protect / num_networks, static_cast<size_t>(1))};
- // Early exit flag if there are no remaining candidates by disadvantaged network.
- bool protected_at_least_one{false};
-
- for (Net& n : networks) {
- if (n.count == 0) continue;
- const size_t before = eviction_candidates.size();
- EraseLastKElements(eviction_candidates, CompareNodeNetworkTime(n.is_local, n.id),
- protect_per_network, [&n](const NodeEvictionCandidate& c) {
- return n.is_local ? c.m_is_local : c.m_network == n.id;
- });
- const size_t after = eviction_candidates.size();
- if (before > after) {
- protected_at_least_one = true;
- const size_t delta{before - after};
- num_protected += delta;
- if (num_protected >= max_protect_by_network) {
- break;
- }
- n.count -= delta;
- }
- }
- if (!protected_at_least_one) {
- break;
- }
- }
-
- // Calculate how many we removed, and update our total number of peers that
- // we want to protect based on uptime accordingly.
- assert(num_protected == initial_size - eviction_candidates.size());
- const size_t remaining_to_protect{total_protect_size - num_protected};
- EraseLastKElements(eviction_candidates, ReverseCompareNodeTimeConnected, remaining_to_protect);
-}
-
-[[nodiscard]] std::optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates)
-{
- // Protect connections with certain characteristics
-
- // Deterministically select 4 peers to protect by netgroup.
- // An attacker cannot predict which netgroups will be protected
- EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4);
- // Protect the 8 nodes with the lowest minimum ping time.
- // An attacker cannot manipulate this metric without physically moving nodes closer to the target.
- EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8);
- // Protect 4 nodes that most recently sent us novel transactions accepted into our mempool.
- // An attacker cannot manipulate this metric without performing useful work.
- EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
- // Protect up to 8 non-tx-relay peers that have sent us novel blocks.
- EraseLastKElements(vEvictionCandidates, CompareNodeBlockRelayOnlyTime, 8,
- [](const NodeEvictionCandidate& n) { return !n.m_relay_txs && n.fRelevantServices; });
-
- // Protect 4 nodes that most recently sent us novel blocks.
- // An attacker cannot manipulate this metric without performing useful work.
- EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4);
-
- // Protect some of the remaining eviction candidates by ratios of desirable
- // or disadvantaged characteristics.
- ProtectEvictionCandidatesByRatio(vEvictionCandidates);
-
- if (vEvictionCandidates.empty()) return std::nullopt;
-
- // If any remaining peers are preferred for eviction consider only them.
- // This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
- // then we probably don't want to evict it no matter what.
- if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](NodeEvictionCandidate const &n){return n.prefer_evict;})) {
- vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(),
- [](NodeEvictionCandidate const &n){return !n.prefer_evict;}),vEvictionCandidates.end());
- }
-
- // Identify the network group with the most connections and youngest member.
- // (vEvictionCandidates is already sorted by reverse connect time)
- uint64_t naMostConnections;
- unsigned int nMostConnections = 0;
- std::chrono::seconds nMostConnectionsTime{0};
- std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
- for (const NodeEvictionCandidate &node : vEvictionCandidates) {
- std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup];
- group.push_back(node);
- const auto grouptime{group[0].m_connected};
-
- if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
- nMostConnections = group.size();
- nMostConnectionsTime = grouptime;
- naMostConnections = node.nKeyedNetGroup;
- }
- }
-
- // Reduce to the network group with the most connections
- vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]);
-
- // Disconnect from the network group with the most connections
- return vEvictionCandidates.front().id;
-}
-
/** Try to find a connection to evict when the node is full.
* Extreme care must be taken to avoid opening the node to attacker
* triggered network partitioning.
@@ -1095,18 +867,24 @@ bool CConnman::AttemptToEvictConnection()
LOCK(m_nodes_mutex);
for (const CNode* node : m_nodes) {
- if (node->HasPermission(NetPermissionFlags::NoBan))
- continue;
- if (!node->IsInboundConn())
- continue;
if (node->fDisconnect)
continue;
- NodeEvictionCandidate candidate = {node->GetId(), node->m_connected, node->m_min_ping_time,
- node->m_last_block_time, node->m_last_tx_time,
- HasAllDesirableServiceFlags(node->nServices),
- node->m_relays_txs.load(), node->m_bloom_filter_loaded.load(),
- node->nKeyedNetGroup, node->m_prefer_evict, node->addr.IsLocal(),
- node->ConnectedThroughNetwork()};
+ NodeEvictionCandidate candidate{
+ .id = node->GetId(),
+ .m_connected = node->m_connected,
+ .m_min_ping_time = node->m_min_ping_time,
+ .m_last_block_time = node->m_last_block_time,
+ .m_last_tx_time = node->m_last_tx_time,
+ .fRelevantServices = node->m_has_all_wanted_services,
+ .m_relay_txs = node->m_relays_txs.load(),
+ .fBloomFilter = node->m_bloom_filter_loaded.load(),
+ .nKeyedNetGroup = node->nKeyedNetGroup,
+ .prefer_evict = node->m_prefer_evict,
+ .m_is_local = node->addr.IsLocal(),
+ .m_network = node->ConnectedThroughNetwork(),
+ .m_noban = node->HasPermission(NetPermissionFlags::NoBan),
+ .m_conn_type = node->m_conn_type,
+ };
vEvictionCandidates.push_back(candidate);
}
}
@@ -1140,12 +918,12 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
}
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
- LogPrintf("Warning: Unknown socket family\n");
+ LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "Unknown socket family\n");
} else {
addr = CAddress{MaybeFlipIPv6toCJDNS(addr), NODE_NONE};
}
- const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(sock->Get())), NODE_NONE};
+ const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(*sock)), NODE_NONE};
NetPermissionFlags permissionFlags = NetPermissionFlags::None;
hListenSocket.AddSocketPermissionFlags(permissionFlags);
@@ -1231,7 +1009,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
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,
std::move(sock),
addr,
CalculateKeyedNetGroup(addr),
@@ -1243,7 +1020,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
pnode->AddRef();
pnode->m_permissionFlags = permissionFlags;
pnode->m_prefer_evict = discouraged;
- m_msgproc->InitializeNode(pnode);
+ m_msgproc->InitializeNode(*pnode, nodeServices);
LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
@@ -1395,13 +1172,12 @@ bool CConnman::InactivityCheck(const CNode& node) const
return false;
}
-bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
- std::set<SOCKET>& recv_set,
- std::set<SOCKET>& send_set,
- std::set<SOCKET>& error_set)
+Sock::EventsPerSock CConnman::GenerateWaitSockets(Span<CNode* const> nodes)
{
+ Sock::EventsPerSock events_per_sock;
+
for (const ListenSocket& hListenSocket : vhListenSocket) {
- recv_set.insert(hListenSocket.sock->Get());
+ events_per_sock.emplace(hListenSocket.sock, Sock::Events{Sock::RECV});
}
for (CNode* pnode : nodes) {
@@ -1428,171 +1204,52 @@ bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
continue;
}
- error_set.insert(pnode->m_sock->Get());
+ Sock::Event requested{0};
if (select_send) {
- send_set.insert(pnode->m_sock->Get());
- continue;
- }
- if (select_recv) {
- recv_set.insert(pnode->m_sock->Get());
- }
- }
-
- return !recv_set.empty() || !send_set.empty() || !error_set.empty();
-}
-
-#ifdef USE_POLL
-void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
- std::set<SOCKET>& recv_set,
- std::set<SOCKET>& send_set,
- std::set<SOCKET>& error_set)
-{
- std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
- if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
- interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
- return;
- }
-
- std::unordered_map<SOCKET, struct pollfd> pollfds;
- for (SOCKET socket_id : recv_select_set) {
- pollfds[socket_id].fd = socket_id;
- pollfds[socket_id].events |= POLLIN;
- }
-
- for (SOCKET socket_id : send_select_set) {
- pollfds[socket_id].fd = socket_id;
- pollfds[socket_id].events |= POLLOUT;
- }
-
- for (SOCKET socket_id : error_select_set) {
- pollfds[socket_id].fd = socket_id;
- // These flags are ignored, but we set them for clarity
- pollfds[socket_id].events |= POLLERR|POLLHUP;
- }
-
- std::vector<struct pollfd> vpollfds;
- vpollfds.reserve(pollfds.size());
- for (auto it : pollfds) {
- vpollfds.push_back(std::move(it.second));
- }
-
- if (poll(vpollfds.data(), vpollfds.size(), SELECT_TIMEOUT_MILLISECONDS) < 0) return;
-
- if (interruptNet) return;
-
- for (struct pollfd pollfd_entry : vpollfds) {
- if (pollfd_entry.revents & POLLIN) recv_set.insert(pollfd_entry.fd);
- if (pollfd_entry.revents & POLLOUT) send_set.insert(pollfd_entry.fd);
- if (pollfd_entry.revents & (POLLERR|POLLHUP)) error_set.insert(pollfd_entry.fd);
- }
-}
-#else
-void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
- std::set<SOCKET>& recv_set,
- std::set<SOCKET>& send_set,
- std::set<SOCKET>& error_set)
-{
- std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
- if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
- interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
- return;
- }
-
- //
- // Find which sockets have data to receive
- //
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = SELECT_TIMEOUT_MILLISECONDS * 1000; // frequency to poll pnode->vSend
-
- fd_set fdsetRecv;
- fd_set fdsetSend;
- fd_set fdsetError;
- FD_ZERO(&fdsetRecv);
- FD_ZERO(&fdsetSend);
- FD_ZERO(&fdsetError);
- SOCKET hSocketMax = 0;
-
- for (SOCKET hSocket : recv_select_set) {
- FD_SET(hSocket, &fdsetRecv);
- hSocketMax = std::max(hSocketMax, hSocket);
- }
-
- for (SOCKET hSocket : send_select_set) {
- FD_SET(hSocket, &fdsetSend);
- hSocketMax = std::max(hSocketMax, hSocket);
- }
-
- for (SOCKET hSocket : error_select_set) {
- FD_SET(hSocket, &fdsetError);
- hSocketMax = std::max(hSocketMax, hSocket);
- }
-
- int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
-
- if (interruptNet)
- return;
-
- if (nSelect == SOCKET_ERROR)
- {
- int nErr = WSAGetLastError();
- LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
- for (unsigned int i = 0; i <= hSocketMax; i++)
- FD_SET(i, &fdsetRecv);
- FD_ZERO(&fdsetSend);
- FD_ZERO(&fdsetError);
- if (!interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS)))
- return;
- }
-
- for (SOCKET hSocket : recv_select_set) {
- if (FD_ISSET(hSocket, &fdsetRecv)) {
- recv_set.insert(hSocket);
+ requested = Sock::SEND;
+ } else if (select_recv) {
+ requested = Sock::RECV;
}
- }
- for (SOCKET hSocket : send_select_set) {
- if (FD_ISSET(hSocket, &fdsetSend)) {
- send_set.insert(hSocket);
- }
+ events_per_sock.emplace(pnode->m_sock, Sock::Events{requested});
}
- for (SOCKET hSocket : error_select_set) {
- if (FD_ISSET(hSocket, &fdsetError)) {
- error_set.insert(hSocket);
- }
- }
+ return events_per_sock;
}
-#endif
void CConnman::SocketHandler()
{
- std::set<SOCKET> recv_set;
- std::set<SOCKET> send_set;
- std::set<SOCKET> error_set;
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+
+ Sock::EventsPerSock events_per_sock;
{
const NodesSnapshot snap{*this, /*shuffle=*/false};
+ const auto timeout = std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS);
+
// Check for the readiness of the already connected sockets and the
// listening sockets in one call ("readiness" as in poll(2) or
// select(2)). If none are ready, wait for a short while and return
// empty sets.
- SocketEvents(snap.Nodes(), recv_set, send_set, error_set);
+ events_per_sock = GenerateWaitSockets(snap.Nodes());
+ if (events_per_sock.empty() || !events_per_sock.begin()->first->WaitMany(timeout, events_per_sock)) {
+ interruptNet.sleep_for(timeout);
+ }
// Service (send/receive) each of the already connected nodes.
- SocketHandlerConnected(snap.Nodes(), recv_set, send_set, error_set);
+ SocketHandlerConnected(snap.Nodes(), events_per_sock);
}
// Accept new connections from listening sockets.
- SocketHandlerListening(recv_set);
+ SocketHandlerListening(events_per_sock);
}
void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
- const std::set<SOCKET>& recv_set,
- const std::set<SOCKET>& send_set,
- const std::set<SOCKET>& error_set)
+ const Sock::EventsPerSock& events_per_sock)
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+
for (CNode* pnode : nodes) {
if (interruptNet)
return;
@@ -1608,9 +1265,12 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
if (!pnode->m_sock) {
continue;
}
- 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;
+ const auto it = events_per_sock.find(pnode->m_sock);
+ if (it != events_per_sock.end()) {
+ recvSet = it->second.occurred & Sock::RECV;
+ sendSet = it->second.occurred & Sock::SEND;
+ errorSet = it->second.occurred & Sock::ERR;
+ }
}
if (recvSet || errorSet)
{
@@ -1680,13 +1340,14 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
}
}
-void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set)
+void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)
{
for (const ListenSocket& listen_socket : vhListenSocket) {
if (interruptNet) {
return;
}
- if (recv_set.count(listen_socket.sock->Get()) > 0) {
+ const auto it = events_per_sock.find(listen_socket.sock);
+ if (it != events_per_sock.end() && it->second.occurred & Sock::RECV) {
AcceptConnection(listen_socket);
}
}
@@ -1694,6 +1355,8 @@ void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set)
void CConnman::ThreadSocketHandler()
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET);
while (!interruptNet)
{
@@ -1805,9 +1468,8 @@ void CConnman::ThreadDNSAddressSeed()
unsigned int nMaxIPs = 256; // Limits number of IPs learned from a DNS seed
if (LookupHost(host, vIPs, nMaxIPs, true)) {
for (const CNetAddr& ip : vIPs) {
- int nOneDay = 24*3600;
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
- addr.nTime = GetTime() - 3*nOneDay - rng.randrange(4*nOneDay); // use a random age between 3 and 7 days old
+ addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
vAdd.push_back(addr);
found++;
}
@@ -1858,7 +1520,13 @@ bool CConnman::GetTryNewOutboundPeer() const
void CConnman::SetTryNewOutboundPeer(bool flag)
{
m_try_another_outbound_peer = flag;
- LogPrint(BCLog::NET, "net: setting try another outbound peer=%s\n", flag ? "true" : "false");
+ LogPrint(BCLog::NET, "setting try another outbound peer=%s\n", flag ? "true" : "false");
+}
+
+void CConnman::StartExtraBlockRelayPeers()
+{
+ LogPrint(BCLog::NET, "enabling extra block-relay-only peers\n");
+ m_start_extra_block_relay_peers = true;
}
// Return the number of peers we have over our outbound connection limit
@@ -1898,6 +1566,7 @@ int CConnman::GetExtraBlockRelayCount() const
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_OPEN_CONNECTION);
+ FastRandomContext rng;
// Connect to specific addresses
if (!connect.empty())
{
@@ -2001,7 +1670,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
case ConnectionType::BLOCK_RELAY:
case ConnectionType::ADDR_FETCH:
case ConnectionType::FEELER:
- setConnected.insert(pnode->addr.GetGroup(addrman.GetAsmap()));
+ setConnected.insert(m_netgroupman.GetGroup(pnode->addr));
} // no default case, so the compiler can warn about missing cases
}
}
@@ -2066,7 +1735,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
addrman.ResolveCollisions();
- int64_t nANow = GetAdjustedTime();
+ const auto nANow{AdjustedTime()};
int nTries = 0;
while (!interruptNet)
{
@@ -2075,7 +1744,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
m_anchors.pop_back();
if (!addr.IsValid() || IsLocal(addr) || !IsReachable(addr) ||
!HasAllDesirableServiceFlags(addr.nServices) ||
- setConnected.count(addr.GetGroup(addrman.GetAsmap()))) continue;
+ setConnected.count(m_netgroupman.GetGroup(addr))) continue;
addrConnect = addr;
LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToString());
break;
@@ -2089,7 +1758,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
break;
CAddress addr;
- int64_t addr_last_try{0};
+ NodeSeconds addr_last_try{0s};
if (fFeeler) {
// First, try to get a tried table collision address. This returns
@@ -2116,7 +1785,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
// Require outbound connections, other than feelers, to be to distinct network groups
- if (!fFeeler && setConnected.count(addr.GetGroup(addrman.GetAsmap()))) {
+ if (!fFeeler && setConnected.count(m_netgroupman.GetGroup(addr))) {
break;
}
@@ -2129,8 +1798,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
continue;
// only consider very recently tried nodes after 30 failed attempts
- if (nANow - addr_last_try < 600 && nTries < 30)
+ if (nANow - addr_last_try < 10min && nTries < 30) {
continue;
+ }
// for non-feelers, require all the services we'll want,
// for feelers, only require they be a full node (only because most
@@ -2151,12 +1821,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
if (addrConnect.IsValid()) {
-
if (fFeeler) {
// Add small amount of random noise before connection to avoid synchronization.
- int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
- if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))
+ if (!interruptNet.sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
return;
+ }
LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
}
@@ -2289,7 +1958,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
if (grantOutbound)
grantOutbound->MoveTo(pnode->grantOutbound);
- m_msgproc->InitializeNode(pnode);
+ m_msgproc->InitializeNode(*pnode, nLocalServices);
{
LOCK(m_nodes_mutex);
m_nodes.push_back(pnode);
@@ -2385,15 +2054,15 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
socklen_t len = sizeof(sockaddr);
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
{
- strError = strprintf(Untranslated("Error: Bind address family for %s not supported"), addrBind.ToString());
- LogPrintf("%s\n", strError.original);
+ strError = strprintf(Untranslated("Bind address family for %s not supported"), addrBind.ToString());
+ LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
return false;
}
std::unique_ptr<Sock> sock = CreateSock(addrBind);
if (!sock) {
- strError = strprintf(Untranslated("Error: Couldn't open socket for incoming connections (socket returned error %s)"), NetworkErrorString(WSAGetLastError()));
- LogPrintf("%s\n", strError.original);
+ strError = strprintf(Untranslated("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;
}
@@ -2422,23 +2091,22 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
#endif
}
- if (::bind(sock->Get(), (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
- {
+ 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.ToString(), PACKAGE_NAME);
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
- LogPrintf("%s\n", strError.original);
+ LogPrintLevel(BCLog::NET, BCLog::Level::Error, "%s\n", strError.original);
return false;
}
LogPrintf("Bound to %s\n", addrBind.ToString());
// Listen for incoming connections
- if (listen(sock->Get(), SOMAXCONN) == SOCKET_ERROR)
+ if (sock->Listen(SOMAXCONN) == SOCKET_ERROR)
{
- strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
- LogPrintf("%s\n", strError.original);
+ 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;
}
@@ -2512,8 +2180,12 @@ void CConnman::SetNetworkActive(bool active)
}
}
-CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in, bool network_active)
- : addrman(addrman_in), nSeed0(nSeed0In), nSeed1(nSeed1In)
+CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in,
+ const NetGroupManager& netgroupman, bool network_active)
+ : addrman(addrman_in)
+ , m_netgroupman{netgroupman}
+ , nSeed0(nSeed0In)
+ , nSeed1(nSeed1In)
{
SetTryNewOutboundPeer(false);
@@ -2574,6 +2246,7 @@ bool CConnman::InitBinds(const Options& options)
bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
Init(connOptions);
if (fListen && !InitBinds(connOptions)) {
@@ -2674,7 +2347,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
class CNetCleanup
{
public:
- CNetCleanup() {}
+ CNetCleanup() = default;
~CNetCleanup()
{
@@ -2788,8 +2461,11 @@ std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addres
{
auto local_socket_bytes = requestor.addrBind.GetAddrBytes();
uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
- .Write(requestor.addr.GetNetwork())
+ .Write(requestor.ConnectedThroughNetwork())
.Write(local_socket_bytes.data(), local_socket_bytes.size())
+ // For outbound connections, the port of the bound address is randomly
+ // assigned by the OS and would therefore not be useful for seeding.
+ .Write(requestor.IsInboundConn() ? requestor.addrBind.GetPort() : 0)
.Finalize();
const auto current_time = GetTime<std::chrono::microseconds>();
auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{});
@@ -2872,7 +2548,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
for (CNode* pnode : m_nodes) {
vstats.emplace_back();
pnode->CopyStats(vstats.back());
- vstats.back().m_mapped_as = pnode->addr.GetMappedAS(addrman.GetAsmap());
+ vstats.back().m_mapped_as = m_netgroupman.GetMappedAS(pnode->addr);
}
}
@@ -2926,7 +2602,9 @@ void CConnman::RecordBytesRecv(uint64_t bytes)
void CConnman::RecordBytesSent(uint64_t bytes)
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
+
nTotalBytesSent += bytes;
const auto now = GetTime<std::chrono::seconds>();
@@ -2942,7 +2620,8 @@ void CConnman::RecordBytesSent(uint64_t bytes)
uint64_t CConnman::GetMaxOutboundTarget() const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
return nMaxOutboundLimit;
}
@@ -2953,7 +2632,15 @@ std::chrono::seconds CConnman::GetMaxOutboundTimeframe() const
std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
+ return GetMaxOutboundTimeLeftInCycle_();
+}
+
+std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle_() const
+{
+ AssertLockHeld(m_total_bytes_sent_mutex);
+
if (nMaxOutboundLimit == 0)
return 0s;
@@ -2967,14 +2654,15 @@ std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const
bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
if (nMaxOutboundLimit == 0)
return false;
if (historicalBlockServingLimit)
{
// keep a large enough buffer to at least relay each block once
- const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle();
+ const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle_();
const uint64_t buffer = timeLeftInCycle / std::chrono::minutes{10} * MAX_BLOCK_SERIALIZED_SIZE;
if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer)
return true;
@@ -2987,7 +2675,8 @@ bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const
uint64_t CConnman::GetOutboundTargetBytesLeft() const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
if (nMaxOutboundLimit == 0)
return 0;
@@ -3001,7 +2690,8 @@ uint64_t CConnman::GetTotalBytesRecv() const
uint64_t CConnman::GetTotalBytesSent() const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
return nTotalBytesSent;
}
@@ -3012,7 +2702,10 @@ ServiceFlags CConnman::GetLocalServices() const
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
-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)
+CNode::CNode(NodeId idIn, 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),
@@ -3022,14 +2715,13 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> s
nKeyedNetGroup(nKeyedNetGroupIn),
id(idIn),
nLocalHostNonce(nLocalHostNonceIn),
- m_conn_type(conn_type_in),
- nLocalServices(nLocalServicesIn)
+ m_conn_type(conn_type_in)
{
if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
for (const std::string &msg : getAllNetMessageTypes())
- mapRecvBytesPerMsgCmd[msg] = 0;
- mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
+ mapRecvBytesPerMsgType[msg] = 0;
+ mapRecvBytesPerMsgType[NET_MESSAGE_TYPE_OTHER] = 0;
if (fLogIPs) {
LogPrint(BCLog::NET, "Added connection to %s peer=%d\n", m_addr_name, id);
@@ -3048,6 +2740,7 @@ bool CConnman::NodeFullyConnected(const CNode* pnode)
void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
size_t nMessageSize = msg.data.size();
LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId());
if (gArgs.GetBoolArg("-capturemessages", false)) {
@@ -3074,7 +2767,7 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
bool optimisticSend(pnode->vSendMsg.empty());
//log total amount of bytes per message type
- pnode->mapSendBytesPerMsgCmd[msg.m_type] += nTotalSize;
+ pnode->mapSendBytesPerMsgType[msg.m_type] += nTotalSize;
pnode->nSendSize += nTotalSize;
if (pnode->nSendSize > nSendBufferMaxSize) pnode->fPauseSend = true;
@@ -3105,9 +2798,9 @@ CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const
return CSipHasher(nSeed0, nSeed1).Write(id);
}
-uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
+uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& address) const
{
- std::vector<unsigned char> vchNetGroup(ad.GetGroup(addrman.GetAsmap()));
+ std::vector<unsigned char> vchNetGroup(m_netgroupman.GetGroup(address));
return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
}
@@ -3127,11 +2820,11 @@ void CaptureMessageToFile(const CAddress& addr,
std::string clean_addr = addr.ToString();
std::replace(clean_addr.begin(), clean_addr.end(), ':', '_');
- fs::path base_path = gArgs.GetDataDirNet() / "message_capture" / clean_addr;
+ fs::path base_path = gArgs.GetDataDirNet() / "message_capture" / fs::u8path(clean_addr);
fs::create_directories(base_path);
fs::path path = base_path / (is_incoming ? "msgs_recv.dat" : "msgs_sent.dat");
- CAutoFile f(fsbridge::fopen(path, "ab"), SER_DISK, CLIENT_VERSION);
+ AutoFile f{fsbridge::fopen(path, "ab")};
ser_writedata64(f, now.count());
f.write(MakeByteSpan(msg_type));