Skip to content

Commit 3985719

Browse files
committed
Support for multiple local addresses
1 parent 478b01d commit 3985719

File tree

8 files changed

+187
-88
lines changed

8 files changed

+187
-88
lines changed

src/irc.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ using namespace std;
1212
using namespace boost;
1313

1414
int nGotIRCAddresses = 0;
15-
bool fGotExternalIP = false;
1615

1716
void ThreadIRCSeed2(void* parg);
1817

@@ -216,7 +215,6 @@ void ThreadIRCSeed2(void* parg)
216215
printf("ThreadIRCSeed started\n");
217216
int nErrorWait = 10;
218217
int nRetryWait = 10;
219-
bool fNameInUse = false;
220218

221219
while (!fShutdown)
222220
{
@@ -248,9 +246,10 @@ void ThreadIRCSeed2(void* parg)
248246
return;
249247
}
250248

249+
CNetAddr addrLocal;
251250
string strMyName;
252-
if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
253-
strMyName = EncodeAddress(addrLocalHost);
251+
if (GetLocal(addrLocal, &addrConnect))
252+
strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
254253
else
255254
strMyName = strprintf("x%u", GetRand(1000000000));
256255

@@ -265,7 +264,6 @@ void ThreadIRCSeed2(void* parg)
265264
if (nRet == 2)
266265
{
267266
printf("IRC name already in use\n");
268-
fNameInUse = true;
269267
Wait(10);
270268
continue;
271269
}
@@ -285,9 +283,8 @@ void ThreadIRCSeed2(void* parg)
285283
if (!fUseProxy && addrFromIRC.IsRoutable())
286284
{
287285
// IRC lets you to re-nick
288-
fGotExternalIP = true;
289-
addrLocalHost.SetIP(addrFromIRC);
290-
strMyName = EncodeAddress(addrLocalHost);
286+
AddLocal(addrFromIRC, LOCAL_IRC);
287+
strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
291288
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
292289
}
293290
}

src/irc.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@
88
void ThreadIRCSeed(void* parg);
99

1010
extern int nGotIRCAddresses;
11-
extern bool fGotExternalIP;
1211

1312
#endif

src/main.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,6 +2232,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
22322232
if (!vRecv.empty())
22332233
vRecv >> pfrom->nStartingHeight;
22342234

2235+
if (pfrom->fInbound && addrMe.IsRoutable())
2236+
{
2237+
pfrom->addrLocal = addrMe;
2238+
SeenLocal(addrMe);
2239+
}
2240+
22352241
// Disconnect if we connected to ourself
22362242
if (nNonce == nLocalHostNonce && nNonce > 1)
22372243
{
@@ -2255,12 +2261,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
22552261
if (!pfrom->fInbound)
22562262
{
22572263
// Advertise our address
2258-
if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable() &&
2259-
!IsInitialBlockDownload())
2264+
if (!fNoListen && !fUseProxy && !IsInitialBlockDownload())
22602265
{
2261-
CAddress addr(addrLocalHost);
2262-
addr.nTime = GetAdjustedTime();
2263-
pfrom->PushAddress(addr);
2266+
CAddress addr = GetLocalAddress(&pfrom->addr);
2267+
if (addr.IsRoutable())
2268+
pfrom->PushAddress(addr);
22642269
}
22652270

22662271
// Get recent addresses
@@ -2889,11 +2894,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
28892894
pnode->setAddrKnown.clear();
28902895

28912896
// Rebroadcast our address
2892-
if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable())
2897+
if (!fNoListen && !fUseProxy)
28932898
{
2894-
CAddress addr(addrLocalHost);
2895-
addr.nTime = GetAdjustedTime();
2896-
pnode->PushAddress(addr);
2899+
CAddress addr = GetLocalAddress(&pnode->addr);
2900+
if (addr.IsRoutable())
2901+
pnode->PushAddress(addr);
28972902
}
28982903
}
28992904
}

src/net.cpp

Lines changed: 124 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest = NU
4545
bool fClient = false;
4646
static bool fUseUPnP = false;
4747
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
48-
CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices);
48+
CCriticalSection cs_mapLocalHost;
49+
map<CNetAddr, int> mapLocalHost;
4950
static CNode* pnodeLocalHost = NULL;
5051
uint64 nLocalHostNonce = 0;
5152
array<int, THREAD_MAX> vnThreadsRunning;
@@ -92,7 +93,45 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
9293
PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
9394
}
9495

