Skip to content

Commit ed9e17b

Browse files
committed
net: use pointers to Sock instead of SOCKET in CConnman::SocketEvents()
This will make it easier to mock-test the surrounding code. The pointed to `Sock` objects will not be destroyed while `CConnman::SocketEvents()` is running because they are either pointers to `CNode::m_sock` and we have incremented the refcount in `CConnman::SocketHandler()` or pointers to `CConnman::vhListenSocket` which is only destroyed at shutdown.
1 parent be3ab96 commit ed9e17b

File tree

2 files changed

+61
-54
lines changed

2 files changed

+61
-54
lines changed

src/net.cpp

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,7 @@ bool CConnman::InactivityCheck(const CNode& node) const
12821282
bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes, Sockets& sockets)
12831283
{
12841284
for (const ListenSocket& hListenSocket : vhListenSocket) {
1285-
sockets.recv.insert(hListenSocket.sock->Get());
1285+
sockets.recv.insert(hListenSocket.sock.get());
12861286
}
12871287

12881288
for (CNode* pnode : nodes) {
@@ -1309,13 +1309,13 @@ bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes, Sockets& sock
13091309
continue;
13101310
}
13111311

1312-
sockets.err.insert(pnode->m_sock->Get());
1312+
sockets.err.insert(pnode->m_sock.get());
13131313
if (select_send) {
1314-
sockets.send.insert(pnode->m_sock->Get());
1314+
sockets.send.insert(pnode->m_sock.get());
13151315
continue;
13161316
}
13171317
if (select_recv) {
1318-
sockets.recv.insert(pnode->m_sock->Get());
1318+
sockets.recv.insert(pnode->m_sock.get());
13191319
}
13201320
}
13211321

@@ -1331,42 +1331,52 @@ void CConnman::SocketEvents(const std::vector<CNode*>& nodes, Sockets& sockets)
13311331
return;
13321332
}
13331333

1334-
std::unordered_map<SOCKET, struct pollfd> pollfds;
1335-
for (SOCKET socket_id : sockets_to_check.recv) {
1336-
pollfds[socket_id].fd = socket_id;
1337-
pollfds[socket_id].events |= POLLIN;
1338-
}
1334+
// The same socket may be queued for more than one event (e.g. waiting for both recv
1335+
// and send - in both `sockets_to_check.recv` and `sockets_to_check.send`). We unique
1336+
// them into `by_socket`.
1337+
struct SockAndPollFd {
1338+
Sock* sock;
1339+
pollfd pfd;
1340+
};
1341+
std::unordered_map<SOCKET, SockAndPollFd> by_socket;
13391342

1340-
for (SOCKET socket_id : sockets_to_check.send) {
1341-
pollfds[socket_id].fd = socket_id;
1342-
pollfds[socket_id].events |= POLLOUT;
1343-
}
1343+
// Add the sockets from `from` to `by_socket` for the given events.
1344+
auto AddSocketsForEvents = [&by_socket](auto& from, short events) {
1345+
for (Sock* sock : from) {
1346+
const SOCKET fd = sock->Get();
1347+
by_socket[fd].sock = sock;
1348+
by_socket[fd].pfd.fd = fd;
1349+
by_socket[fd].pfd.events |= events;
1350+
}
1351+
};
13441352

1345-
for (SOCKET socket_id : sockets_to_check.err) {
1346-
pollfds[socket_id].fd = socket_id;
1347-
// These flags are ignored, but we set them for clarity
1348-
pollfds[socket_id].events |= POLLERR|POLLHUP;
1349-
}
1353+
AddSocketsForEvents(sockets_to_check.recv, POLLIN);
1354+
AddSocketsForEvents(sockets_to_check.send, POLLOUT);
1355+
// These flags are ignored by poll(2), but we set them for clarity.
1356+
AddSocketsForEvents(sockets_to_check.err, POLLERR | POLLHUP);
13501357

13511358
std::vector<struct pollfd> vpollfds;
1352-
vpollfds.reserve(pollfds.size());
1353-
for (auto it : pollfds) {
1354-
vpollfds.push_back(std::move(it.second));
1359+
vpollfds.reserve(by_socket.size());
1360+
for (auto& [socket, sock_and_pollfd] : by_socket) {
1361+
vpollfds.push_back(sock_and_pollfd.pfd);
13551362
}
13561363

13571364
if (poll(vpollfds.data(), vpollfds.size(), SELECT_TIMEOUT_MILLISECONDS) < 0) return;
13581365

13591366
if (interruptNet) return;
13601367

13611368
for (struct pollfd pollfd_entry : vpollfds) {
1369+
auto pos = by_socket.find(pollfd_entry.fd);
1370+
assert(pos != by_socket.end());
1371+
Sock* sock = pos->second.sock;
13621372
if (pollfd_entry.revents & POLLIN) {
1363-
sockets.recv.insert(pollfd_entry.fd);
1373+
sockets.recv.insert(sock);
13641374
}
13651375
if (pollfd_entry.revents & POLLOUT) {
1366-
sockets.send.insert(pollfd_entry.fd);
1376+
sockets.send.insert(sock);
13671377
}
13681378
if (pollfd_entry.revents & (POLLERR|POLLHUP)) {
1369-
sockets.err.insert(pollfd_entry.fd);
1379+
sockets.err.insert(sock);
13701380
}
13711381
}
13721382
}
@@ -1394,20 +1404,18 @@ void CConnman::SocketEvents(const std::vector<CNode*>& nodes, Sockets& sockets)
13941404
FD_ZERO(&fdsetError);
13951405
SOCKET hSocketMax = 0;
13961406

