aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp396
1 files changed, 201 insertions, 195 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 657a39bcf..2443740c4 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -4,7 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include "net.h"
@@ -36,32 +36,45 @@
#define MSG_NOSIGNAL 0
#endif
+// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
+// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
+#ifdef WIN32
+#ifndef PROTECTION_LEVEL_UNRESTRICTED
+#define PROTECTION_LEVEL_UNRESTRICTED 10
+#endif
+#ifndef IPV6_PROTECTION_LEVEL
+#define IPV6_PROTECTION_LEVEL 23
+#endif
+#endif
+
using namespace std;
using namespace boost;
-static const int MAX_OUTBOUND_CONNECTIONS = 8;
-
-bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
+namespace {
+ const int MAX_OUTBOUND_CONNECTIONS = 8;
+ struct ListenSocket {
+ SOCKET socket;
+ bool whitelisted;
-struct LocalServiceInfo {
- int nScore;
- int nPort;
-};
+ ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {}
+ };
+}
//
// Global state variables
//
bool fDiscover = true;
+bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
-static CCriticalSection cs_mapLocalHost;
-static map<CNetAddr, LocalServiceInfo> mapLocalHost;
+CCriticalSection cs_mapLocalHost;
+map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfReachable[NET_MAX] = {};
static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
static CNode* pnodeSync = NULL;
uint64_t nLocalHostNonce = 0;
-static std::vector<SOCKET> vhListenSocket;
+static std::vector<ListenSocket> vhListenSocket;
CAddrMan addrman;
int nMaxConnections = 125;
@@ -104,7 +117,7 @@ unsigned short GetListenPort()
// find 'best' local address for a particular peer
bool GetLocal(CService& addr, const CNetAddr *paddrPeer)
{
- if (fNoListen)
+ if (!fListen)
return false;
int nBestScore = -1;
@@ -183,7 +196,7 @@ bool RecvLine(SOCKET hSocket, string& strLine)
{
// socket error
int nErr = WSAGetLastError();
- LogPrint("net", "recv failed: %d\n", nErr);
+ LogPrint("net", "recv failed: %s\n", NetworkErrorString(nErr));
return false;
}
}
@@ -294,12 +307,18 @@ bool IsLocal(const CService& addr)
return mapLocalHost.count(addr) > 0;
}
+/** check whether a given network is one we can probably connect to */
+bool IsReachable(enum Network net)
+{
+ LOCK(cs_mapLocalHost);
+ return vfReachable[net] && !vfLimited[net];
+}
+
/** check whether a given address is in a network we can probably connect to */
bool IsReachable(const CNetAddr& addr)
{
- LOCK(cs_mapLocalHost);
enum Network net = addr.GetNetwork();
- return vfReachable[net] && !vfLimited[net];
+ return IsReachable(net);
}
bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
@@ -319,7 +338,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
{
if (!RecvLine(hSocket, strLine))
{
- closesocket(hSocket);
+ CloseSocket(hSocket);
return false;
}
if (pszKeyword == NULL)
@@ -330,7 +349,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
break;
}
}
- closesocket(hSocket);
+ CloseSocket(hSocket);
if (strLine.find("<") != string::npos)
strLine = strLine.substr(0, strLine.find("<"));
strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
@@ -344,7 +363,7 @@ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const cha
return true;
}
}
- closesocket(hSocket);
+ CloseSocket(hSocket);
return error("GetMyExternalIP() : connection closed");
}
@@ -355,7 +374,7 @@ bool GetMyExternalIP(CNetAddr& ipRet)
const char* pszKeyword;
for (int nLookup = 0; nLookup <= 1; nLookup++)
- for (int nHost = 1; nHost <= 2; nHost++)
+ for (int nHost = 1; nHost <= 1; nHost++)
{
// We should be phasing out our use of sites like these. If we need
// replacements, we should ask for volunteers to put this simple
@@ -380,25 +399,6 @@ bool GetMyExternalIP(CNetAddr& ipRet)
pszKeyword = "Address:";
}
- else if (nHost == 2)
- {
- addrConnect = CService("74.208.43.192", 80); // www.showmyip.com
-
- if (nLookup == 1)
- {
- CService addrIP("www.showmyip.com", 80, true);
- if (addrIP.IsValid())
- addrConnect = addrIP;
- }
-
- pszGet = "GET /simple/ HTTP/1.1\r\n"
- "Host: www.showmyip.com\r\n"
- "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
- "Connection: close\r\n"
- "\r\n";
-
- pszKeyword = NULL; // Returns just IP address
- }
if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
return true;
@@ -443,7 +443,7 @@ CNode* FindNode(const CNetAddr& ip)
return NULL;
}
-CNode* FindNode(std::string addrName)
+CNode* FindNode(const std::string& addrName)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -476,11 +476,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
}
}
-
/// debug print
LogPrint("net", "trying connection %s lastseen=%.1fhrs\n",
pszDest ? pszDest : addrConnect.ToString(),
- pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
+ pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
// Connect
SOCKET hSocket;
@@ -488,17 +487,9 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
{
addrman.Attempt(addrConnect);
- LogPrint("net", "connected %s\n", pszDest ? pszDest : addrConnect.ToString());
-
// Set to non-blocking
-#ifdef WIN32
- u_long nOne = 1;
- if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
- LogPrintf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
-#else
- if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
- LogPrintf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
-#endif
+ if (!SetSocketNonBlocking(hSocket, true))
+ LogPrintf("ConnectNode: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
// Add node
CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
@@ -510,12 +501,11 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
}
pnode->nTimeConnected = GetTime();
+
return pnode;
}
- else
- {
- return NULL;
- }
+
+ return NULL;
}
void CNode::CloseSocketDisconnect()
@@ -523,9 +513,8 @@ void CNode::CloseSocketDisconnect()
fDisconnect = true;
if (hSocket != INVALID_SOCKET)
{
- LogPrint("net", "disconnecting node %s\n", addrName);
- closesocket(hSocket);
- hSocket = INVALID_SOCKET;
+ LogPrint("net", "disconnecting peer=%d\n", id);
+ CloseSocket(hSocket);
}
// in case this fails, we'll empty the recv buffer when the CNode is deleted
@@ -538,11 +527,6 @@ void CNode::CloseSocketDisconnect()
pnodeSync = NULL;
}
-void CNode::Cleanup()
-{
-}
-
-
void CNode::PushVersion()
{
int nBestHeight = g_signals.GetHeight().get_value_or(0);
@@ -551,8 +535,11 @@ void CNode::PushVersion()
int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
CAddress addrMe = GetLocalAddress(&addr);
- RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), addr.ToString());
+ GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
+ if (fLogIPs)
+ LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id);
+ else
+ LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight, true);
}
@@ -595,6 +582,24 @@ bool CNode::Ban(const CNetAddr &addr) {
return true;
}
+
+std::vector<CSubNet> CNode::vWhitelistedRange;
+CCriticalSection CNode::cs_vWhitelistedRange;
+
+bool CNode::IsWhitelistedRange(const CNetAddr &addr) {
+ LOCK(cs_vWhitelistedRange);
+ BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) {
+ if (subnet.Match(addr))
+ return true;
+ }
+ return false;
+}
+
+void CNode::AddWhitelistedRange(const CSubNet &subnet) {
+ LOCK(cs_vWhitelistedRange);
+ vWhitelistedRange.push_back(subnet);
+}
+
#undef X
#define X(name) stats.name = name
void CNode::copyStats(CNodeStats &stats)
@@ -611,6 +616,7 @@ void CNode::copyStats(CNodeStats &stats)
X(nStartingHeight);
X(nSendBytes);
X(nRecvBytes);
+ X(fWhitelisted);
stats.fSyncNode = (this == pnodeSync);
// It is common for nodes with good ping times to suddenly become lagged,
@@ -657,6 +663,9 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
pch += handled;
nBytes -= handled;
+
+ if (msg.complete())
+ msg.nTime = GetTimeMicros();
}
return true;
@@ -689,7 +698,6 @@ int CNetMessage::readHeader(const char *pch, unsigned int nBytes)
// switch state to reading message data
in_data = true;
- vRecv.resize(hdr.nMessageSize);
return nCopy;
}
@@ -699,6 +707,11 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes)
unsigned int nRemaining = hdr.nMessageSize - nDataPos;
unsigned int nCopy = std::min(nRemaining, nBytes);
+ if (vRecv.size() < nDataPos + nCopy) {
+ // Allocate up to 256 KiB ahead, but never more than the total message size.
+ vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));
+ }
+
memcpy(&vRecv[nDataPos], pch, nCopy);
nDataPos += nCopy;
@@ -741,7 +754,7 @@ void SocketSendData(CNode *pnode)
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
- LogPrintf("socket send error %d\n", nErr);
+ LogPrintf("socket send error %s\n", NetworkErrorString(nErr));
pnode->CloseSocketDisconnect();
}
}
@@ -784,7 +797,6 @@ void ThreadSocketHandler()
// close socket and cleanup
pnode->CloseSocketDisconnect();
- pnode->Cleanup();
// hold in disconnected pool until all refs are released
if (pnode->fNetworkNode || pnode->fInbound)
@@ -828,7 +840,6 @@ void ThreadSocketHandler()
uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
}
-
//
// Find which sockets have data to receive
//
@@ -845,11 +856,12 @@ void ThreadSocketHandler()
SOCKET hSocketMax = 0;
bool have_fds = false;
- BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
- FD_SET(hListenSocket, &fdsetRecv);
- hSocketMax = max(hSocketMax, hListenSocket);
+ BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket) {
+ FD_SET(hListenSocket.socket, &fdsetRecv);
+ hSocketMax = max(hSocketMax, hListenSocket.socket);
have_fds = true;
}
+
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -901,7 +913,7 @@ void ThreadSocketHandler()
if (have_fds)
{
int nErr = WSAGetLastError();
- LogPrintf("socket select error %d\n", nErr);
+ LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
for (unsigned int i = 0; i <= hSocketMax; i++)
FD_SET(i, &fdsetRecv);
}
@@ -910,66 +922,60 @@ void ThreadSocketHandler()
MilliSleep(timeout.tv_usec/1000);
}
-
//
// Accept new connections
//
- BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
- if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
+ BOOST_FOREACH(const ListenSocket& hListenSocket, vhListenSocket)
{
-#ifdef USE_IPV6
- struct sockaddr_storage sockaddr;
-#else
- struct sockaddr sockaddr;
-#endif
- socklen_t len = sizeof(sockaddr);
- SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
- CAddress addr;
- int nInbound = 0;
+ if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
+ {
+ struct sockaddr_storage sockaddr;
+ socklen_t len = sizeof(sockaddr);
+ SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
+ CAddress addr;
+ int nInbound = 0;
- if (hSocket != INVALID_SOCKET)
- if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
- LogPrintf("Warning: Unknown socket family\n");
+ if (hSocket != INVALID_SOCKET)
+ if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
+ LogPrintf("Warning: Unknown socket family\n");
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->fInbound)
- nInbound++;
- }
+ bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
+ {
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->fInbound)
+ nInbound++;
+ }
- if (hSocket == INVALID_SOCKET)
- {
- int nErr = WSAGetLastError();
- if (nErr != WSAEWOULDBLOCK)
- LogPrintf("socket error accept failed: %d\n", nErr);
- }
- else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
- {
+ if (hSocket == INVALID_SOCKET)
{
- LOCK(cs_setservAddNodeAddresses);
- if (!setservAddNodeAddresses.count(addr))
- closesocket(hSocket);
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK)
+ LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
}
- }
- else if (CNode::IsBanned(addr))
- {
- LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
- closesocket(hSocket);
- }
- else
- {
- LogPrint("net", "accepted connection %s\n", addr.ToString());
- CNode* pnode = new CNode(hSocket, addr, "", true);
- pnode->AddRef();
+ else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
{
- LOCK(cs_vNodes);
- vNodes.push_back(pnode);
+ CloseSocket(hSocket);
+ }
+ else if (CNode::IsBanned(addr) && !whitelisted)
+ {
+ LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
+ CloseSocket(hSocket);
+ }
+ else
+ {
+ CNode* pnode = new CNode(hSocket, addr, "", true);
+ pnode->AddRef();
+ pnode->fWhitelisted = whitelisted;
+
+ {
+ LOCK(cs_vNodes);
+ vNodes.push_back(pnode);
+ }
}
}
}
-
//
// Service each socket
//
@@ -1020,7 +1026,7 @@ void ThreadSocketHandler()
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
if (!pnode->fDisconnect)
- LogPrintf("socket recv error %d\n", nErr);
+ LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
pnode->CloseSocketDisconnect();
}
}
@@ -1043,23 +1049,27 @@ void ThreadSocketHandler()
//
// Inactivity checking
//
- if (pnode->vSendMsg.empty())
- pnode->nLastSendEmpty = GetTime();
- if (GetTime() - pnode->nTimeConnected > 60)
+ int64_t nTime = GetTime();
+ if (nTime - pnode->nTimeConnected > 60)
{
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
{
- LogPrint("net", "socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
+ LogPrint("net", "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->id);
pnode->fDisconnect = true;
}
- else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
+ else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
{
- LogPrintf("socket not sending\n");
+ LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
pnode->fDisconnect = true;
}
- else if (GetTime() - pnode->nLastRecv > 90*60)
+ else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
{
- LogPrintf("socket inactivity timeout\n");
+ LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
+ pnode->fDisconnect = true;
+ }
+ else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())
+ {
+ LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
pnode->fDisconnect = true;
}
}
@@ -1198,6 +1208,18 @@ void MapPort(bool)
void ThreadDNSAddressSeed()
{
+ // goal: only query DNS seeds if address need is acute
+ if ((addrman.size() > 0) &&
+ (!GetBoolArg("-forcednsseed", false))) {
+ MilliSleep(11 * 1000);
+
+ LOCK(cs_vNodes);
+ if (vNodes.size() >= 2) {
+ LogPrintf("P2P peers available. Skipped DNS seeding.\n");
+ return;
+ }
+ }
+
const vector<CDNSSeedData> &vSeeds = Params().DNSSeeds();
int found = 0;
@@ -1440,21 +1462,21 @@ void ThreadOpenAddedConnections()
}
// if successful, this moves the passed grant to the constructed node
-bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot)
+bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
{
//
// Initiate outbound network connection
//
boost::this_thread::interruption_point();
- if (!strDest)
+ if (!pszDest) {
if (IsLocal(addrConnect) ||
FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
- FindNode(addrConnect.ToStringIPPort().c_str()))
+ FindNode(addrConnect.ToStringIPPort()))
return false;
- if (strDest && FindNode(strDest))
+ } else if (FindNode(pszDest))
return false;
- CNode* pnode = ConnectNode(addrConnect, strDest);
+ CNode* pnode = ConnectNode(addrConnect, pszDest);
boost::this_thread::interruption_point();
if (!pnode)
@@ -1471,13 +1493,13 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
// for now, use a very simple selection metric: the node from which we received
// most recently
-double static NodeSyncScore(const CNode *pnode) {
- return -pnode->nLastRecv;
+static int64_t NodeSyncScore(const CNode *pnode) {
+ return pnode->nLastRecv;
}
void static StartSync(const vector<CNode*> &vNodes) {
CNode *pnodeNewSync = NULL;
- double dBestScore = 0;
+ int64_t nBestScore = 0;
int nBestHeight = g_signals.GetHeight().get_value_or(0);
@@ -1489,10 +1511,10 @@ void static StartSync(const vector<CNode*> &vNodes) {
(pnode->nStartingHeight > (nBestHeight - 144)) &&
(pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
// if ok, compare node's score with the best so far
- double dScore = NodeSyncScore(pnode);
- if (pnodeNewSync == NULL || dScore > dBestScore) {
+ int64_t nScore = NodeSyncScore(pnode);
+ if (pnodeNewSync == NULL || nScore > nBestScore) {
pnodeNewSync = pnode;
- dBestScore = dScore;
+ nBestScore = nScore;
}
}
}
@@ -1580,21 +1602,17 @@ void ThreadMessageHandler()
-bool BindListenPort(const CService &addrBind, string& strError)
+bool BindListenPort(const CService &addrBind, string& strError, bool fWhitelisted)
{
strError = "";
int nOne = 1;
// Create socket for listening for incoming connections
-#ifdef USE_IPV6
struct sockaddr_storage sockaddr;
-#else
- struct sockaddr sockaddr;
-#endif
socklen_t len = sizeof(sockaddr);
if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len))
{
- strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString());
+ strError = strprintf("Error: Bind address family for %s not supported", addrBind.ToString());
LogPrintf("%s\n", strError);
return false;
}
@@ -1602,36 +1620,28 @@ bool BindListenPort(const CService &addrBind, string& strError)
SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hListenSocket == INVALID_SOCKET)
{
- strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
+ strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
return false;
}
+#ifndef WIN32
#ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
-
-#ifndef WIN32
// Allow binding if the port is still in TIME_WAIT state after
- // the program was closed and restarted. Not an issue on windows.
+ // the program was closed and restarted. Not an issue on windows!
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif
-
-#ifdef WIN32
// Set to non-blocking, incoming connections will also inherit this
- if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
-#else
- if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
-#endif
- {
- strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
+ if (!SetSocketNonBlocking(hListenSocket, true)) {
+ strError = strprintf("BindListenPort: Setting listening socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
return false;
}
-#ifdef USE_IPV6
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if (addrBind.IsIPv6()) {
@@ -1643,13 +1653,10 @@ bool BindListenPort(const CService &addrBind, string& strError)
#endif
#endif
#ifdef WIN32
- int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */;
- int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */;
- // this call is allowed to fail
- setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int));
+ int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
+ setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int));
#endif
}
-#endif
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
@@ -1657,8 +1664,9 @@ bool BindListenPort(const CService &addrBind, string& strError)
if (nErr == WSAEADDRINUSE)
strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString());
else
- strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString(), nErr, strerror(nErr));
+ strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError);
+ CloseSocket(hListenSocket);
return false;
}
LogPrintf("Bound to %s\n", addrBind.ToString());
@@ -1666,14 +1674,15 @@ bool BindListenPort(const CService &addrBind, string& strError)
// Listen for incoming connections
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
{
- strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %d)"), WSAGetLastError());
+ strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
LogPrintf("%s\n", strError);
+ CloseSocket(hListenSocket);
return false;
}
- vhListenSocket.push_back(hListenSocket);
+ vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
- if (addrBind.IsRoutable() && fDiscover)
+ if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
AddLocal(addrBind, LOCAL_BIND);
return true;
@@ -1716,7 +1725,6 @@ void static Discover(boost::thread_group& threadGroup)
if (AddLocal(addr, LOCAL_IF))
LogPrintf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString());
}
-#ifdef USE_IPV6
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
@@ -1724,7 +1732,6 @@ void static Discover(boost::thread_group& threadGroup)
if (AddLocal(addr, LOCAL_IF))
LogPrintf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString());
}
-#endif
}
freeifaddrs(myaddrs);
}
@@ -1757,10 +1764,8 @@ void StartNode(boost::thread_group& threadGroup)
else
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "dnsseed", &ThreadDNSAddressSeed));
-#ifdef USE_UPNP
// Map ports with UPnP
- MapPort(GetBoolArg("-upnp", USE_UPNP));
-#endif
+ MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
// Send and receive from sockets, accept connections
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "net", &ThreadSocketHandler));
@@ -1794,19 +1799,18 @@ bool StopNode()
class CNetCleanup
{
public:
- CNetCleanup()
- {
- }
+ CNetCleanup() {}
+
~CNetCleanup()
{
// Close sockets
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->hSocket != INVALID_SOCKET)
- closesocket(pnode->hSocket);
- BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
- if (hListenSocket != INVALID_SOCKET)
- if (closesocket(hListenSocket) == SOCKET_ERROR)
- LogPrintf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
+ CloseSocket(pnode->hSocket);
+ BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
+ if (hListenSocket.socket != INVALID_SOCKET)
+ if (!CloseSocket(hListenSocket.socket))
+ LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
// clean up some globals (to help leak detection)
BOOST_FOREACH(CNode *pnode, vNodes)
@@ -1815,6 +1819,7 @@ public:
delete pnode;
vNodes.clear();
vNodesDisconnected.clear();
+ vhListenSocket.clear();
delete semOutbound;
semOutbound = NULL;
delete pnodeLocalHost;
@@ -1834,17 +1839,17 @@ instance_of_cnetcleanup;
-void RelayTransaction(const CTransaction& tx, const uint256& hash)
+void RelayTransaction(const CTransaction& tx)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000);
ss << tx;
- RelayTransaction(tx, hash, ss);
+ RelayTransaction(tx, ss);
}
-void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss)
+void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
{
- CInv inv(MSG_TX, hash);
+ CInv inv(MSG_TX, tx.GetHash());
{
LOCK(cs_mapRelay);
// Expire old relay messages
@@ -1866,7 +1871,7 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
LOCK(pnode->cs_filter);
if (pnode->pfilter)
{
- if (pnode->pfilter->IsRelevantAndUpdate(tx, hash))
+ if (pnode->pfilter->IsRelevantAndUpdate(tx))
pnode->PushInventory(inv);
} else
pnode->PushInventory(inv);
@@ -1945,7 +1950,7 @@ bool CAddrDB::Write(const CAddrMan& addr)
{
// Generate random temporary filename
unsigned short randv = 0;
- RAND_bytes((unsigned char *)&randv, sizeof(randv));
+ GetRandBytes((unsigned char*)&randv, sizeof(randv));
std::string tmpfn = strprintf("peers.dat.%04x", randv);
// serialize addresses, checksum data up to that point, then append csum
@@ -1960,21 +1965,21 @@ bool CAddrDB::Write(const CAddrMan& addr)
FILE *file = fopen(pathTmp.string().c_str(), "wb");
CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION);
if (!fileout)
- return error("CAddrman::Write() : open failed");
+ return error("%s : Failed to open file %s", __func__, pathTmp.string());
// Write and commit header, data
try {
fileout << ssPeers;
}
catch (std::exception &e) {
- return error("CAddrman::Write() : I/O error");
+ return error("%s : Serialize or I/O error - %s", __func__, e.what());
}
FileCommit(fileout);
fileout.fclose();
// replace existing peers.dat, if any, with new peers.dat.XXXX
if (!RenameOver(pathTmp, pathAddr))
- return error("CAddrman::Write() : Rename-into-place failed");
+ return error("%s : Rename-into-place failed", __func__);
return true;
}
@@ -1985,13 +1990,14 @@ bool CAddrDB::Read(CAddrMan& addr)
FILE *file = fopen(pathAddr.string().c_str(), "rb");
CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION);
if (!filein)
- return error("CAddrman::Read() : open failed");
+ return error("%s : Failed to open file %s", __func__, pathAddr.string());
// use file size to size memory buffer
int fileSize = boost::filesystem::file_size(pathAddr);
int dataSize = fileSize - sizeof(uint256);
// Don't try to resize to a negative number if file is small
- if ( dataSize < 0 ) dataSize = 0;
+ if (dataSize < 0)
+ dataSize = 0;
vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
@@ -2002,7 +2008,7 @@ bool CAddrDB::Read(CAddrMan& addr)
filein >> hashIn;
}
catch (std::exception &e) {
- return error("CAddrman::Read() 2 : I/O error or stream data corrupted");
+ return error("%s : Deserialize or I/O error - %s", __func__, e.what());
}
filein.fclose();
@@ -2011,7 +2017,7 @@ bool CAddrDB::Read(CAddrMan& addr)
// verify stored checksum matches input data
uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
if (hashIn != hashTmp)
- return error("CAddrman::Read() : checksum mismatch; data corrupted");
+ return error("%s : Checksum mismatch, data corrupted", __func__);
unsigned char pchMsgTmp[4];
try {
@@ -2020,13 +2026,13 @@ bool CAddrDB::Read(CAddrMan& addr)
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
- return error("CAddrman::Read() : invalid network magic number");
+ return error("%s : Invalid network magic number", __func__);
// de-serialize address data into one CAddrMan object
ssPeers >> addr;
}
catch (std::exception &e) {
- return error("CAddrman::Read() : I/O error or stream data corrupted");
+ return error("%s : Deserialize or I/O error - %s", __func__, e.what());
}
return true;