Skip to content

Commit 2447c10

Browse files
committed
Merge #9698: net: fix socket close race
9a0b784 net: add a lock around hSocket (Cory Fields) 45e2e08 net: rearrange so that socket accesses can be grouped together (Cory Fields)
2 parents 33f3b21 + 9a0b784 commit 2447c10

File tree

2 files changed

+49
-26
lines changed

2 files changed

+49
-26
lines changed

src/net.cpp

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ void CConnman::DumpBanlist()
425425
void CNode::CloseSocketDisconnect()
426426
{
427427
fDisconnect = true;
428+
LOCK(cs_hSocket);
428429
if (hSocket != INVALID_SOCKET)
429430
{
430431
LogPrint("net", "disconnecting peer=%d\n", id);
@@ -789,7 +790,13 @@ size_t CConnman::SocketSendData(CNode *pnode) const
789790
while (it != pnode->vSendMsg.end()) {
790791
const auto &data = *it;
791792
assert(data.size() > pnode->nSendOffset);
792-
int nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
793+
int nBytes = 0;
794+
{
795+
LOCK(pnode->cs_hSocket);
796+
if (pnode->hSocket == INVALID_SOCKET)
797+
break;
798+
nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
799+
}
793800
if (nBytes > 0) {
794801
pnode->nLastSend = GetSystemTimeInSeconds();
795802
pnode->nSendBytes += nBytes;
@@ -1148,12 +1155,6 @@ void CConnman::ThreadSocketHandler()
11481155
LOCK(cs_vNodes);
11491156
BOOST_FOREACH(CNode* pnode, vNodes)
11501157
{
1151-
if (pnode->hSocket == INVALID_SOCKET)
1152-
continue;
1153-
FD_SET(pnode->hSocket, &fdsetError);
1154-
hSocketMax = std::max(hSocketMax, pnode->hSocket);
1155-
have_fds = true;
1156-
11571158
// Implement the following logic:
11581159
// * If there is data to send, select() for sending data. As this only
11591160
// happens when optimistic write failed, we choose to first drain the
@@ -1164,16 +1165,28 @@ void CConnman::ThreadSocketHandler()
11641165
// receiving data.
11651166
// * Hand off all complete messages to the processor, to be handled without
11661167
// blocking here.
1168+
1169+
bool select_recv = !pnode->fPauseRecv;
1170+
bool select_send;
11671171
{
11681172
LOCK(pnode->cs_vSend);
1169-
if (!pnode->vSendMsg.empty()) {
1170-
FD_SET(pnode->hSocket, &fdsetSend);
1171-
continue;
1172-
}
1173+
select_send = !pnode->vSendMsg.empty();
11731174
}
1174-
{
1175-
if (!pnode->fPauseRecv)
1176-
FD_SET(pnode->hSocket, &fdsetRecv);
1175+
1176+
LOCK(pnode->cs_hSocket);
1177+
if (pnode->hSocket == INVALID_SOCKET)
1178+
continue;
1179+
1180+
FD_SET(pnode->hSocket, &fdsetError);
1181+
hSocketMax = std::max(hSocketMax, pnode->hSocket);
1182+
have_fds = true;
1183+
1184+
if (select_send) {
1185+
FD_SET(pnode->hSocket, &fdsetSend);
1186+
continue;
1187+
}
1188+
if (select_recv) {
1189+
FD_SET(pnode->hSocket, &fdsetRecv);
11771190
}
11781191
}
11791192
}
@@ -1227,15 +1240,30 @@ void CConnman::ThreadSocketHandler()
12271240
//
12281241
// Receive
12291242
//
1230-
if (pnode->hSocket == INVALID_SOCKET)
1231-
continue;
1232-
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
1243+
bool recvSet = false;
1244+
bool sendSet = false;
1245+
bool errorSet = false;
1246+
{
1247+
LOCK(pnode->cs_hSocket);
1248+
if (pnode->hSocket == INVALID_SOCKET)
1249+
continue;
1250+
recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv);
1251+
sendSet = FD_ISSET(pnode->hSocket, &fdsetSend);
1252+
errorSet = FD_ISSET(pnode->hSocket, &fdsetError);
1253+
}
1254+
if (recvSet || errorSet)
12331255
{
12341256
{
12351257
{
12361258
// typical socket buffer is 8K-64K
12371259
char pchBuf[0x10000];
1238-
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
1260+
int nBytes = 0;
1261+
{
1262+
LOCK(pnode->cs_hSocket);
1263+
if (pnode->hSocket == INVALID_SOCKET)
1264+
continue;
1265+
nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
1266+
}
12391267
if (nBytes > 0)
12401268
{
12411269
bool notify = false;
@@ -1284,9 +1312,7 @@ void CConnman::ThreadSocketHandler()
12841312
//
12851313
// Send
12861314
//
1287-
if (pnode->hSocket == INVALID_SOCKET)
1288-
continue;
1289-
if (FD_ISSET(pnode->hSocket, &fdsetSend))
1315+
if (sendSet)
12901316
{
12911317
LOCK(pnode->cs_vSend);
12921318
size_t nBytes = SocketSendData(pnode);
@@ -2275,8 +2301,7 @@ void CConnman::Stop()
22752301

22762302
// Close sockets
22772303
BOOST_FOREACH(CNode* pnode, vNodes)
2278-
if (pnode->hSocket != INVALID_SOCKET)
2279-
CloseSocket(pnode->hSocket);
2304+
pnode->CloseSocketDisconnect();
22802305
BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
22812306
if (hListenSocket.socket != INVALID_SOCKET)
22822307
if (!CloseSocket(hListenSocket.socket))
@@ -2677,9 +2702,6 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
26772702
size_t nBytesSent = 0;
26782703
{
26792704
LOCK(pnode->cs_vSend);
2680-
if(pnode->hSocket == INVALID_SOCKET) {
2681-
return;
2682-
}
26832705
bool optimisticSend(pnode->vSendMsg.empty());
26842706

26852707
//log total amount of bytes per command

src/net.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,7 @@ class CNode
572572
uint64_t nSendBytes;
573573
std::deque<std::vector<unsigned char>> vSendMsg;
574574
CCriticalSection cs_vSend;
575+
CCriticalSection cs_hSocket;
575576

576577
CCriticalSection cs_vProcessMsg;
577578
std::list<CNetMessage> vProcessMsg;

0 commit comments

Comments
 (0)