upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp181
1 files changed, 101 insertions, 80 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 34c608c..bb39122 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -13,15 +13,32 @@
13#include <thread> // hardware_concurrency, for the miner thread count 13#include <thread> // hardware_concurrency, for the miner thread count
14#ifdef _WIN32 14#ifdef _WIN32
15#include <winsock2.h> 15#include <winsock2.h>
16#else
17#include <poll.h>
16#endif 18#endif
17#include <openssl/rand.h> 19#include <openssl/rand.h>
18#include "btfaddr.h" 20#include "btfaddr.h"
19#include "btftunnel.h" 21#include "btftunnel.h"
22#include "proxy.h"
20 23
21void ThreadReconnectCachedBtfPeers(void* parg); 24void ThreadReconnectCachedBtfPeers(void* parg);
22void ThreadMessageHandler2(void* parg); 25void ThreadMessageHandler2(void* parg);
23void ThreadSocketHandler2(void* parg); 26void ThreadSocketHandler2(void* parg);
24 27
28#ifdef _WIN32
29typedef WSAPOLLFD BtfPollFd;
30static int BtfPoll(BtfPollFd* pfd, unsigned int nfd, int nTimeoutMs)
31{
32 return WSAPoll(pfd, nfd, nTimeoutMs);
33}
34#else
35typedef struct pollfd BtfPollFd;
36static int BtfPoll(BtfPollFd* pfd, unsigned int nfd, int nTimeoutMs)
37{
38 return poll(pfd, (nfds_t)nfd, nTimeoutMs);
39}
40#endif
41
25 42
26 43
27 44
@@ -153,7 +170,7 @@ static const char* pszSockSite[SOCK_SITES] = {
153 "external-ip probe", "listen socket", "inbound accept", 170 "external-ip probe", "listen socket", "inbound accept",
154 "rendezvous dial", "rendezvous listen", "rendezvous accept", 171 "rendezvous dial", "rendezvous listen", "rendezvous accept",
155 "loopback pair listener", "loopback pair app end", "loopback pair pump end", 172 "loopback pair listener", "loopback pair app end", "loopback pair pump end",
156 "nostr relay" 173 "nostr relay", "stratum bridge"
157}; 174};
158 175
159static string SockAccountingText() 176static string SockAccountingText()
@@ -274,8 +291,8 @@ string GetDiagnosticsText()
274 291
275 // The number that would have made the deafness obvious. Anything held but 292 // The number that would have made the deafness obvious. Anything held but
276 // not watched is a socket this node will never read again. 293 // not watched is a socket this node will never read again.
277 str += strprintf(" peers watched %d of %d that select() can hold%s\n", 294 str += strprintf(" peers watched %d of %d held by poll%s\n",
278 nPeersWatched, (int)FD_SETSIZE - 1, 295 nPeersWatched, nHeld,
279 nHeld > nPeersWatched ? " <-- NOT ALL PEERS ARE BEING READ" : ""); 296 nHeld > nPeersWatched ? " <-- NOT ALL PEERS ARE BEING READ" : "");
280 297
281 if (nBlocksReceived > 0) 298 if (nBlocksReceived > 0)
@@ -361,6 +378,9 @@ string GetDiagnosticsText()
361 378
362bool GetMyExternalIP(unsigned int& ipRet) 379bool GetMyExternalIP(unsigned int& ipRet)
363{ 380{
381 if (BtfSocks5ProxyEnabled())
382 return error("GetMyExternalIP() skipped while SOCKS5 proxy is enabled\n");
383
364 // Try several plain-text IP echo services in order. 384 // Try several plain-text IP echo services in order.
365 // Each returns just the IPv4 address as the first line of the HTTP body. 385 // Each returns just the IPv4 address as the first line of the HTTP body.
366 struct { const char* host; const char* path; } services[] = { 386 struct { const char* host; const char* path; } services[] = {
@@ -1127,7 +1147,7 @@ void CNode::Disconnect()
1127 1147
1128 // Invalidate before anything else can look at it. This used to close the 1148 // Invalidate before anything else can look at it. This used to close the
1129 // socket and leave the handle number sitting in the object, so ~CNode 1149 // socket and leave the handle number sitting in the object, so ~CNode
1130 // closed it a second time and the select loop kept arming it in the 1150 // closed it a second time and the socket loop kept arming it in the
1131 // meantime. See the note on ~CNode in net.h. 1151 // meantime. See the note on ~CNode in net.h.
1132 BtfCloseSocket(hSocket); 1152 BtfCloseSocket(hSocket);
1133 hSocket = INVALID_SOCKET; 1153 hSocket = INVALID_SOCKET;
@@ -1276,52 +1296,49 @@ void ThreadSocketHandler2(void* parg)
1276 // 1296 //
1277 // Find which sockets have data to receive 1297 // Find which sockets have data to receive
1278 // 1298 //
1279 struct timeval timeout; 1299 static const int nPollTimeoutMs = 50; // frequency to poll pnode->vSend
1280 timeout.tv_sec = 0; 1300
1281 timeout.tv_usec = 50000; // frequency to poll pnode->vSend 1301 struct NodePollResult
1282 1302 {
1283 fd_set fdsetRecv; 1303 CNode* pnode;
1284 fd_set fdsetSend; 1304 SOCKET hSocket;
1285 FD_ZERO(&fdsetRecv); 1305 bool fRecv;
1286 FD_ZERO(&fdsetSend); 1306 bool fSend;
1287 SOCKET hSocketMax = 0; 1307 bool fInvalid;
1288 FD_SET(hListenSocket, &fdsetRecv); 1308 NodePollResult(CNode* pnodeIn, SOCKET hSocketIn)
1289 hSocketMax = max(hSocketMax, hListenSocket); 1309 : pnode(pnodeIn), hSocket(hSocketIn), fRecv(false), fSend(false), fInvalid(false) {}
1290 // FD_SET drops silently once the set is full, so count what goes in 1310 };
1291 // and say so. A peer that never makes it into the set is never read, 1311
1292 // and that is indistinguishable from a peer with nothing to say -- 1312 vector<BtfPollFd> vPoll;
1293 // the failure this whole path used to hide. 1313 vector<NodePollResult> vPollNodes;
1294 unsigned int nWatched = 1; // the listen socket 1314
1315 BtfPollFd listenPoll;
1316 memset(&listenPoll, 0, sizeof(listenPoll));
1317 listenPoll.fd = hListenSocket;
1318 listenPoll.events = POLLIN;
1319 vPoll.push_back(listenPoll);
1320
1295 CRITICAL_BLOCK(cs_vNodes) 1321 CRITICAL_BLOCK(cs_vNodes)
1296 { 1322 {
1297 foreach(CNode* pnode, vNodes) 1323 foreach(CNode* pnode, vNodes)
1298 { 1324 {
1299 if (nWatched >= FD_SETSIZE)
1300 break;
1301 // A disconnected node stays in vNodes until its references go. 1325 // A disconnected node stays in vNodes until its references go.
1302 // Arming its closed handle asks select() to watch a number the 1326 // Do not watch a closed handle number: the OS may already have
1303 // operating system may already have given to somebody else. 1327 // handed it to a different connection.
1304 if (pnode->hSocket == INVALID_SOCKET) 1328 if (pnode->hSocket == INVALID_SOCKET)
1305 continue; 1329 continue;
1306 FD_SET(pnode->hSocket, &fdsetRecv); 1330
1307 nWatched++; 1331 BtfPollFd pfd;
1308 hSocketMax = max(hSocketMax, pnode->hSocket); 1332 memset(&pfd, 0, sizeof(pfd));
1333 pfd.fd = pnode->hSocket;
1334 pfd.events = POLLIN;
1309 TRY_CRITICAL_BLOCK(pnode->cs_vSend) 1335 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
1310 if (!pnode->vSend.empty()) 1336 if (!pnode->vSend.empty())
1311 FD_SET(pnode->hSocket, &fdsetSend); 1337 pfd.events |= POLLOUT;
1312 } 1338 vPoll.push_back(pfd);
1313 if (vNodes.size() + 1 > (size_t)FD_SETSIZE) 1339 vPollNodes.push_back(NodePollResult(pnode, pnode->hSocket));
1314 {
1315 static int64 nLastWarned = 0;
1316 if (GetTime() - nLastWarned > 60)
1317 {
1318 nLastWarned = GetTime();
1319 printf("WARNING: %d peers but select() can only watch %d -- %d are not being read\n",
1320 (int)vNodes.size(), (int)FD_SETSIZE - 1,
1321 (int)vNodes.size() - (int)FD_SETSIZE + 1);
1322 }
1323 } 1340 }
1324 nPeersWatched = (int)nWatched - 1; // less the listen socket 1341 nPeersWatched = (int)vPollNodes.size();
1325 } 1342 }
1326 1343
1327 // Say the state of the node out loud now and then, so a log pulled off 1344 // Say the state of the node out loud now and then, so a log pulled off
@@ -1342,32 +1359,17 @@ void ThreadSocketHandler2(void* parg)
1342 } 1359 }
1343 1360
1344 vfThreadRunning[0] = false; 1361 vfThreadRunning[0] = false;
1345 int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, NULL, &timeout); 1362 int nPoll = BtfPoll(&vPoll[0], (unsigned int)vPoll.size(), nPollTimeoutMs);
1346 vfThreadRunning[0] = true; 1363 vfThreadRunning[0] = true;
1347 CheckForShutdown(0); 1364 CheckForShutdown(0);
1348 if (nSelect == SOCKET_ERROR) 1365 if (nPoll == SOCKET_ERROR)
1349 { 1366 {
1350 // This used to answer a failed select() by marking every
1351 // descriptor from 0 to hSocketMax ready, which is code written for
1352 // POSIX, where a descriptor is a small integer. A Windows SOCKET is
1353 // a kernel handle in the thousands, so the loop iterated over
1354 // numbers that are not sockets and told the rest of the function
1355 // that every peer had data. One bad handle in the set makes
1356 // select() fail on every pass, so a single closed socket put the
1357 // whole thread into that state permanently.
1358 //
1359 // Find the bad handle instead and let it be dropped.
1360 int nErr = WSAGetLastError(); 1367 int nErr = WSAGetLastError();
1361 LogPrint("net", "select failed: %d\n", nErr); 1368 LogPrint("net", "poll failed: %d\n", nErr);
1362 FD_ZERO(&fdsetRecv);
1363 FD_ZERO(&fdsetSend);
1364 CRITICAL_BLOCK(cs_vNodes) 1369 CRITICAL_BLOCK(cs_vNodes)
1365 { 1370 {
1366 foreach(CNode* pnode, vNodes) 1371 foreach(CNode* pnode, vNodes)
1367 { 1372 {
1368 // Already disconnected: its handle is gone on purpose, and
1369 // reporting it here would name the wrong node for a select()
1370 // failure it did not cause.
1371 if (pnode->hSocket == INVALID_SOCKET) 1373 if (pnode->hSocket == INVALID_SOCKET)
1372 continue; 1374 continue;
1373 int nType = 0; 1375 int nType = 0;
@@ -1376,24 +1378,27 @@ void ThreadSocketHandler2(void* parg)
1376#else 1378#else
1377 socklen_t nTypeLen = sizeof(nType); 1379 socklen_t nTypeLen = sizeof(nType);
1378#endif 1380#endif
1379 if (pnode->hSocket != INVALID_SOCKET && 1381 if (getsockopt(pnode->hSocket, SOL_SOCKET, SO_TYPE, (char*)&nType, &nTypeLen) != 0)
1380 getsockopt(pnode->hSocket, SOL_SOCKET, SO_TYPE, (char*)&nType, &nTypeLen) != 0)
1381 { 1382 {
1382 printf("dropping node %s: its socket is no longer valid\n", 1383 printf("dropping node %s: its socket is no longer valid\n",
1383 pnode->addr.ToString().c_str()); 1384 pnode->addr.ToString().c_str());
1384 pnode->fDisconnect = true; 1385 pnode->fDisconnect = true;
1385 1386
1386 // Stop referring to it, or it goes back into the next 1387 // Stop referring to it, or it goes into the next poll
1387 // select() set and fails it again. 1388 // set and fails it again.
1388 // 1389 //
1389 // Marking fDisconnect is not enough: a node is only 1390 // Marking fDisconnect is not enough: a node is only
1390 // removed from vNodes once it has drained or once 1391 // removed from vNodes once it has drained or once
1391 // DISCONNECT_DRAIN_SECS has passed, so one dead 1392 // DISCONNECT_DRAIN_SECS has passed, so one dead
1392 // descriptor kept failing select() for a full minute -- 1393 // descriptor kept failing the wait for a full minute --
1393 // and a failed select() zeroes both sets above, which 1394 // and a failed wait skips the service loop below
1394 // means NO peer is read on that pass. Measured on a 1395 // entirely, which means NO peer is read on that pass.
1395 // wedged pool: 1,027 consecutive passes over 61 1396 // Measured on a wedged pool under the old select()
1396 // seconds, one bad socket, the entire node deaf. 1397 // implementation: 1,027 consecutive passes over 61
1398 // seconds, one bad socket, the entire node deaf. poll()
1399 // reports a bad descriptor as POLLNVAL on that entry
1400 // rather than failing the whole call, so this path is
1401 // now the backstop rather than the common case.
1397 // 1402 //
1398 // Not closed, only forgotten. getsockopt just told us 1403 // Not closed, only forgotten. getsockopt just told us
1399 // this descriptor is not ours any more; closing it now 1404 // this descriptor is not ours any more; closing it now
@@ -1402,7 +1407,17 @@ void ThreadSocketHandler2(void* parg)
1402 } 1407 }
1403 } 1408 }
1404 } 1409 }
1405 Sleep(timeout.tv_usec/1000); 1410 Sleep(nPollTimeoutMs);
1411 }
1412 else
1413 {
1414 for (size_t i = 0; i < vPollNodes.size(); i++)
1415 {
1416 short revents = vPoll[i + 1].revents; // poll[0] is the listener
1417 vPollNodes[i].fRecv = (revents & (POLLIN | POLLERR | POLLHUP)) != 0;
1418 vPollNodes[i].fSend = (revents & POLLOUT) != 0;
1419 vPollNodes[i].fInvalid = (revents & POLLNVAL) != 0;
1420 }
1406 } 1421 }
1407 RandAddSeed(); 1422 RandAddSeed();
1408 1423
@@ -1418,7 +1433,7 @@ void ThreadSocketHandler2(void* parg)
1418 // 1433 //
1419 // Accept new connections 1434 // Accept new connections
1420 // 1435 //
1421 if (FD_ISSET(hListenSocket, &fdsetRecv)) 1436 if (nPoll != SOCKET_ERROR && (vPoll[0].revents & POLLIN))
1422 { 1437 {
1423 struct sockaddr_in sockaddr; 1438 struct sockaddr_in sockaddr;
1424#ifdef _WIN32 1439#ifdef _WIN32
@@ -1437,7 +1452,7 @@ void ThreadSocketHandler2(void* parg)
1437 { 1452 {
1438 // Refuse rather than accept a connection this node cannot 1453 // Refuse rather than accept a connection this node cannot
1439 // watch. Without this the listen socket kept taking peers -- 1454 // watch. Without this the listen socket kept taking peers --
1440 // it is always in the select set -- while everything past the 1455 // it is always watched -- while everything past the
1441 // limit sat open and unread, which fed on itself: the deafer 1456 // limit sat open and unread, which fed on itself: the deafer
1442 // the node got, the more connections it collected. 1457 // the node got, the more connections it collected.
1443 unsigned int nNodes = 0; 1458 unsigned int nNodes = 0;
@@ -1464,22 +1479,28 @@ void ThreadSocketHandler2(void* parg)
1464 // 1479 //
1465 // Service each socket 1480 // Service each socket
1466 // 1481 //
1467 vector<CNode*> vNodesCopy; 1482 for (size_t i = 0; i < vPollNodes.size(); i++)
1468 CRITICAL_BLOCK(cs_vNodes)
1469 vNodesCopy = vNodes;
1470 foreach(CNode* pnode, vNodesCopy)
1471 { 1483 {
1472 CheckForShutdown(0); 1484 CheckForShutdown(0);
1473 SOCKET hSocket = pnode->hSocket; 1485 NodePollResult& poll = vPollNodes[i];
1474 // Forgotten above because it was already invalid. FD_ISSET on it 1486 CNode* pnode = poll.pnode;
1475 // is meaningless and recv()/send() would be operating on -1. 1487 SOCKET hSocket = poll.hSocket;
1476 if (hSocket == INVALID_SOCKET) 1488
1489 if (hSocket == INVALID_SOCKET || pnode->hSocket != hSocket)
1477 continue; 1490 continue;
1478 1491
1492 if (poll.fInvalid)
1493 {
1494 LogPrint("net", "poll reported invalid socket for %s\n",
1495 pnode->addr.ToString().c_str());
1496 pnode->fDisconnect = true;
1497 continue;
1498 }
1499
1479 // 1500 //
1480 // Receive 1501 // Receive
1481 // 1502 //
1482 if (FD_ISSET(hSocket, &fdsetRecv)) 1503 if (poll.fRecv)
1483 { 1504 {
1484 TRY_CRITICAL_BLOCK(pnode->cs_vRecv) 1505 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
1485 { 1506 {
@@ -1519,7 +1540,7 @@ void ThreadSocketHandler2(void* parg)
1519 // 1540 //
1520 // Send 1541 // Send
1521 // 1542 //
1522 if (FD_ISSET(hSocket, &fdsetSend)) 1543 if (poll.fSend)
1523 { 1544 {
1524 TRY_CRITICAL_BLOCK(pnode->cs_vSend) 1545 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
1525 { 1546 {