aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2013-04-30 18:42:01 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2013-05-01 20:56:50 +0200
commita9d9f0f5f72ab1f9ebc2f76bfe3b7921fa2826d7 (patch)
tree3ff31649fefa8ec471a3c97a408d7cb96c86d740 /src
parent1c621e70bee7575cdf31a08c42eeee3db2b7fdbf (diff)
Do not kill connections on recv buffer overflow
Instead of killing a connection when the receive buffer overflows, just temporarily halt receiving before that happens. Also, no matter what, always allow at least one full message in the receive buffer (otherwise blocks larger than the configured buffer size would pause indefinitely).
Diffstat (limited to 'src')
-rw-r--r--src/net.cpp45
1 files changed, 30 insertions, 15 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 3fa48ae484..54ed1d9b51 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -841,19 +841,39 @@ void ThreadSocketHandler()
{
if (pnode->hSocket == INVALID_SOCKET)
continue;
+ FD_SET(pnode->hSocket, &fdsetError);
+ hSocketMax = 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
+ // write buffer in this case before receiving more. This avoids
+ // needlessly queueing received data, if the remote peer is not themselves
+ // receiving data. This means properly utilizing TCP flow control signalling.
+ // * Otherwise, if there is no (complete) message in the receive buffer,
+ // or there is space left in the buffer, select() for receiving data.
+ // * (if neither of the above applies, there is certainly one message
+ // in the receiver buffer ready to be processed).
+ // Together, that means that at least one of the following is always possible,
+ // so we don't deadlock:
+ // * We send some data.
+ // * We wait for data to be received (and disconnect after timeout).
+ // * We process a message in the buffer (message handler thread).
{
TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend) {
- // do not read, if draining write queue
- if (!pnode->vSendMsg.empty())
- FD_SET(pnode->hSocket, &fdsetSend);
- else
- FD_SET(pnode->hSocket, &fdsetRecv);
- FD_SET(pnode->hSocket, &fdsetError);
- hSocketMax = max(hSocketMax, pnode->hSocket);
- have_fds = true;
+ if (lockSend && !pnode->vSendMsg.empty()) {
+ FD_SET(pnode->hSocket, &fdsetSend);
+ continue;
}
}
+ {
+ TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
+ if (lockRecv && (
+ pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() ||
+ pnode->GetTotalRecvSize() <= ReceiveFloodSize()))
+ FD_SET(pnode->hSocket, &fdsetRecv);
+ }
}
}
@@ -959,12 +979,7 @@ void ThreadSocketHandler()
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv)
{
- if (pnode->GetTotalRecvSize() > ReceiveFloodSize()) {
- if (!pnode->fDisconnect)
- printf("socket recv flood control disconnect (%u bytes)\n", pnode->GetTotalRecvSize());
- pnode->CloseSocketDisconnect();
- }
- else {
+ {
// typical socket buffer is 8K-64K
char pchBuf[0x10000];
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);