// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
-// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "headers.h"
#include "irc.h"
#include "db.h"
#include "net.h"
#include "init.h"
#include "strlcpy.h"
#include "addrman.h"
+#include "ui_interface.h"
#ifdef WIN32
#include <string.h>
void ThreadMapPort2(void* parg);
#endif
void ThreadDNSAddressSeed2(void* parg);
-bool OpenNetworkConnection(const CAddress& addrConnect);
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant = true);
set<CNetAddr> setservAddNodeAddresses;
CCriticalSection cs_setservAddNodeAddresses;
-static CWaitableCriticalSection csOutbound;
-static int nOutbound = 0;
-static CConditionVariable condOutbound;
-
+static CSemaphore *semOutbound = NULL;
unsigned short GetListenPort()
{
}
if (pszKeyword == NULL)
break;
- if (strLine.find(pszKeyword) != -1)
+ if (strLine.find(pszKeyword) != string::npos)
{
strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
break;
}
}
closesocket(hSocket);
- if (strLine.find("<") != -1)
+ if (strLine.find("<") != string::npos)
strLine = strLine.substr(0, strLine.find("<"));
strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
// setAddrKnown automatically filters any duplicate sends.
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushAddress(addr);
+ }
}
}
}
CNode* FindNode(const CNetAddr& ip)
{
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
if ((CNetAddr)pnode->addr == ip)
return (pnode);
CNode* FindNode(const CService& addr)
{
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
if ((CService)pnode->addr == addr)
return (pnode);
pnode->AddRef(nTimeout);
else
pnode->AddRef();
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
vNodes.push_back(pnode);
- WAITABLE_CRITICAL_BLOCK(csOutbound)
- nOutbound++;
+ }
pnode->nTimeConnected = GetTime();
return pnode;
bool CNode::IsBanned(CNetAddr ip)
{
bool fResult = false;
- CRITICAL_BLOCK(cs_setBanned)
{
+ LOCK(cs_setBanned);
std::map<CNetAddr, int64>::iterator i = setBanned.find(ip);
if (i != setBanned.end())
{
if (nMisbehavior >= GetArg("-banscore", 100))
{
int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
- CRITICAL_BLOCK(cs_setBanned)
+ {
+ LOCK(cs_setBanned);
if (setBanned[addr] < banTime)
setBanned[addr] = banTime;
+ }
CloseSocketDisconnect();
printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
return true;
{
printf("ThreadSocketHandler started\n");
list<CNode*> vNodesDisconnected;
- int nPrevNodeCount = 0;
+ unsigned int nPrevNodeCount = 0;
loop
{
//
// Disconnect nodes
//
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
// Disconnect unused nodes
vector<CNode*> vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
// remove from vNodes
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
- if (!pnode->fInbound)
- WAITABLE_CRITICAL_BLOCK(csOutbound)
- {
- nOutbound--;
-
- // Connection slot(s) were removed, notify connection creator(s)
- NOTIFY(condOutbound);
- }
+ if (pnode->fHasGrant)
+ semOutbound->post();
+ pnode->fHasGrant = false;
// close socket and cleanup
pnode->CloseSocketDisconnect();
if (pnode->GetRefCount() <= 0)
{
bool fDelete = false;
- TRY_CRITICAL_BLOCK(pnode->cs_vSend)
- TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
- TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
- TRY_CRITICAL_BLOCK(pnode->cs_inventory)
- fDelete = true;
+ {
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend)
+ {
+ TRY_LOCK(pnode->cs_vRecv, lockRecv);
+ if (lockRecv)
+ {
+ TRY_LOCK(pnode->cs_mapRequests, lockReq);
+ if (lockReq)
+ {
+ TRY_LOCK(pnode->cs_inventory, lockInv);
+ if (lockInv)
+ fDelete = true;
+ }
+ }
+ }
+ }
if (fDelete)
{
vNodesDisconnected.remove(pnode);
if(hListenSocket != INVALID_SOCKET)
FD_SET(hListenSocket, &fdsetRecv);
hSocketMax = max(hSocketMax, hListenSocket);
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->hSocket == INVALID_SOCKET)
FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError);
hSocketMax = max(hSocketMax, pnode->hSocket);
- TRY_CRITICAL_BLOCK(pnode->cs_vSend)
- if (!pnode->vSend.empty())
+ {
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend && !pnode->vSend.empty())
FD_SET(pnode->hSocket, &fdsetSend);
+ }
}
}
if (nSelect == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
- if (hSocketMax > -1)
+ if (hSocketMax != INVALID_SOCKET)
{
printf("socket select error %d\n", nErr);
- for (int i = 0; i <= hSocketMax; i++)
+ for (unsigned int i = 0; i <= hSocketMax; i++)
FD_SET(i, &fdsetRecv);
}
FD_ZERO(&fdsetSend);
if (hSocket != INVALID_SOCKET)
addr = CAddress(sockaddr);
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->fInbound)
- nInbound++;
+ if (pnode->fInbound)
+ nInbound++;
+ }
if (hSocket == INVALID_SOCKET)
{
}
else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
{
- CRITICAL_BLOCK(cs_setservAddNodeAddresses)
+ {
+ LOCK(cs_setservAddNodeAddresses);
if (!setservAddNodeAddresses.count(addr))
closesocket(hSocket);
+ }
}
else if (CNode::IsBanned(addr))
{
printf("accepted connection %s\n", addr.ToString().c_str());
CNode* pnode = new CNode(hSocket, addr, true);
pnode->AddRef();
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
vNodes.push_back(pnode);
+ }
}
}
// Service each socket
//
vector<CNode*> vNodesCopy;
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->AddRef();
continue;
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
{
- TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
+ TRY_LOCK(pnode->cs_vRecv, lockRecv);
+ if (lockRecv)
{
CDataStream& vRecv = pnode->vRecv;
unsigned int nPos = vRecv.size();
continue;
if (FD_ISSET(pnode->hSocket, &fdsetSend))
{
- TRY_CRITICAL_BLOCK(pnode->cs_vSend)
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend)
{
CDataStream& vSend = pnode->vSend;
if (!vSend.empty())
}
}
}
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->Release();
}
{
printf("Loading addresses from DNS seeds (could take a while)\n");
- for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
+ for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
vector<CNetAddr> vaddr;
vector<CAddress> vAdd;
if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
{
CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
if (addr.IsValid())
- OpenNetworkConnection(addr);
+ OpenNetworkConnection(addr, false);
for (int i = 0; i < 10 && i < nLoop; i++)
{
Sleep(500);
if (fShutdown)
return;
- // Limit outbound connections
- int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
+
vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
- WAITABLE_CRITICAL_BLOCK(csOutbound)
- WAIT(condOutbound, fShutdown || nOutbound < nMaxOutbound);
+ semOutbound->wait();
vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
if (fShutdown)
return;
- bool fAddSeeds = false;
-
// Add seed nodes if IRC isn't working
bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
if (addrman.size()==0 && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
{
std::vector<CAddress> vAdd;
- for (int i = 0; i < ARRAYLEN(pnSeed); i++)
+ for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
{
// It'll only connect to one or two seed nodes because once it connects,
// it'll get a pile of addresses with newer timestamps.
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect;
- int64 nBest = std::numeric_limits<int64>::min();
// Only connect to one address per a.b.?.? range.
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
+ int nOutbound = 0;
set<vector<unsigned char> > setConnected;
- CRITICAL_BLOCK(cs_vNodes)
- BOOST_FOREACH(CNode* pnode, vNodes)
+ {
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes) {
setConnected.insert(pnode->addr.GetGroup());
+ if (!pnode->fInbound)
+ nOutbound++;
+ }
+ }
int64 nANow = GetAdjustedTime();
if (addrConnect.IsValid())
OpenNetworkConnection(addrConnect);
+ else
+ semOutbound->post();
}
}
if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0))
{
vservAddressesToAdd.push_back(vservNode);
- CRITICAL_BLOCK(cs_setservAddNodeAddresses)
+ {
+ LOCK(cs_setservAddNodeAddresses);
BOOST_FOREACH(CService& serv, vservNode)
setservAddNodeAddresses.insert(serv);
+ }
}
}
loop
vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd;
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
// (keeping in mind that addnode entries can have many IPs if fAllowDNS)
- CRITICAL_BLOCK(cs_vNodes)
+ {
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
BOOST_FOREACH(CService& addrNode, *(it))
it--;
break;
}
+ }
BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
{
+ semOutbound->wait();
OpenNetworkConnection(CAddress(*(vserv.begin())));
Sleep(500);
if (fShutdown)
}
}
-bool OpenNetworkConnection(const CAddress& addrConnect)
+bool static ReleaseGrant(bool fUseGrant) {
+ if (fUseGrant)
+ semOutbound->post();
+ return false;
+}
+
+// only call this function when semOutbound has been waited for
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant)
{
//
// Initiate outbound network connection
return false;
if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
- return false;
+ return ReleaseGrant(fUseGrant);
vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
CNode* pnode = ConnectNode(addrConnect);
if (fShutdown)
return false;
if (!pnode)
- return false;
+ return ReleaseGrant(fUseGrant);
+ if (pnode->fHasGrant) {
+ // node already has connection grant, release the one that was passed to us
+ ReleaseGrant(fUseGrant);
+ } else {
+ pnode->fHasGrant = fUseGrant;
+ }
pnode->fNetworkNode = true;
return true;
while (!fShutdown)
{
vector<CNode*> vNodesCopy;
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->AddRef();
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
// Receive messages
- TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
- ProcessMessages(pnode);
+ {
+ TRY_LOCK(pnode->cs_vRecv, lockRecv);
+ if (lockRecv)
+ ProcessMessages(pnode);
+ }
if (fShutdown)
return;
// Send messages
- TRY_CRITICAL_BLOCK(pnode->cs_vSend)
- SendMessages(pnode, pnode == pnodeTrickle);
+ {
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend)
+ SendMessages(pnode, pnode == pnodeTrickle);
+ }
if (fShutdown)
return;
}
- CRITICAL_BLOCK(cs_vNodes)
{
+ LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->Release();
}
vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
Sleep(100);
if (fRequestShutdown)
- Shutdown(NULL);
+ StartShutdown();
vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
if (fShutdown)
return;
void StartNode(void* parg)
{
+ if (semOutbound == NULL) {
+ // initialize semaphore
+ int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
+ semOutbound = new CSemaphore(nMaxOutbound);
+ }
+
#ifdef USE_UPNP
#if USE_UPNP
fUseUPnP = GetBoolArg("-upnp", true);
{
vector<CNetAddr> vaddr;
if (LookupHost(pszHostName, vaddr))
+ {
BOOST_FOREACH (const CNetAddr &addr, vaddr)
+ {
if (!addr.IsLocal())
{
addrLocalHost.SetIP(addr);
break;
}
+ }
+ }
}
#else
// Get local host ip
fShutdown = true;
nTransactionsUpdated++;
int64 nStart = GetTime();
- NOTIFY_ALL(condOutbound);
+ if (semOutbound)
+ for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
+ semOutbound->post();
do
{
int nThreadsRunning = 0;