96+
// find 'best' local address for a particular peer
97+
bool GetLocal(CNetAddr& addr, const CNetAddr *paddrPeer)
98+
{
99+
if (fUseProxy || mapArgs.count("-connect") || fNoListen)
100+
return false;
101+
102+
int nBestCount = -1;
103+
int nBestReachability = -1;
104+
{
105+
LOCK(cs_mapLocalHost);
106+
for (map<CNetAddr, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++)
107+
{
108+
int nCount = (*it).second;
109+
int nReachability = (*it).first.GetReachabilityFrom(paddrPeer);
110+
if (nReachability > nBestReachability || (nReachability == nBestReachability && nCount > nBestCount))
111+
{
112+
addr = (*it).first;
113+
nBestReachability = nReachability;
114+
nBestCount = nCount;
115+
}
116+
}
117+
}
118+
return nBestCount >= 0;
119+
}
95120

121+
// get best local address for a particular peer as a CAddress
122+
CAddress GetLocalAddress(const CNetAddr *paddrPeer)
123+
{
124+
CAddress ret(CService("0.0.0.0",0),0);
125+
CNetAddr addr;
126+
if (GetLocal(addr, paddrPeer))
127+
{
128+
ret.SetIP(addr);
129+
ret.SetPort(GetListenPort());
130+
ret.nServices = nLocalServices;
131+
ret.nTime = GetAdjustedTime();
132+
}
133+
return ret;
134+
}
96135

97136
bool RecvLine(SOCKET hSocket, string& strLine)
98137
{
@@ -145,6 +184,64 @@ bool RecvLine(SOCKET hSocket, string& strLine)
145184
}
146185
}
147186

187+
// used when scores of local addresses may have changed
188+
// pushes better local address to peers
189+
void static AdvertizeLocal()
190+
{
191+
LOCK(cs_vNodes);
192+
BOOST_FOREACH(CNode* pnode, vNodes)
193+
{
194+
if (pnode->fSuccessfullyConnected)
195+
{
196+
CAddress addrLocal = GetLocalAddress(&pnode->addr);
197+
if (addrLocal.IsRoutable() && (CNetAddr)addrLocal != (CNetAddr)pnode->addrLocal)
198+
{
199+
pnode->PushAddress(addrLocal);
200+
pnode->addrLocal = addrLocal;
201+
}
202+
}
203+
}
204+
}
205+
206+
// learn a new local address
207+
bool AddLocal(const CNetAddr& addr, int nScore)
208+
{
209+
if (!addr.IsRoutable())
210+
return false;
211+
212+
printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore);
213+
214+
{
215+
LOCK(cs_mapLocalHost);
216+
mapLocalHost[addr] = std::max(nScore, mapLocalHost[addr]) + (mapLocalHost.count(addr) ? 1 : 0);
217+
}
218+
219+
AdvertizeLocal();
220+
221+
return true;
222+
}
223+
224+
// vote for a local address
225+
bool SeenLocal(const CNetAddr& addr)
226+
{
227+
{
228+
LOCK(cs_mapLocalHost);
229+
if (mapLocalHost.count(addr) == 0)
230+
return false;
231+
mapLocalHost[addr]++;
232+
}
233+
234+
AdvertizeLocal();
235+
236+
return true;
237+
}
238+
239+
// check whether a given address is potentially local
240+
bool IsLocal(const CNetAddr& addr)
241+
{
242+
LOCK(cs_mapLocalHost);
243+
return mapLocalHost.count(addr) > 0;
244+
}
148245

149246

150247
bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
@@ -258,33 +355,11 @@ bool GetMyExternalIP(CNetAddr& ipRet)
258355

259356
void ThreadGetMyExternalIP(void* parg)
260357
{
261-
// Wait for IRC to get it first
262-
if (GetBoolArg("-irc", false))
263-
{
264-
for (int i = 0; i < 2 * 60; i++)
265-
{
266-
Sleep(1000);
267-
if (fGotExternalIP || fShutdown)
268-
return;
269-
}
270-
}
271-
272-
// Fallback in case IRC fails to get it
358+
CNetAddr addrLocalHost;
273359
if (GetMyExternalIP(addrLocalHost))
274360
{
275361
printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
276-
if (addrLocalHost.IsRoutable())
277-
{
278-
// If we already connected to a few before we had our IP, go back and addr them.
279-
// setAddrKnown automatically filters any duplicate sends.
280-
CAddress addr(addrLocalHost);
281-
addr.nTime = GetAdjustedTime();
282-
{
283-
LOCK(cs_vNodes);
284-
BOOST_FOREACH(CNode* pnode, vNodes)
285-
pnode->PushAddress(addr);
286-
}
287-
}
362+
AddLocal(addrLocalHost, LOCAL_HTTP);
288363
}
289364
}
290365

