Skip to content

Commit 664ac22

Browse files
committed
net: keep reference to each node during socket wait
Create the snapshot of `CConnman::vNodes` to operate on earlier in `CConnman::SocketHandler()`, before calling `CConnman::SocketEvents()` and pass the `vNodes` copy from the snapshot to `SocketEvents()`. This will keep the refcount of each node incremented during `SocketEvents()` so that the `CNode` object is not destroyed before `SocketEvents()` has finished. Currently in `SocketEvents()` we only remember file descriptor numbers (when not holding `CConnman::cs_vNodes`) which is safe, but we will change this to remember pointers to `CNode::m_sock`.
1 parent 75e8bf5 commit 664ac22

File tree

2 files changed

+45
-13
lines changed

2 files changed

+45
-13
lines changed

src/net.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,16 +1331,17 @@ bool CConnman::InactivityCheck(const CNode& node) const
13311331
return false;
13321332
}
13331333

1334-
bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
1334+
bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
1335+
std::set<SOCKET>& recv_set,
1336+
std::set<SOCKET>& send_set,
1337+
std::set<SOCKET>& error_set)
13351338
{
13361339
for (const ListenSocket& hListenSocket : vhListenSocket) {
13371340
recv_set.insert(hListenSocket.socket);
13381341
}
13391342

13401343
{
1341-
LOCK(cs_vNodes);
1342-
for (CNode* pnode : vNodes)
1343-
{
1344+
for (CNode* pnode : nodes) {
13441345
// Implement the following logic:
13451346
// * If there is data to send, select() for sending data. As this only
13461347
// happens when optimistic write failed, we choose to first drain the
@@ -1378,10 +1379,13 @@ bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &s
13781379
}
13791380

13801381
#ifdef USE_POLL
1381-
void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
1382+
void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
1383+
std::set<SOCKET>& recv_set,
1384+
std::set<SOCKET>& send_set,
1385+
std::set<SOCKET>& error_set)
13821386
{
13831387
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
1384-
if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
1388+
if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
13851389
interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
13861390
return;
13871391
}
@@ -1420,10 +1424,13 @@ void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_s
14201424
}
14211425
}
14221426
#else
1423-
void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
1427+
void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
1428+
std::set<SOCKET>& recv_set,
1429+
std::set<SOCKET>& send_set,
1430+
std::set<SOCKET>& error_set)
14241431
{
14251432
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
1426-
if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
1433+
if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
14271434
interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
14281435
return;
14291436
}
@@ -1497,8 +1504,10 @@ void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_s
14971504

14981505
void CConnman::SocketHandler()
14991506
{
1507+
const NodesSnapshot snap{*this, /*shuffle=*/false};
1508+
15001509
std::set<SOCKET> recv_set, send_set, error_set;
1501-
SocketEvents(recv_set, send_set, error_set);
1510+
SocketEvents(snap.Nodes(), recv_set, send_set, error_set);
15021511

15031512
if (interruptNet) return;
15041513

@@ -1513,8 +1522,6 @@ void CConnman::SocketHandler()
15131522
}
15141523
}
15151524

1516-
const NodesSnapshot snap{*this, /*shuffle=*/false};
1517-
15181525
//
15191526
// Service each socket
15201527
//

src/net.h

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -983,8 +983,33 @@ class CConnman
983983
void NotifyNumConnectionsChanged();
984984
/** Return true if the peer is inactive and should be disconnected. */
985985
bool InactivityCheck(const CNode& node) const;
986-
bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
987-
void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
986+
987+
/**
988+
* Generate a collection of sockets to check for IO readiness.
989+
* @param[in] nodes Select from these nodes' sockets.
990+
* @param[out] recv_set Sockets to check for read readiness.
991+
* @param[out] send_set Sockets to check for write readiness.
992+
* @param[out] error_set Sockets to check for errors.
993+
* @return true if at least one socket is to be checked (the returned set is not empty)
994+
*/
995+
bool GenerateSelectSet(const std::vector<CNode*>& nodes,
996+
std::set<SOCKET>& recv_set,
997+
std::set<SOCKET>& send_set,
998+
std::set<SOCKET>& error_set);
999+
1000+
/**
1001+
* Check which sockets are ready for IO.
1002+
* @param[in] nodes Select from these nodes' sockets.
1003+
* @param[out] recv_set Sockets which are ready for read.
1004+
* @param[out] send_set Sockets which are ready for write.
1005+
* @param[out] error_set Sockets which have errors.
1006+
* This calls `GenerateSelectSet()` to gather a list of sockets to check.
1007+
*/
1008+
void SocketEvents(const std::vector<CNode*>& nodes,
1009+
std::set<SOCKET>& recv_set,
1010+
std::set<SOCKET>& send_set,
1011+
std::set<SOCKET>& error_set);
1012+
9881013
void SocketHandler();
9891014
void ThreadSocketHandler();
9901015
void ThreadDNSAddressSeed();

0 commit comments

Comments
 (0)