@@ -45,7 +45,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest = NU
45
45
bool fClient = false ;
46
46
static bool fUseUPnP = false ;
47
47
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;
49
50
static CNode* pnodeLocalHost = NULL ;
50
51
uint64 nLocalHostNonce = 0 ;
51
52
array<int , THREAD_MAX> vnThreadsRunning;
@@ -92,7 +93,45 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
92
93
PushMessage (" getblocks" , CBlockLocator (pindexBegin), hashEnd);
93
94
}
94
95
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
+ }
95
120
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
+ }
96
135
97
136
bool RecvLine (SOCKET hSocket, string& strLine)
98
137
{
@@ -145,6 +184,64 @@ bool RecvLine(SOCKET hSocket, string& strLine)
145
184
}
146
185
}
147
186
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
+ }
148
245
149
246
150
247
bool GetMyExternalIP2 (const CService& addrConnect, const char * pszGet, const char * pszKeyword, CNetAddr& ipRet)
@@ -258,33 +355,11 @@ bool GetMyExternalIP(CNetAddr& ipRet)
258
355
259
356
void ThreadGetMyExternalIP (void * parg)
260
357
{
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;
273
359
if (GetMyExternalIP (addrLocalHost))
274
360
{
275
361
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);
288
363
}
289
364
}
290
365
@@ -337,7 +412,7 @@ CNode* FindNode(const CService& addr)
337
412
CNode* ConnectNode (CAddress addrConnect, const char *pszDest, int64 nTimeout)
338
413
{
339
414
if (pszDest == NULL ) {
340
- if ((CNetAddr) addrConnect == (CNetAddr)addrLocalHost )
415
+ if (IsLocal ( addrConnect) )
341
416
return NULL ;
342
417
343
418
// Look for an existing connection
@@ -426,7 +501,7 @@ void CNode::PushVersion()
426
501
// / when NTP implemented, change to just nTime = GetAdjustedTime()
427
502
int64 nTime = (fInbound ? GetAdjustedTime () : GetTime ());
428
503
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 );
430
505
RAND_bytes ((unsigned char *)&nLocalHostNonce, sizeof (nLocalHostNonce));
431
506
PushMessage (" version" , PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
432
507
nLocalHostNonce, FormatSubVersion (CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
@@ -898,24 +973,19 @@ void ThreadMapPort2(void* parg)
898
973
r = UPNP_GetValidIGD (devlist, &urls, &data, lanaddr, sizeof (lanaddr));
899
974
if (r == 1 )
900
975
{
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
902
981
{
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 ])
908
983
{
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);
918
986
}
987
+ else
988
+ printf (" UPnP: GetExternalIPAddress failed.\n " );
919
989
}
920
990
921
991
string strDesc = " Bitcoin " + FormatFullVersion ();
@@ -1318,7 +1388,7 @@ void ThreadOpenConnections2(void* parg)
1318
1388
CAddress addr = addrman.Select (10 + min (nOutbound,8 )*10 );
1319
1389
1320
1390
// 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) )
1322
1392
break ;
1323
1393
1324
1394
nTries++;
@@ -1436,8 +1506,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, const char *strDest, boo
1436
1506
if (fShutdown )
1437
1507
return false ;
1438
1508
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) ||
1441
1511
FindNode (addrConnect.ToStringIPPort ().c_str ()))
1442
1512
return false ;
1443
1513
if (strDest && FindNode (strDest))
@@ -1550,7 +1620,6 @@ bool BindListenPort(string& strError)
1550
1620
{
1551
1621
strError = " " ;
1552
1622
int nOne = 1 ;
1553
- addrLocalHost.SetPort (GetListenPort ());
1554
1623
1555
1624
#ifdef WIN32
1556
1625
// Initialize Windows Sockets
@@ -1649,11 +1718,7 @@ void StartNode(void* parg)
1649
1718
{
1650
1719
BOOST_FOREACH (const CNetAddr &addr, vaddr)
1651
1720
{
1652
- if (!addr.IsLocal ())
1653
- {
1654
- addrLocalHost.SetIP (addr);
1655
- break ;
1656
- }
1721
+ AddLocal (addr, LOCAL_IF);
1657
1722
}
1658
1723
}
1659
1724
}
@@ -1676,32 +1741,26 @@ void StartNode(void* parg)
1676
1741
printf (" ipv4 %s: %s\n " , ifa->ifa_name , pszIP);
1677
1742
1678
1743
// 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);
1685
1746
}
1686
1747
else if (ifa->ifa_addr ->sa_family == AF_INET6)
1687
1748
{
1688
1749
struct sockaddr_in6 * s6 = (struct sockaddr_in6 *)(ifa->ifa_addr );
1689
1750
if (inet_ntop (ifa->ifa_addr ->sa_family , (void *)&(s6->sin6_addr ), pszIP, sizeof (pszIP)) != NULL )
1690
1751
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
1691
1757
}
1692
1758
}
1693
1759
freeifaddrs (myaddrs);
1694
1760
}
1695
1761
#endif
1696
- printf (" addrLocalHost = %s\n " , addrLocalHost.ToString ().c_str ());
1697
1762
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 )
1705
1764
{
1706
1765
CreateThread (ThreadGetMyExternalIP, NULL );
1707
1766
}
0 commit comments