@@ -337,7 +412,7 @@ CNode* FindNode(const CService& addr)
337412
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout)
338413
{
339414
if (pszDest == NULL) {
340-
if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost)
415+
if (IsLocal(addrConnect))
341416
return NULL;
342417

343418
// Look for an existing connection
@@ -426,7 +501,7 @@ void CNode::PushVersion()
426501
/// when NTP implemented, change to just nTime = GetAdjustedTime()
427502
int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
428503
CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr);
429-
CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress(CService("0.0.0.0",0)) : addrLocalHost);
504+
CAddress addrMe = GetLocalAddress(&addr);
430505
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
431506
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
432507
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
@@ -898,24 +973,19 @@ void ThreadMapPort2(void* parg)
898973
r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
899974
if (r == 1)
900975
{
901-
if (!addrLocalHost.IsRoutable())
976+
char externalIPAddress[40];
977+
r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
978+
if(r != UPNPCOMMAND_SUCCESS)
979+
printf("UPnP: GetExternalIPAddress() returned %d\n", r);
980+
else
902981
{
903-
char externalIPAddress[40];
904-
r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
905-
if(r != UPNPCOMMAND_SUCCESS)
906-
printf("UPnP: GetExternalIPAddress() returned %d\n", r);
907-
else
982+
if(externalIPAddress[0])
908983
{
909-
if(externalIPAddress[0])
910-
{
911-
printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
912-
CAddress addrExternalFromUPnP(CService(externalIPAddress, 0), nLocalServices);
913-
if (addrExternalFromUPnP.IsRoutable())
914-
addrLocalHost = addrExternalFromUPnP;
915-
}
916-
else
917-
printf("UPnP: GetExternalIPAddress failed.\n");
984+
printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
985+
AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP);
918986
}
987+
else
988+
printf("UPnP: GetExternalIPAddress failed.\n");
919989
}
920990

921991
string strDesc = "Bitcoin " + FormatFullVersion();
@@ -1318,7 +1388,7 @@ void ThreadOpenConnections2(void* parg)
13181388
CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
13191389

13201390
// if we selected an invalid address, restart
1321-
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || addr == addrLocalHost)
1391+
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
13221392
break;
13231393

13241394
nTries++;
@@ -1436,8 +1506,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest, boo
14361506
if (fShutdown)
14371507
return false;
14381508
if (!strDest)
1439-
if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
1440-
FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
1509+
if (IsLocal(addrConnect) ||
1510+
FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
14411511
FindNode(addrConnect.ToStringIPPort().c_str()))
14421512
return false;
14431513
if (strDest && FindNode(strDest))
@@ -1550,7 +1620,6 @@ bool BindListenPort(string& strError)
15501620
{
15511621
strError = "";
15521622
int nOne = 1;
1553-
addrLocalHost.SetPort(GetListenPort());
15541623

15551624
#ifdef WIN32
15561625
// Initialize Windows Sockets
@@ -1649,11 +1718,7 @@ void StartNode(void* parg)
16491718
{
16501719
BOOST_FOREACH (const CNetAddr &addr, vaddr)
16511720
{
1652-
if (!addr.IsLocal())
1653-
{
1654-
addrLocalHost.SetIP(addr);
1655-
break;
1656-
}
1721+
AddLocal(addr, LOCAL_IF);
16571722
}
16581723
}
16591724
}
@@ -1676,32 +1741,26 @@ void StartNode(void* parg)
16761741
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
16771742

16781743
// Take the first IP that isn't loopback 127.x.x.x
1679-
CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices);
1680-
if (addr.IsValid() && !addr.IsLocal())
1681-
{
1682-
addrLocalHost = addr;
1683-
break;
1684-
}
1744+
CNetAddr addr(s4->sin_addr);
1745+
AddLocal(addr, LOCAL_IF);
16851746
}
16861747
else if (ifa->ifa_addr->sa_family == AF_INET6)
16871748
{
16881749
struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
16891750
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
16901751
printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
1752+
1753+
#ifdef USE_IPV6
1754+
CNetAddr addr(s6->sin6_addr);
1755+
AddLocal(addr, LOCAL_IF);
1756+
#endif
16911757
}
16921758
}
16931759
freeifaddrs(myaddrs);
16941760
}
16951761
#endif
1696-
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
16971762

1698-
if (fUseProxy || mapArgs.count("-connect") || fNoListen)
1699-
{
1700-
// Proxies can't take incoming connections
1701-
addrLocalHost.SetIP(CNetAddr("0.0.0.0"));
1702-
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
1703-
}
1704-
else
1763+
if (!fUseProxy && !mapArgs.count("-connect") && !fNoListen)
17051764
{
17061765
CreateThread(ThreadGetMyExternalIP, NULL);
17071766
}

0 commit comments

Comments
 (0)