aboutsummaryrefslogtreecommitdiff
path: root/src/net.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.h')
-rw-r--r--src/net.h163
1 files changed, 87 insertions, 76 deletions
diff --git a/src/net.h b/src/net.h
index 88efa4a248..5cdddf1fee 100644
--- a/src/net.h
+++ b/src/net.h
@@ -13,9 +13,11 @@
#include <crypto/siphash.h>
#include <hash.h>
#include <i2p.h>
+#include <logging.h>
#include <net_permissions.h>
#include <netaddress.h>
#include <netbase.h>
+#include <netgroup.h>
#include <policy/feerate.h>
#include <protocol.h>
#include <random.h>
@@ -31,6 +33,8 @@
#include <condition_variable>
#include <cstdint>
#include <deque>
+#include <functional>
+#include <list>
#include <map>
#include <memory>
#include <optional>
@@ -98,15 +102,22 @@ struct AddedNodeInfo
class CNodeStats;
class CClientUIInterface;
-struct CSerializedNetMsg
-{
+struct CSerializedNetMsg {
CSerializedNetMsg() = default;
CSerializedNetMsg(CSerializedNetMsg&&) = default;
CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default;
- // No copying, only moves.
+ // No implicit copying, only moves.
CSerializedNetMsg(const CSerializedNetMsg& msg) = delete;
CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;
+ CSerializedNetMsg Copy() const
+ {
+ CSerializedNetMsg copy;
+ copy.data = data;
+ copy.m_type = m_type;
+ return copy;
+ }
+
std::vector<unsigned char> data;
std::string m_type;
};
@@ -182,7 +193,15 @@ enum class ConnectionType {
/** Convert ConnectionType enum to a string value */
std::string ConnectionTypeAsString(ConnectionType conn_type);
+
+/**
+ * Look up IP addresses from all interfaces on the machine and add them to the
+ * list of local addresses to self-advertise.
+ * The loopback interface is skipped and only the first address from each
+ * interface is used.
+ */
void Discover();
+
uint16_t GetListenPort();
enum
@@ -241,7 +260,6 @@ class CNodeStats
public:
NodeId nodeid;
ServiceFlags nServices;
- bool fRelayTxes;
std::chrono::seconds m_last_send;
std::chrono::seconds m_last_recv;
std::chrono::seconds m_last_tx_time;
@@ -262,7 +280,6 @@ public:
NetPermissionFlags m_permissionFlags;
std::chrono::microseconds m_last_ping_time;
std::chrono::microseconds m_min_ping_time;
- CAmount minFeeFilter;
// Our address, as reported by the peer
std::string addrLocal;
// Address of this peer
@@ -402,7 +419,17 @@ public:
NetPermissionFlags m_permissionFlags{NetPermissionFlags::None};
std::atomic<ServiceFlags> nServices{NODE_NONE};
- SOCKET hSocket GUARDED_BY(cs_hSocket);
+
+ /**
+ * Socket used for communication with the node.
+ * May not own a Sock object (after `CloseSocketDisconnect()` or during tests).
+ * `shared_ptr` (instead of `unique_ptr`) is used to avoid premature close of
+ * the underlying file descriptor by one thread while another thread is
+ * poll(2)-ing it for activity.
+ * @see https://github.com/bitcoin/bitcoin/issues/21744 for details.
+ */
+ std::shared_ptr<Sock> m_sock GUARDED_BY(m_sock_mutex);
+
/** Total size of all vSendMsg entries */
size_t nSendSize GUARDED_BY(cs_vSend){0};
/** Offset inside the first vSendMsg already sent */
@@ -410,7 +437,7 @@ public:
uint64_t nSendBytes GUARDED_BY(cs_vSend){0};
std::deque<std::vector<unsigned char>> vSendMsg GUARDED_BY(cs_vSend);
Mutex cs_vSend;
- Mutex cs_hSocket;
+ Mutex m_sock_mutex;
Mutex cs_vRecv;
RecursiveMutex cs_vProcessMsg;
@@ -529,34 +556,15 @@ public:
// Peer selected us as (compact blocks) high-bandwidth peer (BIP152)
std::atomic<bool> m_bip152_highbandwidth_from{false};
- struct TxRelay {
- mutable RecursiveMutex cs_filter;
- // We use fRelayTxes for two purposes -
- // a) it allows us to not relay tx invs before receiving the peer's version message
- // b) the peer may tell us in its version message that we should not relay tx invs
- // unless it loads a bloom filter.
- bool fRelayTxes GUARDED_BY(cs_filter){false};
- std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter) GUARDED_BY(cs_filter){nullptr};
-
- mutable RecursiveMutex cs_tx_inventory;
- CRollingBloomFilter filterInventoryKnown GUARDED_BY(cs_tx_inventory){50000, 0.000001};
- // Set of transaction ids we still have to announce.
- // They are sorted by the mempool before relay, so the order is not important.
- std::set<uint256> setInventoryTxToSend;
- // Used for BIP35 mempool sending
- bool fSendMempool GUARDED_BY(cs_tx_inventory){false};
- // Last time a "MEMPOOL" request was serviced.
- std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
- std::chrono::microseconds nNextInvSend{0};
-
- /** Minimum fee rate with which to filter inv's to this node */
- std::atomic<CAmount> minFeeFilter{0};
- CAmount lastSentFeeFilter{0};
- std::chrono::microseconds m_next_send_feefilter{0};
- };
+ /** Whether we should relay transactions to this peer (their version
+ * message did not include fRelay=false and this is not a block-relay-only
+ * connection). This only changes from false to true. It will never change
+ * back to false. Used only in inbound eviction logic. */
+ std::atomic_bool m_relays_txs{false};
- // m_tx_relay == nullptr if we're not relaying transactions with this peer
- std::unique_ptr<TxRelay> m_tx_relay;
+ /** Whether this peer has loaded a bloom filter. Used only in inbound
+ * eviction logic. */
+ std::atomic_bool m_bloom_filter_loaded{false};
/** UNIX epoch time of the last block received from this peer that we had
* not yet seen (e.g. not already received from another peer), that passed
@@ -578,8 +586,7 @@ public:
* criterium in CConnman::AttemptToEvictConnection. */
std::atomic<std::chrono::microseconds> m_min_ping_time{std::chrono::microseconds::max()};
- CNode(NodeId id, 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);
- ~CNode();
+ CNode(NodeId id, 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(const CNode&) = delete;
CNode& operator=(const CNode&) = delete;
@@ -633,23 +640,6 @@ public:
nRefCount--;
}
- void AddKnownTx(const uint256& hash)
- {
- if (m_tx_relay != nullptr) {
- LOCK(m_tx_relay->cs_tx_inventory);
- m_tx_relay->filterInventoryKnown.insert(hash);
- }
- }
-
- void PushTxInventory(const uint256& hash)
- {
- if (m_tx_relay == nullptr) return;
- LOCK(m_tx_relay->cs_tx_inventory);
- if (!m_tx_relay->filterInventoryKnown.contains(hash)) {
- m_tx_relay->setInventoryTxToSend.insert(hash);
- }
- }
-
void CloseSocketDisconnect();
void CopyStats(CNodeStats& stats);
@@ -771,7 +761,10 @@ public:
bool m_i2p_accept_incoming;
};
- void Init(const Options& connOptions) {
+ void Init(const Options& connOptions) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex)
+ {
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+
nLocalServices = connOptions.nLocalServices;
nMaxConnections = connOptions.nMaxConnections;
m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections);
@@ -787,7 +780,7 @@ public:
nReceiveFloodSize = connOptions.nReceiveFloodSize;
m_peer_connect_timeout = std::chrono::seconds{connOptions.m_peer_connect_timeout};
{
- LOCK(cs_totalBytesSent);
+ LOCK(m_total_bytes_sent_mutex);
nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
}
vWhitelistedRange = connOptions.vWhitelistedRange;
@@ -798,9 +791,11 @@ public:
m_onion_binds = connOptions.onion_binds;
}
- CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, bool network_active = true);
+ CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, const NetGroupManager& netgroupman,
+ bool network_active = true);
+
~CConnman();
- bool Start(CScheduler& scheduler, const Options& options);
+ bool Start(CScheduler& scheduler, const Options& options) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
void StopThreads();
void StopNodes();
@@ -819,7 +814,7 @@ public:
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
- void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);
+ void PushMessage(CNode* pnode, CSerializedNetMsg&& msg) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
using NodeFn = std::function<void(CNode*)>;
void ForEachNode(const NodeFn& func)
@@ -910,24 +905,22 @@ public:
//! that peer during `net_processing.cpp:PushNodeVersion()`.
ServiceFlags GetLocalServices() const;
- uint64_t GetMaxOutboundTarget() const;
+ uint64_t GetMaxOutboundTarget() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
std::chrono::seconds GetMaxOutboundTimeframe() const;
//! check if the outbound target is reached
//! if param historicalBlockServingLimit is set true, the function will
//! response true if the limit for serving historical blocks has been reached
- bool OutboundTargetReached(bool historicalBlockServingLimit) const;
+ bool OutboundTargetReached(bool historicalBlockServingLimit) const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
//! response the bytes left in the current max outbound cycle
//! in case of no limit, it will always response 0
- uint64_t GetOutboundTargetBytesLeft() const;
+ uint64_t GetOutboundTargetBytesLeft() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
- //! returns the time left in the current max outbound cycle
- //! in case of no limit, it will always return 0
- std::chrono::seconds GetMaxOutboundTimeLeftInCycle() const;
+ std::chrono::seconds GetMaxOutboundTimeLeftInCycle() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
uint64_t GetTotalBytesRecv() const;
- uint64_t GetTotalBytesSent() const;
+ uint64_t GetTotalBytesSent() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/** Get a unique deterministic randomizer. */
CSipHasher GetDeterministicRandomizer(uint64_t id) const;
@@ -953,6 +946,10 @@ private:
NetPermissionFlags m_permissions;
};
+ //! returns the time left in the current max outbound cycle
+ //! 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, NetPermissionFlags permissions);
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
bool InitBinds(const Options& options);
@@ -1012,7 +1009,7 @@ private:
/**
* Check connected and listening sockets for IO readiness and process them accordingly.
*/
- void SocketHandler();
+ void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/**
* Do the read/write for connected sockets that are ready for IO.
@@ -1025,7 +1022,8 @@ private:
void 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 std::set<SOCKET>& error_set)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/**
* Accept incoming connections, one from each read-ready listening socket.
@@ -1033,7 +1031,7 @@ private:
*/
void SocketHandlerListening(const std::set<SOCKET>& recv_set);
- void ThreadSocketHandler();
+ void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
void ThreadDNSAddressSeed();
uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;
@@ -1062,7 +1060,7 @@ private:
// Network stats
void RecordBytesRecv(uint64_t bytes);
- void RecordBytesSent(uint64_t bytes);
+ void RecordBytesSent(uint64_t bytes) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/**
* Return vector of current BLOCK_RELAY peers.
@@ -1073,14 +1071,14 @@ private:
static bool NodeFullyConnected(const CNode* pnode);
// Network usage totals
- mutable RecursiveMutex cs_totalBytesSent;
+ mutable Mutex m_total_bytes_sent_mutex;
std::atomic<uint64_t> nTotalBytesRecv{0};
- uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0};
+ uint64_t nTotalBytesSent GUARDED_BY(m_total_bytes_sent_mutex) {0};
// outbound limit & stats
- uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent) {0};
- std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent) {0};
- uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
+ uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(m_total_bytes_sent_mutex) {0};
+ std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(m_total_bytes_sent_mutex) {0};
+ uint64_t nMaxOutboundLimit GUARDED_BY(m_total_bytes_sent_mutex);
// P2P timeout in seconds
std::chrono::seconds m_peer_connect_timeout;
@@ -1096,6 +1094,7 @@ private:
std::atomic<bool> fNetworkActive{true};
bool fAddressesInitialized{false};
AddrMan& addrman;
+ const NetGroupManager& m_netgroupman;
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
Mutex m_addr_fetches_mutex;
std::vector<std::string> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
@@ -1263,7 +1262,17 @@ private:
};
/** Dump binary message to file, with timestamp */
-void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Span<const unsigned char>& data, bool is_incoming);
+void CaptureMessageToFile(const CAddress& addr,
+ const std::string& msg_type,
+ Span<const unsigned char> data,
+ bool is_incoming);
+
+/** Defaults to `CaptureMessageToFile()`, but can be overridden by unit tests. */
+extern std::function<void(const CAddress& addr,
+ const std::string& msg_type,
+ Span<const unsigned char> data,
+ bool is_incoming)>
+ CaptureMessage;
struct NodeEvictionCandidate
{
@@ -1273,7 +1282,7 @@ struct NodeEvictionCandidate
std::chrono::seconds m_last_block_time;
std::chrono::seconds m_last_tx_time;
bool fRelevantServices;
- bool fRelayTxes;
+ bool m_relay_txs;
bool fBloomFilter;
uint64_t nKeyedNetGroup;
bool prefer_evict;
@@ -1307,6 +1316,8 @@ struct NodeEvictionCandidate
*
* - I2P peers
*
+ * - CJDNS peers
+ *
* This helps protect these privacy network peers, which tend to be otherwise
* disadvantaged under our eviction criteria for their higher min ping times
* relative to IPv4/IPv6 peers, and favorise the diversity of peer connections.