// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2011 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.
#include "headers.h"
+#include "irc.h"
+#include "db.h"
+#include "net.h"
+#include "init.h"
+#include "strlcpy.h"
+
+#ifdef __WXMSW__
+#include <string.h>
+// This file can be downloaded as a part of the Windows Platform SDK
+// and is required for Bitcoin binaries to work properly on versions
+// of Windows before XP. If you are doing builds of Bitcoin for
+// public release, you should uncomment this line.
+//#include <WSPiApi.h>
+#endif
#ifdef USE_UPNP
#include <miniupnpc/miniwget.h>
#include <miniupnpc/upnperrors.h>
#endif
+using namespace std;
+using namespace boost;
+
static const int MAX_OUTBOUND_CONNECTIONS = 8;
void ThreadMessageHandler2(void* parg);
bool fAllowDNS = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices);
-CNode* pnodeLocalHost = NULL;
+static CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0;
array<int, 10> vnThreadsRunning;
-SOCKET hListenSocket = INVALID_SOCKET;
+static SOCKET hListenSocket = INVALID_SOCKET;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
// Settings
int fUseProxy = false;
+int nConnectTimeout = 5000;
CAddress addrProxy("127.0.0.1",9050);
-bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
+bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout)
{
hSocketRet = INVALID_SOCKET;
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
return false;
-#ifdef BSD
+#ifdef SO_NOSIGPIPE
int set = 1;
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif
- bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168));
- bool fProxy = (fUseProxy && fRoutable);
+ bool fProxy = (fUseProxy && addrConnect.IsRoutable());
struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
+#ifdef __WXMSW__
+ u_long fNonblock = 1;
+ if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
+#else
+ int fFlags = fcntl(hSocket, F_GETFL, 0);
+ if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
+#endif
+ {
+ closesocket(hSocket);
+ return false;
+ }
+
+
if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
{
+ // WSAEINVAL is here because some legacy version of winsock uses it
+ if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
+ {
+ struct timeval timeout;
+ timeout.tv_sec = nTimeout / 1000;
+ timeout.tv_usec = (nTimeout % 1000) * 1000;
+
+ fd_set fdset;
+ FD_ZERO(&fdset);
+ FD_SET(hSocket, &fdset);
+ int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
+ if (nRet == 0)
+ {
+ printf("connection timeout\n");
+ closesocket(hSocket);
+ return false;
+ }
+ if (nRet == SOCKET_ERROR)
+ {
+ printf("select() for connection failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ socklen_t nRetSize = sizeof(nRet);
+#ifdef __WXMSW__
+ if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
+#else
+ if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
+#endif
+ {
+ printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ if (nRet != 0)
+ {
+ printf("connect() failed after select(): %s\n",strerror(nRet));
+ closesocket(hSocket);
+ return false;
+ }
+ }
+#ifdef __WXMSW__
+ else if (WSAGetLastError() != WSAEISCONN)
+#else
+ else
+#endif
+ {
+ printf("connect() failed: %i\n",WSAGetLastError());
+ closesocket(hSocket);
+ return false;
+ }
+ }
+
+ /*
+ this isn't even strictly necessary
+ CNode::ConnectNode immediately turns the socket back to non-blocking
+ but we'll turn it back to blocking just in case
+ */
+#ifdef __WXMSW__
+ fNonblock = 0;
+ if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
+#else
+ fFlags = fcntl(hSocket, F_GETFL, 0);
+ if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
+#endif
+ {
closesocket(hSocket);
return false;
}
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
CRITICAL_BLOCK(cs_vNodes)
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushAddress(addr);
}
}
-bool AddAddress(CAddress addr, int64 nTimePenalty)
+bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
{
if (!addr.IsRoutable())
return false;
// New address
printf("AddAddress(%s)\n", addr.ToString().c_str());
mapAddresses.insert(make_pair(addr.GetKey(), addr));
- CAddrDB().WriteAddress(addr);
+ if (pAddrDB)
+ pAddrDB->WriteAddress(addr);
+ else
+ CAddrDB().WriteAddress(addr);
return true;
}
else
fUpdated = true;
}
if (fUpdated)
- CAddrDB().WriteAddress(addrFound);
+ {
+ if (pAddrDB)
+ pAddrDB->WriteAddress(addrFound);
+ else
+ CAddrDB().WriteAddress(addrFound);
+ }
}
}
return false;
// call this in the destructor so it doesn't get called after it's deleted.
CRITICAL_BLOCK(cs_vNodes)
{
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
{
CRITICAL_BLOCK(pnode->cs_mapRequests)
{
if (pnodeLocalHost->IsSubscribed(nChannel))
return true;
CRITICAL_BLOCK(cs_vNodes)
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->IsSubscribed(nChannel))
return true;
return false;
{
// Relay subscribe
CRITICAL_BLOCK(cs_vNodes)
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode != this)
pnode->PushMessage("subscribe", nChannel, nHops);
}
{
// Relay subscription cancel
CRITICAL_BLOCK(cs_vNodes)
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode != this)
pnode->PushMessage("sub-cancel", nChannel);
}
{
CRITICAL_BLOCK(cs_vNodes)
{
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->addr.ip == ip)
return (pnode);
}
{
CRITICAL_BLOCK(cs_vNodes)
{
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->addr == addr)
return (pnode);
}
{
// Disconnect unused nodes
vector<CNode*> vNodesCopy = vNodes;
- foreach(CNode* pnode, vNodesCopy)
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
if (pnode->fDisconnect ||
(pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
// Delete disconnected nodes
list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
- foreach(CNode* pnode, vNodesDisconnectedCopy)
+ BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
{
// wait until threads are done using it
if (pnode->GetRefCount() <= 0)
hSocketMax = max(hSocketMax, hListenSocket);
CRITICAL_BLOCK(cs_vNodes)
{
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
{
- if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)
+ if (pnode->hSocket == INVALID_SOCKET)
continue;
FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError);
if (nSelect == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
- printf("socket select error %d\n", nErr);
- for (int i = 0; i <= hSocketMax; i++)
- FD_SET(i, &fdsetRecv);
+ if (hSocketMax > -1)
+ {
+ printf("socket select error %d\n", nErr);
+ for (int i = 0; i <= hSocketMax; i++)
+ FD_SET(i, &fdsetRecv);
+ }
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
Sleep(timeout.tv_usec/1000);
int nInbound = 0;
CRITICAL_BLOCK(cs_vNodes)
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->fInbound)
nInbound++;
if (hSocket == INVALID_SOCKET)
CRITICAL_BLOCK(cs_vNodes)
{
vNodesCopy = vNodes;
- foreach(CNode* pnode, vNodesCopy)
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->AddRef();
}
- foreach(CNode* pnode, vNodesCopy)
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
if (fShutdown)
return;
CDataStream& vRecv = pnode->vRecv;
unsigned int nPos = vRecv.size();
- if (nPos > 1000*GetArg("-maxreceivebuffer", 10*1000)) {
+ if (nPos > ReceiveBufferSize()) {
if (!pnode->fDisconnect)
printf("socket recv flood control disconnect (%d bytes)\n", vRecv.size());
pnode->CloseSocketDisconnect();
pnode->CloseSocketDisconnect();
}
}
- if (vSend.size() > 1000*GetArg("-maxsendbuffer", 10*1000)) {
+ if (vSend.size() > SendBufferSize()) {
if (!pnode->fDisconnect)
printf("socket send flood control disconnect (%d bytes)\n", vSend.size());
pnode->CloseSocketDisconnect();
}
CRITICAL_BLOCK(cs_vNodes)
{
- foreach(CNode* pnode, vNodesCopy)
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->Release();
}
{
char intClient[16];
char intPort[6];
+ string strDesc = "Bitcoin " + FormatFullVersion();
#ifndef __WXMSW__
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
- port, port, lanaddr, 0, "TCP", 0);
+ port, port, lanaddr, strDesc.c_str(), "TCP", 0);
#else
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
- port, port, lanaddr, 0, "TCP", 0, "0");
+ port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
#endif
if(r!=UPNPCOMMAND_SUCCESS)
printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
if (fUseUPnP != fMapPort)
{
fUseUPnP = fMapPort;
- CWalletDB().WriteSetting("fUseUPnP", fUseUPnP);
+ WriteSetting("fUseUPnP", fUseUPnP);
}
if (fUseUPnP && vnThreadsRunning[5] < 1)
{
printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
}
}
+#else
+void MapPort(bool /* unused fMapPort */)
+{
+ // Intentionally left blank.
+}
#endif
static const char *strDNSSeed[] = {
"bitseed.xf2.org",
"bitseed.bitcoin.org.uk",
+ "dnsseed.bluematt.me",
};
void DNSAddressSeed()
{
int found = 0;
- printf("Loading addresses from DNS seeds (could take a while)\n");
+ if (!fTestNet)
+ {
+ printf("Loading addresses from DNS seeds (could take a while)\n");
+ CAddrDB addrDB;
+ addrDB.TxnBegin();
- for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
- vector<CAddress> vaddr;
- if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, true))
- {
- foreach (CAddress& addr, vaddr)
+ for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
+ vector<CAddress> vaddr;
+ if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true))
{
- if (addr.GetByte(3) != 127)
+ BOOST_FOREACH (CAddress& addr, vaddr)
{
- addr.nTime = 0;
- AddAddress(addr);
- found++;
+ if (addr.GetByte(3) != 127)
+ {
+ addr.nTime = 0;
+ AddAddress(addr, 0, &addrDB);
+ found++;
+ }
}
}
}
+
+ addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
}
printf("%d addresses found from DNS seeds\n", found);
{
for (int64 nLoop = 0;; nLoop++)
{
- foreach(string strAddr, mapMultiArgs["-connect"])
+ BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
{
CAddress addr(strAddr, fAllowDNS);
if (addr.IsValid())
// Connect to manually added nodes first
if (mapArgs.count("-addnode"))
{
- foreach(string strAddr, mapMultiArgs["-addnode"])
+ BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
{
CAddress addr(strAddr, fAllowDNS);
if (addr.IsValid())
{
int nOutbound = 0;
CRITICAL_BLOCK(cs_vNodes)
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (!pnode->fInbound)
nOutbound++;
int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
{
nSeedDisconnected = GetTime();
CRITICAL_BLOCK(cs_vNodes)
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (setSeed.count(pnode->addr.ip))
pnode->fDisconnect = true;
}
// Keep setting timestamps to 0 so they won't reconnect
if (GetTime() - nSeedDisconnected < 60 * 60)
{
- foreach(PAIRTYPE(const vector<unsigned char>, CAddress)& item, mapAddresses)
+ BOOST_FOREACH(PAIRTYPE(const vector<unsigned char>, CAddress)& item, mapAddresses)
{
if (setSeed.count(item.second.ip) && item.second.nTime != 0)
{
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
set<unsigned int> setConnected;
CRITICAL_BLOCK(cs_vNodes)
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
setConnected.insert(pnode->addr.ip & 0x0000ffff);
CRITICAL_BLOCK(cs_mapAddresses)
{
- foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
+ BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
const CAddress& addr = item.second;
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
CRITICAL_BLOCK(cs_vNodes)
{
vNodesCopy = vNodes;
- foreach(CNode* pnode, vNodesCopy)
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->AddRef();
}
CNode* pnodeTrickle = NULL;
if (!vNodesCopy.empty())
pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
- foreach(CNode* pnode, vNodesCopy)
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
// Receive messages
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
CRITICAL_BLOCK(cs_vNodes)
{
- foreach(CNode* pnode, vNodesCopy)
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->Release();
}
return false;
}
-#ifdef BSD
+#ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
{
vector<CAddress> vaddr;
if (Lookup(pszHostName, vaddr, nLocalServices, -1, true))
- foreach (const CAddress &addr, vaddr)
+ BOOST_FOREACH (const CAddress &addr, vaddr)
if (addr.GetByte(3) != 127)
{
addrLocalHost = addr;
printf("Error: CreateThread(ThreadIRCSeed) failed\n");
// Send and receive from sockets, accept connections
- pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
+ CreateThread(ThreadSocketHandler, NULL, true);
// Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL))
printf("Error: CreateThread(ThreadMessageHandler) failed\n");
// Generate coins in the background
- GenerateBitcoins(fGenerateBitcoins);
+ GenerateBitcoins(fGenerateBitcoins, pwalletMain);
}
bool StopNode()
~CNetCleanup()
{
// Close sockets
- foreach(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->hSocket != INVALID_SOCKET)
closesocket(pnode->hSocket);
if (hListenSocket != INVALID_SOCKET)