diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2012-02-12 13:45:24 +0100 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2012-05-04 16:12:23 +0200 |
commit | 39857190dee3ed296112cfcfd79b0a375143b6c6 (patch) | |
tree | c78b110e9731a9b495074e3889b5767ab8d40e8b /src/net.cpp | |
parent | 478b01d9a797f3ea41cca141992b161867a5996d (diff) |
Support for multiple local addresses
Diffstat (limited to 'src/net.cpp')
-rw-r--r-- | src/net.cpp | 189 |
1 files changed, 124 insertions, 65 deletions
diff --git a/src/net.cpp b/src/net.cpp index 0483206969..0a78bc445f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -45,7 +45,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest = NU bool fClient = false; static bool fUseUPnP = false; uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); -CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices); +CCriticalSection cs_mapLocalHost; +map<CNetAddr, int> mapLocalHost; static CNode* pnodeLocalHost = NULL; uint64 nLocalHostNonce = 0; array<int, THREAD_MAX> vnThreadsRunning; @@ -92,7 +93,45 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); } +// find 'best' local address for a particular peer +bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer) +{ + if (fUseProxy || mapArgs.count("-connect") || fNoListen) + return false; + + int nBestCount = -1; + int nBestReachability = -1; + { + LOCK(cs_mapLocalHost); + for (map<CNetAddr, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) + { + int nCount = (*it).second; + int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); + if (nReachability > nBestReachability || (nReachability == nBestReachability && nCount > nBestCount)) + { + addr = (*it).first; + nBestReachability = nReachability; + nBestCount = nCount; + } + } + } + return nBestCount >= 0; +} +// get best local address for a particular peer as a CAddress +CAddress GetLocalAddress(const CNetAddr *paddrPeer) +{ + CAddress ret(CService("0.0.0.0",0),0); + CNetAddr addr; + if (GetLocal(addr, paddrPeer)) + { + ret.SetIP(addr); + ret.SetPort(GetListenPort()); + ret.nServices = nLocalServices; + ret.nTime = GetAdjustedTime(); + } + return ret; +} bool RecvLine(SOCKET hSocket, string& strLine) { @@ -145,6 +184,64 @@ bool RecvLine(SOCKET hSocket, string& strLine) } } +// used when scores of local addresses may have changed +// pushes better local address to peers +void static AdvertizeLocal() +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + if (pnode->fSuccessfullyConnected) + { + CAddress addrLocal = GetLocalAddress(&pnode->addr); + if (addrLocal.IsRoutable() && (CNetAddr)addrLocal != (CNetAddr)pnode->addrLocal) + { + pnode->PushAddress(addrLocal); + pnode->addrLocal = addrLocal; + } + } + } +} + +// learn a new local address +bool AddLocal(const CNetAddr& addr, int nScore) +{ + if (!addr.IsRoutable()) + return false; + + printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore); + + { + LOCK(cs_mapLocalHost); + mapLocalHost[addr] = std::max(nScore, mapLocalHost[addr]) + (mapLocalHost.count(addr) ? 1 : 0); + } + + AdvertizeLocal(); + + return true; +} + +// vote for a local address +bool SeenLocal(const CNetAddr& addr) +{ + { + LOCK(cs_mapLocalHost); + if (mapLocalHost.count(addr) == 0) + return false; + mapLocalHost[addr]++; + } + + AdvertizeLocal(); + + return true; +} + +// check whether a given address is potentially local +bool IsLocal(const CNetAddr& addr) +{ + LOCK(cs_mapLocalHost); + return mapLocalHost.count(addr) > 0; +} bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) @@ -258,33 +355,11 @@ bool GetMyExternalIP(CNetAddr& ipRet) void ThreadGetMyExternalIP(void* parg) { - // Wait for IRC to get it first - if (GetBoolArg("-irc", false)) - { - for (int i = 0; i < 2 * 60; i++) - { - Sleep(1000); - if (fGotExternalIP || fShutdown) - return; - } - } - - // Fallback in case IRC fails to get it + CNetAddr addrLocalHost; if (GetMyExternalIP(addrLocalHost)) { printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str()); - if (addrLocalHost.IsRoutable()) - { - // If we already connected to a few before we had our IP, go back and addr them. - // setAddrKnown automatically filters any duplicate sends. - CAddress addr(addrLocalHost); - addr.nTime = GetAdjustedTime(); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - pnode->PushAddress(addr); - } - } + AddLocal(addrLocalHost, LOCAL_HTTP); } } @@ -337,7 +412,7 @@ CNode* FindNode(const CService& addr) CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout) { if (pszDest == NULL) { - if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost) + if (IsLocal(addrConnect)) return NULL; // Look for an existing connection @@ -426,7 +501,7 @@ void CNode::PushVersion() /// when NTP implemented, change to just nTime = GetAdjustedTime() int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr); - CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress(CService("0.0.0.0",0)) : addrLocalHost); + CAddress addrMe = GetLocalAddress(&addr); RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight); @@ -898,24 +973,19 @@ void ThreadMapPort2(void* parg) r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); if (r == 1) { - if (!addrLocalHost.IsRoutable()) + char externalIPAddress[40]; + r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); + if(r != UPNPCOMMAND_SUCCESS) + printf("UPnP: GetExternalIPAddress() returned %d\n", r); + else { - char externalIPAddress[40]; - r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); - if(r != UPNPCOMMAND_SUCCESS) - printf("UPnP: GetExternalIPAddress() returned %d\n", r); - else + if(externalIPAddress[0]) { - if(externalIPAddress[0]) - { - printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress); - CAddress addrExternalFromUPnP(CService(externalIPAddress, 0), nLocalServices); - if (addrExternalFromUPnP.IsRoutable()) - addrLocalHost = addrExternalFromUPnP; - } - else - printf("UPnP: GetExternalIPAddress failed.\n"); + printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress); + AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP); } + else + printf("UPnP: GetExternalIPAddress failed.\n"); } string strDesc = "Bitcoin " + FormatFullVersion(); @@ -1318,7 +1388,7 @@ 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()) || addr == addrLocalHost) + if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) break; nTries++; @@ -1436,8 +1506,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest, boo if (fShutdown) return false; if (!strDest) - if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() || - FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) || + if (IsLocal(addrConnect) || + FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) || FindNode(addrConnect.ToStringIPPort().c_str())) return false; if (strDest && FindNode(strDest)) @@ -1550,7 +1620,6 @@ bool BindListenPort(string& strError) { strError = ""; int nOne = 1; - addrLocalHost.SetPort(GetListenPort()); #ifdef WIN32 // Initialize Windows Sockets @@ -1649,11 +1718,7 @@ void StartNode(void* parg) { BOOST_FOREACH (const CNetAddr &addr, vaddr) { - if (!addr.IsLocal()) - { - addrLocalHost.SetIP(addr); - break; - } + AddLocal(addr, LOCAL_IF); } } } @@ -1676,32 +1741,26 @@ void StartNode(void* parg) printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP); // Take the first IP that isn't loopback 127.x.x.x - CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices); - if (addr.IsValid() && !addr.IsLocal()) - { - addrLocalHost = addr; - break; - } + CNetAddr addr(s4->sin_addr); + AddLocal(addr, LOCAL_IF); } 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 } } freeifaddrs(myaddrs); } #endif - printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); - if (fUseProxy || mapArgs.count("-connect") || fNoListen) - { - // Proxies can't take incoming connections - addrLocalHost.SetIP(CNetAddr("0.0.0.0")); - printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); - } - else + if (!fUseProxy && !mapArgs.count("-connect") && !fNoListen) { CreateThread(ThreadGetMyExternalIP, NULL); } |