1397-
for (SOCKET hSocket : sockets_to_check.recv) {
1398-
FD_SET(hSocket, &fdsetRecv);
1399-
hSocketMax = std::max(hSocketMax, hSocket);
1400-
}
1401-
1402-
for (SOCKET hSocket : sockets_to_check.send) {
1403-
FD_SET(hSocket, &fdsetSend);
1404-
hSocketMax = std::max(hSocketMax, hSocket);
1405-
}
1407+
// Add the sockets from `from` to the given fd set.
1408+
auto AddSocketsForEvents = [&hSocketMax](auto& from, fd_set& set) {
1409+
for (Sock* sock : from) {
1410+
const SOCKET fd = sock->Get();
1411+
FD_SET(fd, &set);
1412+
hSocketMax = std::max(hSocketMax, fd);
1413+
}
1414+
};
14061415

1407-
for (SOCKET hSocket : sockets_to_check.err) {
1408-
FD_SET(hSocket, &fdsetError);
1409-
hSocketMax = std::max(hSocketMax, hSocket);
1410-
}
1416+
AddSocketsForEvents(sockets_to_check.recv, fdsetRecv);
1417+
AddSocketsForEvents(sockets_to_check.send, fdsetSend);
1418+
AddSocketsForEvents(sockets_to_check.err, fdsetError);
14111419

14121420
int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
14131421

@@ -1426,21 +1434,21 @@ void CConnman::SocketEvents(const std::vector<CNode*>& nodes, Sockets& sockets)
14261434
return;
14271435
}
14281436

1429-
for (SOCKET hSocket : sockets_to_check.recv) {
1430-
if (FD_ISSET(hSocket, &fdsetRecv)) {
1431-
sockets.recv.insert(hSocket);
1437+
for (Sock* sock : sockets_to_check.recv) {
1438+
if (FD_ISSET(sock->Get(), &fdsetRecv)) {
1439+
sockets.recv.insert(sock);
14321440
}
14331441
}
14341442

1435-
for (SOCKET hSocket : sockets_to_check.send) {
1436-
if (FD_ISSET(hSocket, &fdsetSend)) {
1437-
sockets.send.insert(hSocket);
1443+
for (Sock* sock : sockets_to_check.send) {
1444+
if (FD_ISSET(sock->Get(), &fdsetSend)) {
1445+
sockets.send.insert(sock);
14381446
}
14391447
}
14401448

1441-
for (SOCKET hSocket : sockets_to_check.err) {
1442-
if (FD_ISSET(hSocket, &fdsetError)) {
1443-
sockets.err.insert(hSocket);
1449+
for (Sock* sock : sockets_to_check.err) {
1450+
if (FD_ISSET(sock->Get(), &fdsetError)) {
1451+
sockets.err.insert(sock);
14441452
}
14451453
}
14461454
}
@@ -1460,8 +1468,7 @@ void CConnman::SocketHandler()
14601468
//
14611469
for (const ListenSocket& hListenSocket : vhListenSocket)
14621470
{
1463-
if (hListenSocket.sock->IsValid() && sockets.recv.count(hListenSocket.sock->Get()) > 0)
1464-
{
1471+
if (hListenSocket.sock->IsValid() && sockets.recv.count(hListenSocket.sock.get()) > 0) {
14651472
AcceptConnection(hListenSocket);
14661473
}
14671474
}
@@ -1484,9 +1491,9 @@ void CConnman::SocketHandler()
14841491
if (!pnode->m_sock->IsValid()) {
14851492
continue;
14861493
}
1487-
recvSet = sockets.recv.count(pnode->m_sock->Get()) > 0;
1488-
sendSet = sockets.send.count(pnode->m_sock->Get()) > 0;
1489-
errorSet = sockets.err.count(pnode->m_sock->Get()) > 0;
1494+
recvSet = sockets.recv.count(pnode->m_sock.get()) > 0;
1495+
sendSet = sockets.send.count(pnode->m_sock.get()) > 0;
1496+
errorSet = sockets.err.count(pnode->m_sock.get()) > 0;
14901497
}
14911498
if (recvSet || errorSet)
14921499
{

src/net.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,9 +1080,9 @@ class CConnman
10801080
* Used to check which of a set of sockets is ready for IO.
10811081
*/
10821082
struct Sockets {
1083-
std::unordered_set<SOCKET> recv;
1084-
std::unordered_set<SOCKET> send;
1085-
std::unordered_set<SOCKET> err;
1083+
std::unordered_set<Sock*> recv;
1084+
std::unordered_set<Sock*> send;
1085+
std::unordered_set<Sock*> err;
10861086
};
10871087

10881088
/**

0 commit comments

Comments
 (0)