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)
This commit is contained in:
parent
f1f4e25d60
commit
3b543952d4
74
src/net.cpp
74
src/net.cpp
@ -438,6 +438,7 @@ void CConnman::DumpBanlist()
|
||||
void CNode::CloseSocketDisconnect()
|
||||
{
|
||||
fDisconnect = true;
|
||||
LOCK(cs_hSocket);
|
||||
if (hSocket != INVALID_SOCKET)
|
||||
{
|
||||
LogPrint("net", "disconnecting peer=%d\n", id);
|
||||
@ -802,7 +803,13 @@ size_t CConnman::SocketSendData(CNode *pnode) const
|
||||
while (it != pnode->vSendMsg.end()) {
|
||||
const auto &data = *it;
|
||||
assert(data.size() > pnode->nSendOffset);
|
||||
int nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
int nBytes = 0;
|
||||
{
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
break;
|
||||
nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
}
|
||||
if (nBytes > 0) {
|
||||
pnode->nLastSend = GetSystemTimeInSeconds();
|
||||
pnode->nSendBytes += nBytes;
|
||||
@ -1171,12 +1178,6 @@ void CConnman::ThreadSocketHandler()
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
{
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
FD_SET(pnode->hSocket, &fdsetError);
|
||||
hSocketMax = std::max(hSocketMax, pnode->hSocket);
|
||||
have_fds = true;
|
||||
|
||||
// Implement the following logic:
|
||||
// * If there is data to send, select() for sending data. As this only
|
||||
// happens when optimistic write failed, we choose to first drain the
|
||||
@ -1187,16 +1188,28 @@ void CConnman::ThreadSocketHandler()
|
||||
// receiving data.
|
||||
// * Hand off all complete messages to the processor, to be handled without
|
||||
// blocking here.
|
||||
|
||||
bool select_recv = !pnode->fPauseRecv;
|
||||
bool select_send;
|
||||
{
|
||||
LOCK(pnode->cs_vSend);
|
||||
if (!pnode->vSendMsg.empty()) {
|
||||
FD_SET(pnode->hSocket, &fdsetSend);
|
||||
continue;
|
||||
}
|
||||
select_send = !pnode->vSendMsg.empty();
|
||||
}
|
||||
{
|
||||
if (!pnode->fPauseRecv)
|
||||
FD_SET(pnode->hSocket, &fdsetRecv);
|
||||
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
|
||||
FD_SET(pnode->hSocket, &fdsetError);
|
||||
hSocketMax = std::max(hSocketMax, pnode->hSocket);
|
||||
have_fds = true;
|
||||
|
||||
if (select_send) {
|
||||
FD_SET(pnode->hSocket, &fdsetSend);
|
||||
continue;
|
||||
}
|
||||
if (select_recv) {
|
||||
FD_SET(pnode->hSocket, &fdsetRecv);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1244,15 +1257,30 @@ void CConnman::ThreadSocketHandler()
|
||||
//
|
||||
// Receive
|
||||
//
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
|
||||
bool recvSet = false;
|
||||
bool sendSet = false;
|
||||
bool errorSet = false;
|
||||
{
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv);
|
||||
sendSet = FD_ISSET(pnode->hSocket, &fdsetSend);
|
||||
errorSet = FD_ISSET(pnode->hSocket, &fdsetError);
|
||||
}
|
||||
if (recvSet || errorSet)
|
||||
{
|
||||
{
|
||||
{
|
||||
// typical socket buffer is 8K-64K
|
||||
char pchBuf[0x10000];
|
||||
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
||||
int nBytes = 0;
|
||||
{
|
||||
LOCK(pnode->cs_hSocket);
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
|
||||
}
|
||||
if (nBytes > 0)
|
||||
{
|
||||
bool notify = false;
|
||||
@ -1301,9 +1329,7 @@ void CConnman::ThreadSocketHandler()
|
||||
//
|
||||
// Send
|
||||
//
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
if (FD_ISSET(pnode->hSocket, &fdsetSend))
|
||||
if (sendSet)
|
||||
{
|
||||
LOCK(pnode->cs_vSend);
|
||||
size_t nBytes = SocketSendData(pnode);
|
||||
@ -2341,8 +2367,7 @@ void CConnman::Stop()
|
||||
|
||||
// Close sockets
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
if (pnode->hSocket != INVALID_SOCKET)
|
||||
CloseSocket(pnode->hSocket);
|
||||
pnode->CloseSocketDisconnect();
|
||||
BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
|
||||
if (hListenSocket.socket != INVALID_SOCKET)
|
||||
if (!CloseSocket(hListenSocket.socket))
|
||||
@ -2780,9 +2805,6 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
|
||||
size_t nBytesSent = 0;
|
||||
{
|
||||
LOCK(pnode->cs_vSend);
|
||||
if(pnode->hSocket == INVALID_SOCKET) {
|
||||
return;
|
||||
}
|
||||
bool optimisticSend(pnode->vSendMsg.empty());
|
||||
|
||||
//log total amount of bytes per command
|
||||
|
Loading…
Reference in New Issue
Block a user