aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp62
1 files changed, 33 insertions, 29 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 755312682..54ed1d9b5 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -48,6 +48,7 @@ static CNode* pnodeSync = NULL;
uint64 nLocalHostNonce = 0;
static std::vector<SOCKET> vhListenSocket;
CAddrMan addrman;
+int nMaxConnections = 125;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
@@ -840,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);
+ }
}
}
@@ -908,7 +929,7 @@ void ThreadSocketHandler()
if (nErr != WSAEWOULDBLOCK)
printf("socket error accept failed: %d\n", nErr);
}
- else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
+ else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
{
{
LOCK(cs_setservAddNodeAddresses);
@@ -958,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);
@@ -1653,18 +1669,6 @@ bool BindListenPort(const CService &addrBind, string& strError)
strError = "";
int nOne = 1;
-#ifdef WIN32
- // Initialize Windows Sockets
- WSADATA wsadata;
- int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
- if (ret != NO_ERROR)
- {
- strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
- printf("%s\n", strError.c_str());
- return false;
- }
-#endif
-
// Create socket for listening for incoming connections
#ifdef USE_IPV6
struct sockaddr_storage sockaddr;
@@ -1815,7 +1819,7 @@ void StartNode(boost::thread_group& threadGroup)
{
if (semOutbound == NULL) {
// initialize semaphore
- int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
+ int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
semOutbound = new CSemaphore(nMaxOutbound);
}