|
26 | 26 | #include <fcntl.h>
|
27 | 27 | #endif
|
28 | 28 |
|
| 29 | +#ifdef USE_POLL |
| 30 | +#include <poll.h> |
| 31 | +#endif |
| 32 | + |
29 | 33 | #ifdef USE_UPNP
|
30 | 34 | #include <miniupnpc/miniupnpc.h>
|
31 | 35 | #include <miniupnpc/miniwget.h>
|
32 | 36 | #include <miniupnpc/upnpcommands.h>
|
33 | 37 | #include <miniupnpc/upnperrors.h>
|
34 | 38 | #endif
|
35 | 39 |
|
| 40 | +#include <unordered_map> |
36 | 41 |
|
37 | 42 | #include <math.h>
|
38 | 43 |
|
@@ -71,6 +76,10 @@ enum BindFlags {
|
71 | 76 | BF_WHITELIST = (1U << 2),
|
72 | 77 | };
|
73 | 78 |
|
| 79 | +// The set of sockets cannot be modified while waiting |
| 80 | +// The sleep time needs to be small to avoid new sockets stalling |
| 81 | +static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50; |
| 82 | + |
74 | 83 | const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
|
75 | 84 |
|
76 | 85 | static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
|
@@ -1258,28 +1267,10 @@ void CConnman::InactivityCheck(CNode *pnode)
|
1258 | 1267 | }
|
1259 | 1268 | }
|
1260 | 1269 |
|
1261 |
| -void CConnman::SocketHandler() |
| 1270 | +bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set) |
1262 | 1271 | {
|
1263 |
| - // |
1264 |
| - // Find which sockets have data to receive |
1265 |
| - // |
1266 |
| - struct timeval timeout; |
1267 |
| - timeout.tv_sec = 0; |
1268 |
| - timeout.tv_usec = 50000; // frequency to poll pnode->vSend |
1269 |
| - |
1270 |
| - fd_set fdsetRecv; |
1271 |
| - fd_set fdsetSend; |
1272 |
| - fd_set fdsetError; |
1273 |
| - FD_ZERO(&fdsetRecv); |
1274 |
| - FD_ZERO(&fdsetSend); |
1275 |
| - FD_ZERO(&fdsetError); |
1276 |
| - SOCKET hSocketMax = 0; |
1277 |
| - bool have_fds = false; |
1278 |
| - |
1279 | 1272 | for (const ListenSocket& hListenSocket : vhListenSocket) {
|
1280 |
| - FD_SET(hListenSocket.socket, &fdsetRecv); |
1281 |
| - hSocketMax = std::max(hSocketMax, hListenSocket.socket); |
1282 |
| - have_fds = true; |
| 1273 | + recv_set.insert(hListenSocket.socket); |
1283 | 1274 | }
|
1284 | 1275 |
|
1285 | 1276 | {
|
@@ -1308,46 +1299,151 @@ void CConnman::SocketHandler()
|
1308 | 1299 | if (pnode->hSocket == INVALID_SOCKET)
|
1309 | 1300 | continue;
|
1310 | 1301 |
|
1311 |
| - FD_SET(pnode->hSocket, &fdsetError); |
1312 |
| - hSocketMax = std::max(hSocketMax, pnode->hSocket); |
1313 |
| - have_fds = true; |
1314 |
| - |
| 1302 | + error_set.insert(pnode->hSocket); |
1315 | 1303 | if (select_send) {
|
1316 |
| - FD_SET(pnode->hSocket, &fdsetSend); |
| 1304 | + send_set.insert(pnode->hSocket); |
1317 | 1305 | continue;
|
1318 | 1306 | }
|
1319 | 1307 | if (select_recv) {
|
1320 |
| - FD_SET(pnode->hSocket, &fdsetRecv); |
| 1308 | + recv_set.insert(pnode->hSocket); |
1321 | 1309 | }
|
1322 | 1310 | }
|
1323 | 1311 | }
|
1324 | 1312 |
|
1325 |
| - int nSelect = select(have_fds ? hSocketMax + 1 : 0, |
1326 |
| - &fdsetRecv, &fdsetSend, &fdsetError, &timeout); |
| 1313 | + return !recv_set.empty() || !send_set.empty() || !error_set.empty(); |
| 1314 | +} |
| 1315 | + |
| 1316 | +#ifdef USE_POLL |
| 1317 | +void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set) |
| 1318 | +{ |
| 1319 | + std::set<SOCKET> recv_select_set, send_select_set, error_select_set; |
| 1320 | + if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) { |
| 1321 | + interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS)); |
| 1322 | + return; |
| 1323 | + } |
| 1324 | + |
| 1325 | + std::unordered_map<SOCKET, struct pollfd> pollfds; |
| 1326 | + for (SOCKET socket_id : recv_select_set) { |
| 1327 | + pollfds[socket_id].fd = socket_id; |
| 1328 | + pollfds[socket_id].events |= POLLIN; |
| 1329 | + } |
| 1330 | + |
| 1331 | + for (SOCKET socket_id : send_select_set) { |
| 1332 | + pollfds[socket_id].fd = socket_id; |
| 1333 | + pollfds[socket_id].events |= POLLOUT; |
| 1334 | + } |
| 1335 | + |
| 1336 | + for (SOCKET socket_id : error_select_set) { |
| 1337 | + pollfds[socket_id].fd = socket_id; |
| 1338 | + // These flags are ignored, but we set them for clarity |
| 1339 | + pollfds[socket_id].events |= POLLERR|POLLHUP; |
| 1340 | + } |
| 1341 | + |
| 1342 | + std::vector<struct pollfd> vpollfds; |
| 1343 | + vpollfds.reserve(pollfds.size()); |
| 1344 | + for (auto it : pollfds) { |
| 1345 | + vpollfds.push_back(std::move(it.second)); |
| 1346 | + } |
| 1347 | + |
| 1348 | + if (poll(vpollfds.data(), vpollfds.size(), SELECT_TIMEOUT_MILLISECONDS) < 0) return; |
| 1349 | + |
| 1350 | + if (interruptNet) return; |
| 1351 | + |
| 1352 | + for (struct pollfd pollfd_entry : vpollfds) { |
| 1353 | + if (pollfd_entry.revents & POLLIN) recv_set.insert(pollfd_entry.fd); |
| 1354 | + if (pollfd_entry.revents & POLLOUT) send_set.insert(pollfd_entry.fd); |
| 1355 | + if (pollfd_entry.revents & (POLLERR|POLLHUP)) error_set.insert(pollfd_entry.fd); |
| 1356 | + } |
| 1357 | +} |
| 1358 | +#else |
| 1359 | +void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set) |
| 1360 | +{ |
| 1361 | + std::set<SOCKET> recv_select_set, send_select_set, error_select_set; |
| 1362 | + if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) { |
| 1363 | + interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS)); |
| 1364 | + return; |
| 1365 | + } |
| 1366 | + |
| 1367 | + // |
| 1368 | + // Find which sockets have data to receive |
| 1369 | + // |
| 1370 | + struct timeval timeout; |
| 1371 | + timeout.tv_sec = 0; |
| 1372 | + timeout.tv_usec = SELECT_TIMEOUT_MILLISECONDS * 1000; // frequency to poll pnode->vSend |
| 1373 | + |
| 1374 | + fd_set fdsetRecv; |
| 1375 | + fd_set fdsetSend; |
| 1376 | + fd_set fdsetError; |
| 1377 | + FD_ZERO(&fdsetRecv); |
| 1378 | + FD_ZERO(&fdsetSend); |
| 1379 | + FD_ZERO(&fdsetError); |
| 1380 | + SOCKET hSocketMax = 0; |
| 1381 | + |
| 1382 | + for (SOCKET hSocket : recv_select_set) { |
| 1383 | + FD_SET(hSocket, &fdsetRecv); |
| 1384 | + hSocketMax = std::max(hSocketMax, hSocket); |
| 1385 | + } |
| 1386 | + |
| 1387 | + for (SOCKET hSocket : send_select_set) { |
| 1388 | + FD_SET(hSocket, &fdsetSend); |
| 1389 | + hSocketMax = std::max(hSocketMax, hSocket); |
| 1390 | + } |
| 1391 | + |
| 1392 | + for (SOCKET hSocket : error_select_set) { |
| 1393 | + FD_SET(hSocket, &fdsetError); |
| 1394 | + hSocketMax = std::max(hSocketMax, hSocket); |
| 1395 | + } |
| 1396 | + |
| 1397 | + int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout); |
| 1398 | + |
1327 | 1399 | if (interruptNet)
|
1328 | 1400 | return;
|
1329 | 1401 |
|
1330 | 1402 | if (nSelect == SOCKET_ERROR)
|
1331 | 1403 | {
|
1332 |
| - if (have_fds) |
1333 |
| - { |
1334 |
| - int nErr = WSAGetLastError(); |
1335 |
| - LogPrintf("socket select error %s\n", NetworkErrorString(nErr)); |
1336 |
| - for (unsigned int i = 0; i <= hSocketMax; i++) |
1337 |
| - FD_SET(i, &fdsetRecv); |
1338 |
| - } |
| 1404 | + int nErr = WSAGetLastError(); |
| 1405 | + LogPrintf("socket select error %s\n", NetworkErrorString(nErr)); |
| 1406 | + for (unsigned int i = 0; i <= hSocketMax; i++) |
| 1407 | + FD_SET(i, &fdsetRecv); |
1339 | 1408 | FD_ZERO(&fdsetSend);
|
1340 | 1409 | FD_ZERO(&fdsetError);
|
1341 |
| - if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000))) |
| 1410 | + if (!interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS))) |
1342 | 1411 | return;
|
1343 | 1412 | }
|
1344 | 1413 |
|
| 1414 | + for (SOCKET hSocket : recv_select_set) { |
| 1415 | + if (FD_ISSET(hSocket, &fdsetRecv)) { |
| 1416 | + recv_set.insert(hSocket); |
| 1417 | + } |
| 1418 | + } |
| 1419 | + |
| 1420 | + for (SOCKET hSocket : send_select_set) { |
| 1421 | + if (FD_ISSET(hSocket, &fdsetSend)) { |
| 1422 | + send_set.insert(hSocket); |
| 1423 | + } |
| 1424 | + } |
| 1425 | + |
| 1426 | + for (SOCKET hSocket : error_select_set) { |
| 1427 | + if (FD_ISSET(hSocket, &fdsetError)) { |
| 1428 | + error_set.insert(hSocket); |
| 1429 | + } |
| 1430 | + } |
| 1431 | +} |
| 1432 | +#endif |
| 1433 | + |
| 1434 | +void CConnman::SocketHandler() |
| 1435 | +{ |
| 1436 | + std::set<SOCKET> recv_set, send_set, error_set; |
| 1437 | + SocketEvents(recv_set, send_set, error_set); |
| 1438 | + |
| 1439 | + if (interruptNet) return; |
| 1440 | + |
1345 | 1441 | //
|
1346 | 1442 | // Accept new connections
|
1347 | 1443 | //
|
1348 | 1444 | for (const ListenSocket& hListenSocket : vhListenSocket)
|
1349 | 1445 | {
|
1350 |
| - if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv)) |
| 1446 | + if (hListenSocket.socket != INVALID_SOCKET && recv_set.count(hListenSocket.socket) > 0) |
1351 | 1447 | {
|
1352 | 1448 | AcceptConnection(hListenSocket);
|
1353 | 1449 | }
|
@@ -1378,9 +1474,9 @@ void CConnman::SocketHandler()
|
1378 | 1474 | LOCK(pnode->cs_hSocket);
|
1379 | 1475 | if (pnode->hSocket == INVALID_SOCKET)
|
1380 | 1476 | continue;
|
1381 |
| - recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv); |
1382 |
| - sendSet = FD_ISSET(pnode->hSocket, &fdsetSend); |
1383 |
| - errorSet = FD_ISSET(pnode->hSocket, &fdsetError); |
| 1477 | + recvSet = recv_set.count(pnode->hSocket) > 0; |
| 1478 | + sendSet = send_set.count(pnode->hSocket) > 0; |
| 1479 | + errorSet = error_set.count(pnode->hSocket) > 0; |
1384 | 1480 | }
|
1385 | 1481 | if (recvSet || errorSet)
|
1386 | 1482 | {
|
|
0 commit comments