|
|
|
@ -45,12 +45,14 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
@@ -45,12 +45,14 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
|
|
|
|
|
bool fClient = false; |
|
|
|
|
static bool fUseUPnP = false; |
|
|
|
|
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); |
|
|
|
|
CCriticalSection cs_mapLocalHost; |
|
|
|
|
map<CNetAddr, int> mapLocalHost; |
|
|
|
|
static CCriticalSection cs_mapLocalHost; |
|
|
|
|
static map<CService, int> mapLocalHost; |
|
|
|
|
static bool vfReachable[NET_MAX] = {}; |
|
|
|
|
static bool vfLimited[NET_MAX] = {}; |
|
|
|
|
static CNode* pnodeLocalHost = NULL; |
|
|
|
|
uint64 nLocalHostNonce = 0; |
|
|
|
|
array<int, THREAD_MAX> vnThreadsRunning; |
|
|
|
|
static SOCKET hListenSocket = INVALID_SOCKET; |
|
|
|
|
static std::vector<SOCKET> vhListenSocket; |
|
|
|
|
CAddrMan addrman; |
|
|
|
|
|
|
|
|
|
vector<CNode*> vNodes; |
|
|
|
@ -91,7 +93,7 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
@@ -91,7 +93,7 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// find 'best' local address for a particular peer
|
|
|
|
|
bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer) |
|
|
|
|
bool GetLocal(CService& addr, const CNetAddr *paddrPeer) |
|
|
|
|
{ |
|
|
|
|
if (fUseProxy || mapArgs.count("-connect") || fNoListen) |
|
|
|
|
return false; |
|
|
|
@ -100,7 +102,7 @@ bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
@@ -100,7 +102,7 @@ bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
|
|
|
|
|
int nBestReachability = -1; |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_mapLocalHost); |
|
|
|
|
for (map<CNetAddr, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) |
|
|
|
|
for (map<CService, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) |
|
|
|
|
{ |
|
|
|
|
int nCount = (*it).second; |
|
|
|
|
int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); |
|
|
|
@ -119,11 +121,10 @@ bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
@@ -119,11 +121,10 @@ bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
|
|
|
|
|
CAddress GetLocalAddress(const CNetAddr *paddrPeer) |
|
|
|
|
{ |
|
|
|
|
CAddress ret(CService("0.0.0.0",0),0); |
|
|
|
|
CNetAddr addr; |
|
|
|
|
CService addr; |
|
|
|
|
if (GetLocal(addr, paddrPeer)) |
|
|
|
|
{ |
|
|
|
|
ret.SetIP(addr); |
|
|
|
|
ret.SetPort(GetListenPort()); |
|
|
|
|
ret = CAddress(addr); |
|
|
|
|
ret.nServices = nLocalServices; |
|
|
|
|
ret.nTime = GetAdjustedTime(); |
|
|
|
|
} |
|
|
|
@ -191,7 +192,7 @@ void static AdvertizeLocal()
@@ -191,7 +192,7 @@ void static AdvertizeLocal()
|
|
|
|
|
if (pnode->fSuccessfullyConnected) |
|
|
|
|
{ |
|
|
|
|
CAddress addrLocal = GetLocalAddress(&pnode->addr); |
|
|
|
|
if (addrLocal.IsRoutable() && (CNetAddr)addrLocal != (CNetAddr)pnode->addrLocal) |
|
|
|
|
if (addrLocal.IsRoutable() && (CService)addrLocal != (CService)pnode->addrLocal) |
|
|
|
|
{ |
|
|
|
|
pnode->PushAddress(addrLocal); |
|
|
|
|
pnode->addrLocal = addrLocal; |
|
|
|
@ -201,7 +202,7 @@ void static AdvertizeLocal()
@@ -201,7 +202,7 @@ void static AdvertizeLocal()
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// learn a new local address
|
|
|
|
|
bool AddLocal(const CNetAddr& addr, int nScore) |
|
|
|
|
bool AddLocal(const CService& addr, int nScore) |
|
|
|
|
{ |
|
|
|
|
if (!addr.IsRoutable()) |
|
|
|
|
return false; |
|
|
|
@ -211,6 +212,9 @@ bool AddLocal(const CNetAddr& addr, int nScore)
@@ -211,6 +212,9 @@ bool AddLocal(const CNetAddr& addr, int nScore)
|
|
|
|
|
{ |
|
|
|
|
LOCK(cs_mapLocalHost); |
|
|
|
|
mapLocalHost[addr] = std::max(nScore, mapLocalHost[addr]) + (mapLocalHost.count(addr) ? 1 : 0); |
|
|
|
|
enum Network net = addr.GetNetwork(); |
|
|
|
|
vfReachable[net] = true; |
|
|
|
|
if (net == NET_IPV6) vfReachable[NET_IPV4] = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
AdvertizeLocal(); |
|
|
|
@ -218,8 +222,28 @@ bool AddLocal(const CNetAddr& addr, int nScore)
@@ -218,8 +222,28 @@ bool AddLocal(const CNetAddr& addr, int nScore)
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// vote for a local address
|
|
|
|
|
bool SeenLocal(const CNetAddr& addr) |
|
|
|
|
bool AddLocal(const CNetAddr& addr, int nScore, int port) |
|
|
|
|
{ |
|
|
|
|
if (port == -1) |
|
|
|
|
port = GetListenPort(); |
|
|
|
|
return AddLocal(CService(addr, port), nScore); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Make a particular network entirely off-limits (no automatic connects to it) */ |
|
|
|
|
void SetLimited(enum Network net, bool fLimited) |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_mapLocalHost); |
|
|
|
|
vfLimited[net] = fLimited; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool IsLimited(const CNetAddr& addr) |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_mapLocalHost); |
|
|
|
|
return vfLimited[addr.GetNetwork()]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** vote for a local address */ |
|
|
|
|
bool SeenLocal(const CService& addr) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_mapLocalHost); |
|
|
|
@ -233,13 +257,20 @@ bool SeenLocal(const CNetAddr& addr)
@@ -233,13 +257,20 @@ bool SeenLocal(const CNetAddr& addr)
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// check whether a given address is potentially local
|
|
|
|
|
bool IsLocal(const CNetAddr& addr) |
|
|
|
|
/** check whether a given address is potentially local */ |
|
|
|
|
bool IsLocal(const CService& addr) |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_mapLocalHost); |
|
|
|
|
return mapLocalHost.count(addr) > 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 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]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) |
|
|
|
|
{ |
|
|
|
@ -675,9 +706,10 @@ void ThreadSocketHandler2(void* parg)
@@ -675,9 +706,10 @@ void ThreadSocketHandler2(void* parg)
|
|
|
|
|
FD_ZERO(&fdsetError); |
|
|
|
|
SOCKET hSocketMax = 0; |
|
|
|
|
|
|
|
|
|
if(hListenSocket != INVALID_SOCKET) |
|
|
|
|
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) { |
|
|
|
|
FD_SET(hListenSocket, &fdsetRecv); |
|
|
|
|
hSocketMax = max(hSocketMax, hListenSocket); |
|
|
|
|
hSocketMax = max(hSocketMax, hListenSocket); |
|
|
|
|
} |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_vNodes); |
|
|
|
|
BOOST_FOREACH(CNode* pnode, vNodes) |
|
|
|
@ -718,16 +750,22 @@ void ThreadSocketHandler2(void* parg)
@@ -718,16 +750,22 @@ void ThreadSocketHandler2(void* parg)
|
|
|
|
|
//
|
|
|
|
|
// Accept new connections
|
|
|
|
|
//
|
|
|
|
|
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) |
|
|
|
|
if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv)) |
|
|
|
|
{ |
|
|
|
|
struct sockaddr_in sockaddr; |
|
|
|
|
#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 (hSocket != INVALID_SOCKET) |
|
|
|
|
addr = CAddress(sockaddr); |
|
|
|
|
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) |
|
|
|
|
printf("warning: unknown socket family\n"); |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
LOCK(cs_vNodes); |
|
|
|
@ -1380,11 +1418,14 @@ void ThreadOpenConnections2(void* parg)
@@ -1380,11 +1418,14 @@ void ThreadOpenConnections2(void* parg)
|
|
|
|
|
CAddress addr = addrman.Select(10 + min(nOutbound,8)*10); |
|
|
|
|
|
|
|
|
|
// if we selected an invalid address, restart
|
|
|
|
|
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) |
|
|
|
|
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
nTries++; |
|
|
|
|
|
|
|
|
|
if (IsLimited(addr)) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
// only consider very recently tried nodes after 30 failed attempts
|
|
|
|
|
if (nANow - addr.nLastTry < 600 && nTries < 30) |
|
|
|
|
continue; |
|
|
|
@ -1613,7 +1654,7 @@ void ThreadMessageHandler2(void* parg)
@@ -1613,7 +1654,7 @@ void ThreadMessageHandler2(void* parg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool BindListenPort(string& strError) |
|
|
|
|
bool BindListenPort(const CService &addrBind, string& strError) |
|
|
|
|
{ |
|
|
|
|
strError = ""; |
|
|
|
|
int nOne = 1; |
|
|
|
@ -1631,7 +1672,20 @@ bool BindListenPort(string& strError)
@@ -1631,7 +1672,20 @@ bool BindListenPort(string& strError)
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// Create socket for listening for incoming connections
|
|
|
|
|
hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
|
|
|
|
#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().c_str()); |
|
|
|
|
printf("%s\n", strError.c_str()); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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()); |
|
|
|
@ -1650,6 +1704,7 @@ bool BindListenPort(string& strError)
@@ -1650,6 +1704,7 @@ bool BindListenPort(string& strError)
|
|
|
|
|
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN32 |
|
|
|
|
// Set to nonblocking, incoming connections will also inherit this
|
|
|
|
|
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) |
|
|
|
@ -1662,24 +1717,33 @@ bool BindListenPort(string& strError)
@@ -1662,24 +1717,33 @@ bool BindListenPort(string& strError)
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// The sockaddr_in structure specifies the address family,
|
|
|
|
|
// IP address, and port for the socket that is being bound
|
|
|
|
|
struct sockaddr_in sockaddr; |
|
|
|
|
memset(&sockaddr, 0, sizeof(sockaddr)); |
|
|
|
|
sockaddr.sin_family = AF_INET; |
|
|
|
|
sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
|
|
|
|
|
sockaddr.sin_port = htons(GetListenPort()); |
|
|
|
|
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) |
|
|
|
|
#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()) { |
|
|
|
|
#ifdef IPV6_V6ONLY |
|
|
|
|
setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)); |
|
|
|
|
#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)); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) |
|
|
|
|
{ |
|
|
|
|
int nErr = WSAGetLastError(); |
|
|
|
|
if (nErr == WSAEADDRINUSE) |
|
|
|
|
strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), ntohs(sockaddr.sin_port)); |
|
|
|
|
strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin is probably already running."), addrBind.ToString().c_str()); |
|
|
|
|
else |
|
|
|
|
strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr); |
|
|
|
|
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr)); |
|
|
|
|
printf("%s\n", strError.c_str()); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
printf("Bound to port %d\n", ntohs(sockaddr.sin_port)); |
|
|
|
|
printf("Bound to %s\n", addrBind.ToString().c_str()); |
|
|
|
|
|
|
|
|
|
// Listen for incoming connections
|
|
|
|
|
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) |
|
|
|
@ -1689,6 +1753,11 @@ bool BindListenPort(string& strError)
@@ -1689,6 +1753,11 @@ bool BindListenPort(string& strError)
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vhListenSocket.push_back(hListenSocket); |
|
|
|
|
|
|
|
|
|
if (addrBind.IsRoutable() && GetBoolArg("-discover", true)) |
|
|
|
|
AddLocal(addrBind, LOCAL_BIND); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1722,28 +1791,22 @@ void static Discover()
@@ -1722,28 +1791,22 @@ void static Discover()
|
|
|
|
|
if ((ifa->ifa_flags & IFF_UP) == 0) continue; |
|
|
|
|
if (strcmp(ifa->ifa_name, "lo") == 0) continue; |
|
|
|
|
if (strcmp(ifa->ifa_name, "lo0") == 0) continue; |
|
|
|
|
char pszIP[100]; |
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET) |
|
|
|
|
{ |
|
|
|
|
struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr); |
|
|
|
|
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL) |
|
|
|
|
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP); |
|
|
|
|
|
|
|
|
|
// Take the first IP that isn't loopback 127.x.x.x
|
|
|
|
|
CNetAddr addr(s4->sin_addr); |
|
|
|
|
AddLocal(addr, LOCAL_IF); |
|
|
|
|
if (AddLocal(addr, LOCAL_IF)) |
|
|
|
|
printf("ipv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); |
|
|
|
|
} |
|
|
|
|
#ifdef USE_IPV6 |
|
|
|
|
else if (ifa->ifa_addr->sa_family == AF_INET6) |
|
|
|
|
{ |
|
|
|
|
struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr); |
|
|
|
|
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL) |
|
|
|
|
printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP); |
|
|
|
|
|
|
|
|
|
#ifdef USE_IPV6 |
|
|
|
|
CNetAddr addr(s6->sin6_addr); |
|
|
|
|
AddLocal(addr, LOCAL_IF); |
|
|
|
|
#endif |
|
|
|
|
if (AddLocal(addr, LOCAL_IF)) |
|
|
|
|
printf("ipv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
freeifaddrs(myaddrs); |
|
|
|
|
} |
|
|
|
@ -1866,9 +1929,10 @@ public:
@@ -1866,9 +1929,10 @@ public:
|
|
|
|
|
BOOST_FOREACH(CNode* pnode, vNodes) |
|
|
|
|
if (pnode->hSocket != INVALID_SOCKET) |
|
|
|
|
closesocket(pnode->hSocket); |
|
|
|
|
if (hListenSocket != INVALID_SOCKET) |
|
|
|
|
if (closesocket(hListenSocket) == SOCKET_ERROR) |
|
|
|
|
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); |
|
|
|
|
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) |
|
|
|
|
if (hListenSocket != INVALID_SOCKET) |
|
|
|
|
if (closesocket(hListenSocket) == SOCKET_ERROR) |
|
|
|
|
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); |
|
|
|
|
|
|
|
|
|
#ifdef WIN32 |
|
|
|
|
// Shutdown Windows Sockets
|
|
|
|
|