]>
Commit | Line | Data |
---|---|---|
0a61b0df | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
88216419 | 2 | // Copyright (c) 2009-2012 The Bitcoin developers |
0a61b0df | 3 | // Distributed under the MIT/X11 software license, see the accompanying |
4 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. | |
5 | ||
6 | #include "headers.h" | |
f23f9a03 | 7 | #include "irc.h" |
1512d5ce | 8 | #include "db.h" |
40c2614e | 9 | #include "net.h" |
edd309e5 | 10 | #include "init.h" |
fdd7d047 | 11 | #include "strlcpy.h" |
0a61b0df | 12 | |
6853e627 | 13 | #ifdef WIN32 |
013df1cc MC |
14 | #include <string.h> |
15 | #endif | |
16 | ||
8bb5edc1 MC |
17 | #ifdef USE_UPNP |
18 | #include <miniupnpc/miniwget.h> | |
19 | #include <miniupnpc/miniupnpc.h> | |
20 | #include <miniupnpc/upnpcommands.h> | |
21 | #include <miniupnpc/upnperrors.h> | |
22 | #endif | |
23 | ||
223b6f1b WL |
24 | using namespace std; |
25 | using namespace boost; | |
26 | ||
0a61b0df | 27 | static const int MAX_OUTBOUND_CONNECTIONS = 8; |
28 | ||
29 | void ThreadMessageHandler2(void* parg); | |
30 | void ThreadSocketHandler2(void* parg); | |
31 | void ThreadOpenConnections2(void* parg); | |
b24e6e4d | 32 | void ThreadOpenAddedConnections2(void* parg); |
8bb5edc1 MC |
33 | #ifdef USE_UPNP |
34 | void ThreadMapPort2(void* parg); | |
35 | #endif | |
2bc6cece | 36 | void ThreadDNSAddressSeed2(void* parg); |
0a61b0df | 37 | bool OpenNetworkConnection(const CAddress& addrConnect); |
38 | ||
39 | ||
40 | ||
41 | ||
42 | ||
43 | // | |
44 | // Global state variables | |
45 | // | |
46 | bool fClient = false; | |
a6a5bb7c | 47 | bool fAllowDNS = false; |
bde280b9 | 48 | uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); |
67a42f92 | 49 | CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices); |
99860de3 | 50 | static CNode* pnodeLocalHost = NULL; |
bde280b9 | 51 | uint64 nLocalHostNonce = 0; |
0a61b0df | 52 | array<int, 10> vnThreadsRunning; |
99860de3 | 53 | static SOCKET hListenSocket = INVALID_SOCKET; |
0a61b0df | 54 | |
55 | vector<CNode*> vNodes; | |
56 | CCriticalSection cs_vNodes; | |
57 | map<vector<unsigned char>, CAddress> mapAddresses; | |
58 | CCriticalSection cs_mapAddresses; | |
59 | map<CInv, CDataStream> mapRelay; | |
bde280b9 | 60 | deque<pair<int64, CInv> > vRelayExpiration; |
0a61b0df | 61 | CCriticalSection cs_mapRelay; |
bde280b9 | 62 | map<CInv, int64> mapAlreadyAskedFor; |
0a61b0df | 63 | |
0a61b0df | 64 | |
b24e6e4d MC |
65 | set<CNetAddr> setservAddNodeAddresses; |
66 | CCriticalSection cs_setservAddNodeAddresses; | |
67 | ||
0a61b0df | 68 | |
69 | ||
70 | ||
00bcfe0b GA |
71 | unsigned short GetListenPort() |
72 | { | |
73 | return (unsigned short)(GetArg("-port", GetDefaultPort())); | |
74 | } | |
0a61b0df | 75 | |
76 | void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) | |
77 | { | |
78 | // Filter out duplicate requests | |
79 | if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd) | |
80 | return; | |
81 | pindexLastGetBlocksBegin = pindexBegin; | |
82 | hashLastGetBlocksEnd = hashEnd; | |
83 | ||
84 | PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); | |
85 | } | |
86 | ||
87 | ||
88 | ||
89 | ||
90 | ||
67a42f92 | 91 | bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) |
0a61b0df | 92 | { |
93 | SOCKET hSocket; | |
94 | if (!ConnectSocket(addrConnect, hSocket)) | |
95 | return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str()); | |
96 | ||
97 | send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL); | |
98 | ||
99 | string strLine; | |
100 | while (RecvLine(hSocket, strLine)) | |
101 | { | |
222e3de4 | 102 | if (strLine.empty()) // HTTP response is separated from headers by blank line |
0a61b0df | 103 | { |
104 | loop | |
105 | { | |
106 | if (!RecvLine(hSocket, strLine)) | |
107 | { | |
108 | closesocket(hSocket); | |
109 | return false; | |
110 | } | |
222e3de4 | 111 | if (pszKeyword == NULL) |
112 | break; | |
0a61b0df | 113 | if (strLine.find(pszKeyword) != -1) |
114 | { | |
115 | strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword)); | |
116 | break; | |
117 | } | |
118 | } | |
119 | closesocket(hSocket); | |
c891967b | 120 | if (strLine.find("<") != -1) |
0a61b0df | 121 | strLine = strLine.substr(0, strLine.find("<")); |
122 | strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r")); | |
123 | while (strLine.size() > 0 && isspace(strLine[strLine.size()-1])) | |
124 | strLine.resize(strLine.size()-1); | |
67a42f92 | 125 | CService addr(strLine,0,true); |
0a61b0df | 126 | printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); |
67a42f92 | 127 | if (!addr.IsValid() || !addr.IsRoutable()) |
0a61b0df | 128 | return false; |
67a42f92 | 129 | ipRet.SetIP(addr); |
0a61b0df | 130 | return true; |
131 | } | |
132 | } | |
133 | closesocket(hSocket); | |
134 | return error("GetMyExternalIP() : connection closed"); | |
135 | } | |
136 | ||
629e37dd | 137 | // We now get our external IP from the IRC server first and only use this as a backup |
67a42f92 | 138 | bool GetMyExternalIP(CNetAddr& ipRet) |
0a61b0df | 139 | { |
c981d768 | 140 | CService addrConnect; |
0a61b0df | 141 | const char* pszGet; |
142 | const char* pszKeyword; | |
143 | ||
5d1b8f17 | 144 | if (fNoListen||fUseProxy) |
0a61b0df | 145 | return false; |
146 | ||
147 | for (int nLookup = 0; nLookup <= 1; nLookup++) | |
148 | for (int nHost = 1; nHost <= 2; nHost++) | |
149 | { | |
629e37dd | 150 | // We should be phasing out our use of sites like these. If we need |
151 | // replacements, we should ask for volunteers to put this simple | |
152 | // php file on their webserver that prints the client IP: | |
153 | // <?php echo $_SERVER["REMOTE_ADDR"]; ?> | |
0a61b0df | 154 | if (nHost == 1) |
155 | { | |
c981d768 | 156 | addrConnect = CService("91.198.22.70",80); // checkip.dyndns.org |
0a61b0df | 157 | |
158 | if (nLookup == 1) | |
159 | { | |
67a42f92 | 160 | CService addrIP("checkip.dyndns.org", 80, true); |
a6a5bb7c PW |
161 | if (addrIP.IsValid()) |
162 | addrConnect = addrIP; | |
0a61b0df | 163 | } |
164 | ||
683bcb91 | 165 | pszGet = "GET / HTTP/1.1\r\n" |
166 | "Host: checkip.dyndns.org\r\n" | |
167 | "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" | |
0a61b0df | 168 | "Connection: close\r\n" |
169 | "\r\n"; | |
170 | ||
683bcb91 | 171 | pszKeyword = "Address:"; |
0a61b0df | 172 | } |
173 | else if (nHost == 2) | |
174 | { | |
c981d768 | 175 | addrConnect = CService("74.208.43.192", 80); // www.showmyip.com |
0a61b0df | 176 | |
177 | if (nLookup == 1) | |
178 | { | |
67a42f92 | 179 | CService addrIP("www.showmyip.com", 80, true); |
a6a5bb7c PW |
180 | if (addrIP.IsValid()) |
181 | addrConnect = addrIP; | |
0a61b0df | 182 | } |
183 | ||
683bcb91 | 184 | pszGet = "GET /simple/ HTTP/1.1\r\n" |
185 | "Host: www.showmyip.com\r\n" | |
0a61b0df | 186 | "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" |
187 | "Connection: close\r\n" | |
188 | "\r\n"; | |
189 | ||
683bcb91 | 190 | pszKeyword = NULL; // Returns just IP address |
0a61b0df | 191 | } |
192 | ||
193 | if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet)) | |
194 | return true; | |
195 | } | |
196 | ||
197 | return false; | |
198 | } | |
199 | ||
629e37dd | 200 | void ThreadGetMyExternalIP(void* parg) |
201 | { | |
202 | // Wait for IRC to get it first | |
9d952d17 | 203 | if (GetBoolArg("-irc", false)) |
629e37dd | 204 | { |
205 | for (int i = 0; i < 2 * 60; i++) | |
206 | { | |
207 | Sleep(1000); | |
208 | if (fGotExternalIP || fShutdown) | |
209 | return; | |
210 | } | |
211 | } | |
212 | ||
213 | // Fallback in case IRC fails to get it | |
67a42f92 | 214 | if (GetMyExternalIP(addrLocalHost)) |
629e37dd | 215 | { |
216 | printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str()); | |
217 | if (addrLocalHost.IsRoutable()) | |
218 | { | |
219 | // If we already connected to a few before we had our IP, go back and addr them. | |
220 | // setAddrKnown automatically filters any duplicate sends. | |
221 | CAddress addr(addrLocalHost); | |
222 | addr.nTime = GetAdjustedTime(); | |
223 | CRITICAL_BLOCK(cs_vNodes) | |
223b6f1b | 224 | BOOST_FOREACH(CNode* pnode, vNodes) |
629e37dd | 225 | pnode->PushAddress(addr); |
226 | } | |
227 | } | |
228 | } | |
229 | ||
0a61b0df | 230 | |
231 | ||
232 | ||
233 | ||
bde280b9 | 234 | bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB) |
0a61b0df | 235 | { |
236 | if (!addr.IsRoutable()) | |
237 | return false; | |
67a42f92 | 238 | if ((CService)addr == (CService)addrLocalHost) |
0a61b0df | 239 | return false; |
bde280b9 | 240 | addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty); |
94066965 GA |
241 | bool fUpdated = false; |
242 | bool fNew = false; | |
243 | CAddress addrFound = addr; | |
244 | ||
0a61b0df | 245 | CRITICAL_BLOCK(cs_mapAddresses) |
246 | { | |
247 | map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey()); | |
248 | if (it == mapAddresses.end()) | |
249 | { | |
250 | // New address | |
a6a5bb7c | 251 | printf("AddAddress(%s)\n", addr.ToString().c_str()); |
0a61b0df | 252 | mapAddresses.insert(make_pair(addr.GetKey(), addr)); |
94066965 GA |
253 | fUpdated = true; |
254 | fNew = true; | |
0a61b0df | 255 | } |
256 | else | |
257 | { | |
94066965 | 258 | addrFound = (*it).second; |
0a61b0df | 259 | if ((addrFound.nServices | addr.nServices) != addrFound.nServices) |
260 | { | |
261 | // Services have been added | |
262 | addrFound.nServices |= addr.nServices; | |
263 | fUpdated = true; | |
264 | } | |
265 | bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); | |
bde280b9 | 266 | int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); |
0a61b0df | 267 | if (addrFound.nTime < addr.nTime - nUpdateInterval) |
268 | { | |
269 | // Periodically update most recently seen time | |
270 | addrFound.nTime = addr.nTime; | |
271 | fUpdated = true; | |
272 | } | |
0a61b0df | 273 | } |
274 | } | |
94066965 GA |
275 | // There is a nasty deadlock bug if this is done inside the cs_mapAddresses |
276 | // CRITICAL_BLOCK: | |
277 | // Thread 1: begin db transaction (locks inside-db-mutex) | |
278 | // then AddAddress (locks cs_mapAddresses) | |
279 | // Thread 2: AddAddress (locks cs_mapAddresses) | |
280 | // ... then db operation hangs waiting for inside-db-mutex | |
281 | if (fUpdated) | |
282 | { | |
283 | if (pAddrDB) | |
284 | pAddrDB->WriteAddress(addrFound); | |
285 | else | |
286 | CAddrDB().WriteAddress(addrFound); | |
287 | } | |
288 | return fNew; | |
0a61b0df | 289 | } |
290 | ||
67a42f92 | 291 | void AddressCurrentlyConnected(const CService& addr) |
0a61b0df | 292 | { |
a75d7066 PW |
293 | CAddress *paddrFound = NULL; |
294 | ||
0a61b0df | 295 | CRITICAL_BLOCK(cs_mapAddresses) |
296 | { | |
297 | // Only if it's been published already | |
298 | map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey()); | |
299 | if (it != mapAddresses.end()) | |
a75d7066 PW |
300 | paddrFound = &(*it).second; |
301 | } | |
302 | ||
303 | if (paddrFound) | |
304 | { | |
305 | int64 nUpdateInterval = 20 * 60; | |
306 | if (paddrFound->nTime < GetAdjustedTime() - nUpdateInterval) | |
0a61b0df | 307 | { |
a75d7066 PW |
308 | // Periodically update most recently seen time |
309 | paddrFound->nTime = GetAdjustedTime(); | |
310 | CAddrDB addrdb; | |
311 | addrdb.WriteAddress(*paddrFound); | |
0a61b0df | 312 | } |
313 | } | |
314 | } | |
315 | ||
316 | ||
317 | ||
318 | ||
319 | ||
320 | void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1) | |
321 | { | |
322 | // If the dialog might get closed before the reply comes back, | |
323 | // call this in the destructor so it doesn't get called after it's deleted. | |
324 | CRITICAL_BLOCK(cs_vNodes) | |
325 | { | |
223b6f1b | 326 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 327 | { |
328 | CRITICAL_BLOCK(pnode->cs_mapRequests) | |
329 | { | |
330 | for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();) | |
331 | { | |
332 | CRequestTracker& tracker = (*mi).second; | |
333 | if (tracker.fn == fn && tracker.param1 == param1) | |
334 | pnode->mapRequests.erase(mi++); | |
335 | else | |
336 | mi++; | |
337 | } | |
338 | } | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
343 | ||
344 | ||
345 | ||
346 | ||
347 | ||
348 | ||
349 | // | |
350 | // Subscription methods for the broadcast and subscription system. | |
351 | // Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT. | |
352 | // | |
353 | // The subscription system uses a meet-in-the-middle strategy. | |
354 | // With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers | |
355 | // subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through. | |
356 | // | |
357 | ||
358 | bool AnySubscribed(unsigned int nChannel) | |
359 | { | |
360 | if (pnodeLocalHost->IsSubscribed(nChannel)) | |
361 | return true; | |
362 | CRITICAL_BLOCK(cs_vNodes) | |
223b6f1b | 363 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 364 | if (pnode->IsSubscribed(nChannel)) |
365 | return true; | |
366 | return false; | |
367 | } | |
368 | ||
369 | bool CNode::IsSubscribed(unsigned int nChannel) | |
370 | { | |
371 | if (nChannel >= vfSubscribe.size()) | |
372 | return false; | |
373 | return vfSubscribe[nChannel]; | |
374 | } | |
375 | ||
376 | void CNode::Subscribe(unsigned int nChannel, unsigned int nHops) | |
377 | { | |
378 | if (nChannel >= vfSubscribe.size()) | |
379 | return; | |
380 | ||
381 | if (!AnySubscribed(nChannel)) | |
382 | { | |
383 | // Relay subscribe | |
384 | CRITICAL_BLOCK(cs_vNodes) | |
223b6f1b | 385 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 386 | if (pnode != this) |
387 | pnode->PushMessage("subscribe", nChannel, nHops); | |
388 | } | |
389 | ||
390 | vfSubscribe[nChannel] = true; | |
391 | } | |
392 | ||
393 | void CNode::CancelSubscribe(unsigned int nChannel) | |
394 | { | |
395 | if (nChannel >= vfSubscribe.size()) | |
396 | return; | |
397 | ||
398 | // Prevent from relaying cancel if wasn't subscribed | |
399 | if (!vfSubscribe[nChannel]) | |
400 | return; | |
401 | vfSubscribe[nChannel] = false; | |
402 | ||
403 | if (!AnySubscribed(nChannel)) | |
404 | { | |
405 | // Relay subscription cancel | |
406 | CRITICAL_BLOCK(cs_vNodes) | |
223b6f1b | 407 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 408 | if (pnode != this) |
409 | pnode->PushMessage("sub-cancel", nChannel); | |
410 | } | |
411 | } | |
412 | ||
413 | ||
414 | ||
415 | ||
416 | ||
417 | ||
418 | ||
419 | ||
420 | ||
67a42f92 | 421 | CNode* FindNode(const CNetAddr& ip) |
0a61b0df | 422 | { |
423 | CRITICAL_BLOCK(cs_vNodes) | |
424 | { | |
223b6f1b | 425 | BOOST_FOREACH(CNode* pnode, vNodes) |
67a42f92 | 426 | if ((CNetAddr)pnode->addr == ip) |
0a61b0df | 427 | return (pnode); |
428 | } | |
429 | return NULL; | |
430 | } | |
431 | ||
67a42f92 | 432 | CNode* FindNode(const CService& addr) |
0a61b0df | 433 | { |
434 | CRITICAL_BLOCK(cs_vNodes) | |
435 | { | |
223b6f1b | 436 | BOOST_FOREACH(CNode* pnode, vNodes) |
67a42f92 | 437 | if ((CService)pnode->addr == addr) |
0a61b0df | 438 | return (pnode); |
439 | } | |
440 | return NULL; | |
441 | } | |
442 | ||
bde280b9 | 443 | CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) |
0a61b0df | 444 | { |
67a42f92 | 445 | if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost) |
0a61b0df | 446 | return NULL; |
447 | ||
448 | // Look for an existing connection | |
67a42f92 | 449 | CNode* pnode = FindNode((CService)addrConnect); |
0a61b0df | 450 | if (pnode) |
451 | { | |
452 | if (nTimeout != 0) | |
453 | pnode->AddRef(nTimeout); | |
454 | else | |
455 | pnode->AddRef(); | |
456 | return pnode; | |
457 | } | |
458 | ||
459 | /// debug print | |
460 | printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n", | |
a6a5bb7c | 461 | addrConnect.ToString().c_str(), |
0a61b0df | 462 | (double)(addrConnect.nTime - GetAdjustedTime())/3600.0, |
463 | (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0); | |
464 | ||
465 | CRITICAL_BLOCK(cs_mapAddresses) | |
466 | mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime(); | |
467 | ||
468 | // Connect | |
469 | SOCKET hSocket; | |
470 | if (ConnectSocket(addrConnect, hSocket)) | |
471 | { | |
472 | /// debug print | |
a6a5bb7c | 473 | printf("connected %s\n", addrConnect.ToString().c_str()); |
0a61b0df | 474 | |
475 | // Set to nonblocking | |
6853e627 | 476 | #ifdef WIN32 |
0a61b0df | 477 | u_long nOne = 1; |
478 | if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) | |
479 | printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError()); | |
480 | #else | |
481 | if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) | |
482 | printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno); | |
483 | #endif | |
484 | ||
485 | // Add node | |
486 | CNode* pnode = new CNode(hSocket, addrConnect, false); | |
487 | if (nTimeout != 0) | |
488 | pnode->AddRef(nTimeout); | |
489 | else | |
490 | pnode->AddRef(); | |
491 | CRITICAL_BLOCK(cs_vNodes) | |
492 | vNodes.push_back(pnode); | |
493 | ||
494 | pnode->nTimeConnected = GetTime(); | |
495 | return pnode; | |
496 | } | |
497 | else | |
498 | { | |
499 | return NULL; | |
500 | } | |
501 | } | |
502 | ||
503 | void CNode::CloseSocketDisconnect() | |
504 | { | |
505 | fDisconnect = true; | |
506 | if (hSocket != INVALID_SOCKET) | |
507 | { | |
508 | if (fDebug) | |
509 | printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); | |
a6a5bb7c | 510 | printf("disconnecting node %s\n", addr.ToString().c_str()); |
0a61b0df | 511 | closesocket(hSocket); |
512 | hSocket = INVALID_SOCKET; | |
513 | } | |
514 | } | |
515 | ||
516 | void CNode::Cleanup() | |
517 | { | |
518 | // All of a nodes broadcasts and subscriptions are automatically torn down | |
519 | // when it goes down, so a node has to stay up to keep its broadcast going. | |
520 | ||
521 | // Cancel subscriptions | |
522 | for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++) | |
523 | if (vfSubscribe[nChannel]) | |
524 | CancelSubscribe(nChannel); | |
525 | } | |
526 | ||
527 | ||
f8ded588 GA |
528 | void CNode::PushVersion() |
529 | { | |
530 | /// when NTP implemented, change to just nTime = GetAdjustedTime() | |
bde280b9 | 531 | int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); |
c981d768 | 532 | CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr); |
baba6e7d | 533 | CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress(CService("0.0.0.0",0)) : addrLocalHost); |
f8ded588 GA |
534 | RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); |
535 | PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, | |
536 | nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight); | |
537 | } | |
538 | ||
539 | ||
540 | ||
541 | ||
542 | ||
67a42f92 | 543 | std::map<CNetAddr, int64> CNode::setBanned; |
15f3ad4d GA |
544 | CCriticalSection CNode::cs_setBanned; |
545 | ||
546 | void CNode::ClearBanned() | |
547 | { | |
548 | setBanned.clear(); | |
549 | } | |
550 | ||
67a42f92 | 551 | bool CNode::IsBanned(CNetAddr ip) |
15f3ad4d GA |
552 | { |
553 | bool fResult = false; | |
554 | CRITICAL_BLOCK(cs_setBanned) | |
555 | { | |
67a42f92 | 556 | std::map<CNetAddr, int64>::iterator i = setBanned.find(ip); |
15f3ad4d GA |
557 | if (i != setBanned.end()) |
558 | { | |
bde280b9 | 559 | int64 t = (*i).second; |
15f3ad4d GA |
560 | if (GetTime() < t) |
561 | fResult = true; | |
562 | } | |
563 | } | |
564 | return fResult; | |
565 | } | |
566 | ||
567 | bool CNode::Misbehaving(int howmuch) | |
568 | { | |
569 | if (addr.IsLocal()) | |
570 | { | |
571 | printf("Warning: local node %s misbehaving\n", addr.ToString().c_str()); | |
572 | return false; | |
573 | } | |
574 | ||
575 | nMisbehavior += howmuch; | |
576 | if (nMisbehavior >= GetArg("-banscore", 100)) | |
577 | { | |
bde280b9 | 578 | int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban |
15f3ad4d | 579 | CRITICAL_BLOCK(cs_setBanned) |
67a42f92 PW |
580 | if (setBanned[addr] < banTime) |
581 | setBanned[addr] = banTime; | |
15f3ad4d GA |
582 | CloseSocketDisconnect(); |
583 | printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior); | |
584 | return true; | |
585 | } | |
586 | return false; | |
587 | } | |
588 | ||
0a61b0df | 589 | |
590 | ||
591 | ||
592 | ||
593 | ||
594 | ||
595 | ||
596 | ||
597 | ||
598 | ||
599 | ||
600 | void ThreadSocketHandler(void* parg) | |
601 | { | |
602 | IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg)); | |
603 | try | |
604 | { | |
605 | vnThreadsRunning[0]++; | |
606 | ThreadSocketHandler2(parg); | |
607 | vnThreadsRunning[0]--; | |
608 | } | |
609 | catch (std::exception& e) { | |
610 | vnThreadsRunning[0]--; | |
611 | PrintException(&e, "ThreadSocketHandler()"); | |
612 | } catch (...) { | |
613 | vnThreadsRunning[0]--; | |
614 | throw; // support pthread_cancel() | |
615 | } | |
616 | printf("ThreadSocketHandler exiting\n"); | |
617 | } | |
618 | ||
619 | void ThreadSocketHandler2(void* parg) | |
620 | { | |
621 | printf("ThreadSocketHandler started\n"); | |
622 | list<CNode*> vNodesDisconnected; | |
623 | int nPrevNodeCount = 0; | |
624 | ||
625 | loop | |
626 | { | |
627 | // | |
628 | // Disconnect nodes | |
629 | // | |
630 | CRITICAL_BLOCK(cs_vNodes) | |
631 | { | |
632 | // Disconnect unused nodes | |
633 | vector<CNode*> vNodesCopy = vNodes; | |
223b6f1b | 634 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 635 | { |
636 | if (pnode->fDisconnect || | |
637 | (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty())) | |
638 | { | |
639 | // remove from vNodes | |
640 | vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); | |
641 | ||
642 | // close socket and cleanup | |
643 | pnode->CloseSocketDisconnect(); | |
644 | pnode->Cleanup(); | |
645 | ||
646 | // hold in disconnected pool until all refs are released | |
647 | pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60); | |
648 | if (pnode->fNetworkNode || pnode->fInbound) | |
649 | pnode->Release(); | |
650 | vNodesDisconnected.push_back(pnode); | |
651 | } | |
652 | } | |
653 | ||
654 | // Delete disconnected nodes | |
655 | list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected; | |
223b6f1b | 656 | BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy) |
0a61b0df | 657 | { |
658 | // wait until threads are done using it | |
659 | if (pnode->GetRefCount() <= 0) | |
660 | { | |
661 | bool fDelete = false; | |
662 | TRY_CRITICAL_BLOCK(pnode->cs_vSend) | |
663 | TRY_CRITICAL_BLOCK(pnode->cs_vRecv) | |
664 | TRY_CRITICAL_BLOCK(pnode->cs_mapRequests) | |
665 | TRY_CRITICAL_BLOCK(pnode->cs_inventory) | |
666 | fDelete = true; | |
667 | if (fDelete) | |
668 | { | |
669 | vNodesDisconnected.remove(pnode); | |
670 | delete pnode; | |
671 | } | |
672 | } | |
673 | } | |
674 | } | |
675 | if (vNodes.size() != nPrevNodeCount) | |
676 | { | |
677 | nPrevNodeCount = vNodes.size(); | |
678 | MainFrameRepaint(); | |
679 | } | |
680 | ||
681 | ||
682 | // | |
683 | // Find which sockets have data to receive | |
684 | // | |
685 | struct timeval timeout; | |
686 | timeout.tv_sec = 0; | |
687 | timeout.tv_usec = 50000; // frequency to poll pnode->vSend | |
688 | ||
689 | fd_set fdsetRecv; | |
690 | fd_set fdsetSend; | |
691 | fd_set fdsetError; | |
692 | FD_ZERO(&fdsetRecv); | |
693 | FD_ZERO(&fdsetSend); | |
694 | FD_ZERO(&fdsetError); | |
695 | SOCKET hSocketMax = 0; | |
5f88e888 W |
696 | |
697 | if(hListenSocket != INVALID_SOCKET) | |
698 | FD_SET(hListenSocket, &fdsetRecv); | |
0a61b0df | 699 | hSocketMax = max(hSocketMax, hListenSocket); |
700 | CRITICAL_BLOCK(cs_vNodes) | |
701 | { | |
223b6f1b | 702 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 703 | { |
d7f1d200 | 704 | if (pnode->hSocket == INVALID_SOCKET) |
0a61b0df | 705 | continue; |
706 | FD_SET(pnode->hSocket, &fdsetRecv); | |
707 | FD_SET(pnode->hSocket, &fdsetError); | |
708 | hSocketMax = max(hSocketMax, pnode->hSocket); | |
709 | TRY_CRITICAL_BLOCK(pnode->cs_vSend) | |
710 | if (!pnode->vSend.empty()) | |
711 | FD_SET(pnode->hSocket, &fdsetSend); | |
712 | } | |
713 | } | |
714 | ||
715 | vnThreadsRunning[0]--; | |
716 | int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout); | |
717 | vnThreadsRunning[0]++; | |
718 | if (fShutdown) | |
719 | return; | |
720 | if (nSelect == SOCKET_ERROR) | |
721 | { | |
722 | int nErr = WSAGetLastError(); | |
c6710c7a MC |
723 | if (hSocketMax > -1) |
724 | { | |
725 | printf("socket select error %d\n", nErr); | |
726 | for (int i = 0; i <= hSocketMax; i++) | |
727 | FD_SET(i, &fdsetRecv); | |
728 | } | |
0a61b0df | 729 | FD_ZERO(&fdsetSend); |
730 | FD_ZERO(&fdsetError); | |
731 | Sleep(timeout.tv_usec/1000); | |
732 | } | |
733 | ||
734 | ||
735 | // | |
736 | // Accept new connections | |
737 | // | |
5f88e888 | 738 | if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv)) |
0a61b0df | 739 | { |
740 | struct sockaddr_in sockaddr; | |
741 | socklen_t len = sizeof(sockaddr); | |
742 | SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); | |
25ab1758 | 743 | CAddress addr; |
4698dd9a CM |
744 | int nInbound = 0; |
745 | ||
25ab1758 PW |
746 | if (hSocket != INVALID_SOCKET) |
747 | addr = CAddress(sockaddr); | |
748 | ||
5a3e82f9 | 749 | CRITICAL_BLOCK(cs_vNodes) |
223b6f1b | 750 | BOOST_FOREACH(CNode* pnode, vNodes) |
5a3e82f9 GA |
751 | if (pnode->fInbound) |
752 | nInbound++; | |
25ab1758 | 753 | |
0a61b0df | 754 | if (hSocket == INVALID_SOCKET) |
755 | { | |
756 | if (WSAGetLastError() != WSAEWOULDBLOCK) | |
757 | printf("socket error accept failed: %d\n", WSAGetLastError()); | |
758 | } | |
5a3e82f9 | 759 | else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS) |
0a61b0df | 760 | { |
b24e6e4d MC |
761 | CRITICAL_BLOCK(cs_setservAddNodeAddresses) |
762 | if (!setservAddNodeAddresses.count(addr)) | |
763 | closesocket(hSocket); | |
0a61b0df | 764 | } |
67a42f92 | 765 | else if (CNode::IsBanned(addr)) |
15f3ad4d GA |
766 | { |
767 | printf("connetion from %s dropped (banned)\n", addr.ToString().c_str()); | |
768 | closesocket(hSocket); | |
769 | } | |
0a61b0df | 770 | else |
771 | { | |
a6a5bb7c | 772 | printf("accepted connection %s\n", addr.ToString().c_str()); |
0a61b0df | 773 | CNode* pnode = new CNode(hSocket, addr, true); |
774 | pnode->AddRef(); | |
775 | CRITICAL_BLOCK(cs_vNodes) | |
776 | vNodes.push_back(pnode); | |
777 | } | |
778 | } | |
779 | ||
780 | ||
781 | // | |
782 | // Service each socket | |
783 | // | |
784 | vector<CNode*> vNodesCopy; | |
785 | CRITICAL_BLOCK(cs_vNodes) | |
786 | { | |
787 | vNodesCopy = vNodes; | |
223b6f1b | 788 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 789 | pnode->AddRef(); |
790 | } | |
223b6f1b | 791 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 792 | { |
793 | if (fShutdown) | |
794 | return; | |
795 | ||
796 | // | |
797 | // Receive | |
798 | // | |
799 | if (pnode->hSocket == INVALID_SOCKET) | |
800 | continue; | |
801 | if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError)) | |
802 | { | |
803 | TRY_CRITICAL_BLOCK(pnode->cs_vRecv) | |
804 | { | |
805 | CDataStream& vRecv = pnode->vRecv; | |
806 | unsigned int nPos = vRecv.size(); | |
807 | ||
49731745 | 808 | if (nPos > ReceiveBufferSize()) { |
0a61b0df | 809 | if (!pnode->fDisconnect) |
9cbae55a | 810 | printf("socket recv flood control disconnect (%d bytes)\n", vRecv.size()); |
0a61b0df | 811 | pnode->CloseSocketDisconnect(); |
812 | } | |
9cbae55a GA |
813 | else { |
814 | // typical socket buffer is 8K-64K | |
815 | char pchBuf[0x10000]; | |
816 | int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); | |
817 | if (nBytes > 0) | |
0a61b0df | 818 | { |
9cbae55a GA |
819 | vRecv.resize(nPos + nBytes); |
820 | memcpy(&vRecv[nPos], pchBuf, nBytes); | |
821 | pnode->nLastRecv = GetTime(); | |
822 | } | |
823 | else if (nBytes == 0) | |
824 | { | |
825 | // socket closed gracefully | |
0a61b0df | 826 | if (!pnode->fDisconnect) |
9cbae55a | 827 | printf("socket closed\n"); |
0a61b0df | 828 | pnode->CloseSocketDisconnect(); |
829 | } | |
9cbae55a GA |
830 | else if (nBytes < 0) |
831 | { | |
832 | // error | |
833 | int nErr = WSAGetLastError(); | |
834 | if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | |
835 | { | |
836 | if (!pnode->fDisconnect) | |
837 | printf("socket recv error %d\n", nErr); | |
838 | pnode->CloseSocketDisconnect(); | |
839 | } | |
840 | } | |
0a61b0df | 841 | } |
842 | } | |
843 | } | |
844 | ||
845 | // | |
846 | // Send | |
847 | // | |
848 | if (pnode->hSocket == INVALID_SOCKET) | |
849 | continue; | |
850 | if (FD_ISSET(pnode->hSocket, &fdsetSend)) | |
851 | { | |
852 | TRY_CRITICAL_BLOCK(pnode->cs_vSend) | |
853 | { | |
854 | CDataStream& vSend = pnode->vSend; | |
855 | if (!vSend.empty()) | |
856 | { | |
857 | int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT); | |
858 | if (nBytes > 0) | |
859 | { | |
860 | vSend.erase(vSend.begin(), vSend.begin() + nBytes); | |
861 | pnode->nLastSend = GetTime(); | |
862 | } | |
863 | else if (nBytes < 0) | |
864 | { | |
865 | // error | |
866 | int nErr = WSAGetLastError(); | |
867 | if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | |
868 | { | |
869 | printf("socket send error %d\n", nErr); | |
870 | pnode->CloseSocketDisconnect(); | |
871 | } | |
872 | } | |
49731745 | 873 | if (vSend.size() > SendBufferSize()) { |
9cbae55a GA |
874 | if (!pnode->fDisconnect) |
875 | printf("socket send flood control disconnect (%d bytes)\n", vSend.size()); | |
876 | pnode->CloseSocketDisconnect(); | |
877 | } | |
0a61b0df | 878 | } |
879 | } | |
880 | } | |
881 | ||
882 | // | |
883 | // Inactivity checking | |
884 | // | |
885 | if (pnode->vSend.empty()) | |
886 | pnode->nLastSendEmpty = GetTime(); | |
887 | if (GetTime() - pnode->nTimeConnected > 60) | |
888 | { | |
889 | if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) | |
890 | { | |
891 | printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0); | |
892 | pnode->fDisconnect = true; | |
893 | } | |
894 | else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60) | |
895 | { | |
896 | printf("socket not sending\n"); | |
897 | pnode->fDisconnect = true; | |
898 | } | |
899 | else if (GetTime() - pnode->nLastRecv > 90*60) | |
900 | { | |
901 | printf("socket inactivity timeout\n"); | |
902 | pnode->fDisconnect = true; | |
903 | } | |
904 | } | |
905 | } | |
906 | CRITICAL_BLOCK(cs_vNodes) | |
907 | { | |
223b6f1b | 908 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 909 | pnode->Release(); |
910 | } | |
911 | ||
0a61b0df | 912 | Sleep(10); |
913 | } | |
914 | } | |
915 | ||
916 | ||
917 | ||
918 | ||
919 | ||
920 | ||
921 | ||
922 | ||
923 | ||
8bb5edc1 MC |
924 | #ifdef USE_UPNP |
925 | void ThreadMapPort(void* parg) | |
926 | { | |
927 | IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg)); | |
928 | try | |
929 | { | |
930 | vnThreadsRunning[5]++; | |
931 | ThreadMapPort2(parg); | |
932 | vnThreadsRunning[5]--; | |
933 | } | |
934 | catch (std::exception& e) { | |
935 | vnThreadsRunning[5]--; | |
936 | PrintException(&e, "ThreadMapPort()"); | |
937 | } catch (...) { | |
938 | vnThreadsRunning[5]--; | |
939 | PrintException(NULL, "ThreadMapPort()"); | |
940 | } | |
941 | printf("ThreadMapPort exiting\n"); | |
942 | } | |
943 | ||
944 | void ThreadMapPort2(void* parg) | |
945 | { | |
946 | printf("ThreadMapPort started\n"); | |
947 | ||
948 | char port[6]; | |
00bcfe0b | 949 | sprintf(port, "%d", GetListenPort()); |
8bb5edc1 | 950 | |
8bb5edc1 MC |
951 | const char * multicastif = 0; |
952 | const char * minissdpdpath = 0; | |
953 | struct UPNPDev * devlist = 0; | |
954 | char lanaddr[64]; | |
955 | ||
94b97046 LD |
956 | #ifndef UPNPDISCOVER_SUCCESS |
957 | /* miniupnpc 1.5 */ | |
958 | devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0); | |
959 | #else | |
960 | /* miniupnpc 1.6 */ | |
961 | int error = 0; | |
b4ada906 | 962 | devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); |
94b97046 | 963 | #endif |
8bb5edc1 MC |
964 | |
965 | struct UPNPUrls urls; | |
966 | struct IGDdatas data; | |
967 | int r; | |
968 | ||
f285d4f4 DH |
969 | r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); |
970 | if (r == 1) | |
8bb5edc1 | 971 | { |
baba6e7d MC |
972 | if (!addrLocalHost.IsRoutable()) |
973 | { | |
974 | char externalIPAddress[40]; | |
975 | r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); | |
976 | if(r != UPNPCOMMAND_SUCCESS) | |
977 | printf("UPnP: GetExternalIPAddress() returned %d\n", r); | |
978 | else | |
979 | { | |
980 | if(externalIPAddress[0]) | |
981 | { | |
982 | printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress); | |
983 | CAddress addrExternalFromUPnP(CService(externalIPAddress, 0), nLocalServices); | |
984 | if (addrExternalFromUPnP.IsRoutable()) | |
985 | addrLocalHost = addrExternalFromUPnP; | |
986 | } | |
987 | else | |
988 | printf("UPnP: GetExternalIPAddress failed.\n"); | |
989 | } | |
990 | } | |
991 | ||
15656981 | 992 | string strDesc = "Bitcoin " + FormatFullVersion(); |
94b97046 | 993 | #ifndef UPNPDISCOVER_SUCCESS |
177dbcaa | 994 | /* miniupnpc 1.5 */ |
94b97046 | 995 | r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, |
b985efaa | 996 | port, port, lanaddr, strDesc.c_str(), "TCP", 0); |
94b97046 | 997 | #else |
177dbcaa | 998 | /* miniupnpc 1.6 */ |
8bb5edc1 | 999 | r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, |
b985efaa | 1000 | port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0"); |
94b97046 | 1001 | #endif |
b4ada906 | 1002 | |
8bb5edc1 MC |
1003 | if(r!=UPNPCOMMAND_SUCCESS) |
1004 | printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", | |
1005 | port, port, lanaddr, r, strupnperror(r)); | |
1006 | else | |
1007 | printf("UPnP Port Mapping successful.\n"); | |
177dbcaa | 1008 | int i = 1; |
8bb5edc1 MC |
1009 | loop { |
1010 | if (fShutdown || !fUseUPnP) | |
1011 | { | |
1012 | r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port, "TCP", 0); | |
1013 | printf("UPNP_DeletePortMapping() returned : %d\n", r); | |
1014 | freeUPNPDevlist(devlist); devlist = 0; | |
1015 | FreeUPNPUrls(&urls); | |
1016 | return; | |
1017 | } | |
177dbcaa MC |
1018 | if (i % 600 == 0) // Refresh every 20 minutes |
1019 | { | |
1020 | #ifndef UPNPDISCOVER_SUCCESS | |
1021 | /* miniupnpc 1.5 */ | |
1022 | r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, | |
1023 | port, port, lanaddr, strDesc.c_str(), "TCP", 0); | |
1024 | #else | |
1025 | /* miniupnpc 1.6 */ | |
1026 | r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, | |
1027 | port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0"); | |
1028 | #endif | |
1029 | ||
1030 | if(r!=UPNPCOMMAND_SUCCESS) | |
1031 | printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", | |
1032 | port, port, lanaddr, r, strupnperror(r)); | |
1033 | else | |
1034 | printf("UPnP Port Mapping successful.\n");; | |
1035 | } | |
8bb5edc1 | 1036 | Sleep(2000); |
177dbcaa | 1037 | i++; |
8bb5edc1 MC |
1038 | } |
1039 | } else { | |
1040 | printf("No valid UPnP IGDs found\n"); | |
1041 | freeUPNPDevlist(devlist); devlist = 0; | |
f285d4f4 DH |
1042 | if (r != 0) |
1043 | FreeUPNPUrls(&urls); | |
8bb5edc1 | 1044 | loop { |
973800b5 | 1045 | if (fShutdown || !fUseUPnP) |
8bb5edc1 MC |
1046 | return; |
1047 | Sleep(2000); | |
1048 | } | |
1049 | } | |
1050 | } | |
1051 | ||
1052 | void MapPort(bool fMapPort) | |
1053 | { | |
1054 | if (fUseUPnP != fMapPort) | |
1055 | { | |
1056 | fUseUPnP = fMapPort; | |
64c7ee7e | 1057 | WriteSetting("fUseUPnP", fUseUPnP); |
8bb5edc1 MC |
1058 | } |
1059 | if (fUseUPnP && vnThreadsRunning[5] < 1) | |
1060 | { | |
1061 | if (!CreateThread(ThreadMapPort, NULL)) | |
1062 | printf("Error: ThreadMapPort(ThreadMapPort) failed\n"); | |
1063 | } | |
1064 | } | |
9f0ac169 GA |
1065 | #else |
1066 | void MapPort(bool /* unused fMapPort */) | |
1067 | { | |
1068 | // Intentionally left blank. | |
1069 | } | |
8bb5edc1 MC |
1070 | #endif |
1071 | ||
1072 | ||
1073 | ||
1074 | ||
1075 | ||
1076 | ||
1077 | ||
1078 | ||
1079 | ||
1080 | ||
f684aec4 JG |
1081 | static const char *strDNSSeed[] = { |
1082 | "bitseed.xf2.org", | |
f03c31db | 1083 | "dnsseed.bluematt.me", |
61a8c056 | 1084 | "seed.bitcoin.sipa.be", |
64773488 | 1085 | "dnsseed.bitcoin.dashjr.org", |
f684aec4 | 1086 | }; |
0a61b0df | 1087 | |
2bc6cece | 1088 | void ThreadDNSAddressSeed(void* parg) |
f684aec4 | 1089 | { |
2bc6cece MC |
1090 | IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg)); |
1091 | try | |
1092 | { | |
1093 | vnThreadsRunning[6]++; | |
1094 | ThreadDNSAddressSeed2(parg); | |
1095 | vnThreadsRunning[6]--; | |
1096 | } | |
1097 | catch (std::exception& e) { | |
1098 | vnThreadsRunning[6]--; | |
1099 | PrintException(&e, "ThreadDNSAddressSeed()"); | |
1100 | } catch (...) { | |
1101 | vnThreadsRunning[6]--; | |
1102 | throw; // support pthread_cancel() | |
1103 | } | |
1104 | printf("ThreadDNSAddressSeed exiting\n"); | |
1105 | } | |
1106 | ||
1107 | void ThreadDNSAddressSeed2(void* parg) | |
1108 | { | |
1109 | printf("ThreadDNSAddressSeed started\n"); | |
f684aec4 JG |
1110 | int found = 0; |
1111 | ||
ce8f78a7 MC |
1112 | if (!fTestNet) |
1113 | { | |
1114 | printf("Loading addresses from DNS seeds (could take a while)\n"); | |
f684aec4 | 1115 | |
ce8f78a7 | 1116 | for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { |
67a42f92 PW |
1117 | vector<CNetAddr> vaddr; |
1118 | if (LookupHost(strDNSSeed[seed_idx], vaddr)) | |
a6a5bb7c | 1119 | { |
a75d7066 PW |
1120 | CAddrDB addrDB; |
1121 | addrDB.TxnBegin(); | |
67a42f92 | 1122 | BOOST_FOREACH (CNetAddr& ip, vaddr) |
a6a5bb7c | 1123 | { |
67a42f92 | 1124 | if (ip.IsRoutable()) |
ce8f78a7 | 1125 | { |
67a42f92 | 1126 | CAddress addr(CService(ip, GetDefaultPort()), NODE_NETWORK); |
ce8f78a7 | 1127 | addr.nTime = 0; |
d655a26c | 1128 | AddAddress(addr, 0, &addrDB); |
ce8f78a7 MC |
1129 | found++; |
1130 | } | |
a6a5bb7c | 1131 | } |
a75d7066 | 1132 | addrDB.TxnCommit(); // Save addresses (it's ok if this fails) |
f684aec4 JG |
1133 | } |
1134 | } | |
1135 | } | |
1136 | ||
448b4516 | 1137 | printf("%d addresses found from DNS seeds\n", found); |
f684aec4 | 1138 | } |
0a61b0df | 1139 | |
1140 | ||
1141 | ||
2bc6cece MC |
1142 | |
1143 | ||
1144 | ||
1145 | ||
1146 | ||
1147 | ||
1148 | ||
1149 | ||
1150 | ||
0a61b0df | 1151 | unsigned int pnSeed[] = |
1152 | { | |
b2f76e9d DF |
1153 | 0x959bd347, 0xf8de42b2, 0x73bc0518, 0xea6edc50, 0x21b00a4d, 0xc725b43d, 0xd665464d, 0x1a2a770e, |
1154 | 0x27c93946, 0x65b2fa46, 0xb80ae255, 0x66b3b446, 0xb1877a3e, 0x6ee89e3e, 0xc3175b40, 0x2a01a83c, | |
1155 | 0x95b1363a, 0xa079ad3d, 0xe6ca801f, 0x027f4f4a, 0x34f7f03a, 0xf790f04a, 0x16ca801f, 0x2f4d5e40, | |
1156 | 0x3a4d5e40, 0xc43a322e, 0xc8159753, 0x14d4724c, 0x7919a118, 0xe0bdb34e, 0x68a16b2e, 0xff64b44d, | |
1157 | 0x6099115b, 0x9b57b05b, 0x7bd1b4ad, 0xdf95944f, 0x29d2b73d, 0xafa8db79, 0xe247ba41, 0x24078348, | |
1158 | 0xf722f03c, 0x33567ebc, 0xace64ed4, 0x984d3932, 0xb5f34e55, 0x27b7024d, 0x94579247, 0x8894042e, | |
1159 | 0x9357d34c, 0x1063c24b, 0xcaa228b1, 0xa3c5a8b2, 0x5dc64857, 0xa2c23643, 0xa8369a54, 0x31203077, | |
1160 | 0x00707c5c, 0x09fc0b3a, 0x272e9e2e, 0xf80f043e, 0x9449ca3e, 0x5512c33e, 0xd106b555, 0xe8024157, | |
1161 | 0xe288ec29, 0xc79c5461, 0xafb63932, 0xdb02ab4b, 0x0e512777, 0x8a145a4c, 0xb201ff4f, 0x5e09314b, | |
1162 | 0xcd9bfbcd, 0x1c023765, 0x4394e75c, 0xa728bd4d, 0x65331552, 0xa98420b1, 0x89ecf559, 0x6e80801f, | |
1163 | 0xf404f118, 0xefd62b51, 0x05918346, 0x9b186d5f, 0xacabab46, 0xf912e255, 0xc188ea62, 0xcc55734e, | |
1164 | 0xc668064d, 0xd77a4558, 0x46201c55, 0xf17dfc80, 0xf7142f2e, 0x87bfb718, 0x8aa54fb2, 0xc451d518, | |
1165 | 0xc4ae8831, 0x8dd44d55, 0x5bbd206c, 0x64536b5d, 0x5c667e60, 0x3b064242, 0xfe963a42, 0xa28e6dc8, | |
1166 | 0xe8a9604a, 0xc989464e, 0xd124a659, 0x50065140, 0xa44dfe5e, 0x1079e655, 0x3fb986d5, 0x47895b18, | |
1167 | 0x7d3ce4ad, 0x4561ba50, 0x296eec62, 0x255b41ad, 0xaed35ec9, 0x55556f12, 0xc7d3154d, 0x3297b65d, | |
1168 | 0x8930121f, 0xabf42e4e, 0x4a29e044, 0x1212685d, 0x676c1e40, 0xce009744, 0x383a8948, 0xa2dbd0ad, | |
1169 | 0xecc2564d, 0x07dbc252, 0x887ee24b, 0x5171644c, 0x6bb798c1, 0x847f495d, 0x4cbb7145, 0x3bb81c32, | |
1170 | 0x45eb262e, 0xc8015a4e, 0x250a361b, 0xf694f946, 0xd64a183e, 0xd4f1dd59, 0x8f20ffd4, 0x51d9e55c, | |
1171 | 0x09521763, 0x5e02002e, 0x32c8074d, 0xe685762e, 0x8290b0bc, 0x762a922e, 0xfc5ee754, 0x83a24829, | |
1172 | 0x775b224d, 0x6295bb4d, 0x38ec0555, 0xbffbba50, 0xe5560260, 0x86b16a7c, 0xd372234e, 0x49a3c24b, | |
1173 | 0x2f6a171f, 0x4d75ed60, 0xae94115b, 0xcb543744, 0x63080c59, 0x3f9c724c, 0xc977ce18, 0x532efb18, | |
1174 | 0x69dc3b2e, 0x5f94d929, 0x1732bb4d, 0x9c814b4d, 0xe6b3762e, 0xc024f662, 0x8face35b, 0x6b5b044d, | |
1175 | 0x798c7b57, 0x79a6b44c, 0x067d3057, 0xf9e94e5f, 0x91cbe15b, 0x71405eb2, 0x2662234e, 0xcbcc4a6d, | |
1176 | 0xbf69d54b, 0xa79b4e55, 0xec6d3e51, 0x7c0b3c02, 0x60f83653, 0x24c1e15c, 0x1110b62e, 0x10350f59, | |
1177 | 0xa56f1d55, 0x3509e7a9, 0xeb128354, 0x14268e2e, 0x934e28bc, 0x8e32692e, 0x8331a21f, 0x3e633932, | |
1178 | 0xc812b12e, 0xc684bf2e, 0x80112d2e, 0xe0ddc96c, 0xc630ca4a, 0x5c09b3b2, 0x0b580518, 0xc8e9d54b, | |
1179 | 0xd169aa43, 0x17d0d655, 0x1d029963, 0x7ff87559, 0xcb701f1f, 0x6fa3e85d, 0xe45e9a54, 0xf05d1802, | |
1180 | 0x44d03b2e, 0x837b692e, 0xccd4354e, 0x3d6da13c, 0x3423084d, 0xf707c34a, 0x55f6db3a, 0xad26e442, | |
1181 | 0x6233a21f, 0x09e80e59, 0x8caeb54d, 0xbe870941, 0xb407d20e, 0x20b51018, 0x56fb152e, 0x460d2a4e, | |
1182 | 0xbb9a2946, 0x560eb12e, 0xed83dd29, 0xd6724f53, 0xa50aafb8, 0x451346d9, 0x88348e2e, 0x7312fead, | |
1183 | 0x8ecaf96f, 0x1bda4e5f, 0xf1671e40, 0x3c8c3e3b, 0x4716324d, 0xdde24ede, 0xf98cd17d, 0xa91d4644, | |
1184 | 0x28124eb2, 0x147d5129, 0xd022042e, 0x61733d3b, 0xad0d5e02, 0x8ce2932e, 0xe5c18502, 0x549c1e32, | |
1185 | 0x9685801f, 0x86e217ad, 0xd948214b, 0x4110f462, 0x3a2e894e, 0xbd35492e, 0x87e0d558, 0x64b8ef7d, | |
1186 | 0x7c3eb962, 0x72a84b3e, 0x7cd667c9, 0x28370a2e, 0x4bc60e7b, 0x6fc1ec60, 0x14a6983f, 0x86739a4b, | |
1187 | 0x46954e5f, 0x32e2e15c, 0x2e9326cf, 0xe5801c5e, 0x379607b2, 0x32151145, 0xf0e39744, 0xacb54c55, | |
1188 | 0xa37dfb60, 0x83b55cc9, 0x388f7ca5, 0x15034f5f, 0x3e94965b, 0x68e0ffad, 0x35280f59, 0x8fe190cf, | |
1189 | 0x7c6ba5b2, 0xa5e9db43, 0x4ee1fc60, 0xd9d94e5f, 0x04040677, 0x0ea9b35e, 0x5961f14f, 0x67fda063, | |
1190 | 0xa48a5a31, 0xc6524e55, 0x283d325e, 0x3f37515f, 0x96b94b3e, 0xacce620e, 0x6481cc5b, 0xa4a06d4b, | |
1191 | 0x9e95d2d9, 0xe40c03d5, 0xc2f4514b, 0xb79aad44, 0xf64be843, 0xb2064070, 0xfca00455, 0x429dfa4e, | |
1192 | 0x2323f173, 0xeda4185e, 0xabd5227d, 0x9efd4d58, 0xb1104758, 0x4811e955, 0xbd9ab355, 0xe921f44b, | |
1193 | 0x9f166dce, 0x09e279b2, 0xe0c9ac7b, 0x7901a5ad, 0xa145d4b0, 0x79104671, 0xec31e35a, 0x4fe0b555, | |
1194 | 0xc7d9cbad, 0xad057f55, 0xe94cc759, 0x7fe0b043, 0xe4529f2e, 0x0d4dd4b2, 0x9f11a54d, 0x031e2e4e, | |
1195 | 0xe6014f5f, 0x11d1ca6c, 0x26bd7f61, 0xeb86854f, 0x4d347b57, 0x116bbe2e, 0xdba7234e, 0x7bcbfd2e, | |
1196 | 0x174dd4b2, 0x6686762e, 0xb089ba50, 0xc6258246, 0x087e767b, 0xc4a8cb4a, 0x595dba50, 0x7f0ae502, | |
1197 | 0x7b1dbd5a, 0xa0603492, 0x57d1af4b, 0x9e21ffd4, 0x6393064d, 0x7407376e, 0xe484762e, 0x122a4e53, | |
1198 | 0x4a37aa43, 0x3888a6be, 0xee77864e, 0x039c8dd5, 0x688d89af, 0x0e988f62, 0x08218246, 0xfc2f8246, | |
1199 | 0xd1d97040, 0xd64cd4b2, 0x5ae4a6b8, 0x7d0de9bc, 0x8d304d61, 0x06c5c672, 0xa4c8bd4d, 0xe0fd373b, | |
1200 | 0x575ebe4d, 0x72d26277, 0x55570f55, 0x77b154d9, 0xe214293a, 0xfc740f4b, 0xfe3f6a57, 0xa9c55f02, | |
1201 | 0xae4054db, 0x2394d918, 0xb511b24a, 0xb8741ab2, 0x0758e65e, 0xc7b5795b, 0xb0a30a4c, 0xaf7f170c, | |
1202 | 0xf3b4762e, 0x8179576d, 0x738a1581, 0x4b95b64c, 0x9829b618, 0x1bea932e, 0x7bdeaa4b, 0xcb5e0281, | |
1203 | 0x65618f54, 0x0658474b, 0x27066acf, 0x40556d65, 0x7d204d53, 0xf28bc244, 0xdce23455, 0xadc0ff54, | |
1204 | 0x3863c948, 0xcee34e5f, 0xdeb85e02, 0x2ed17a61, 0x6a7b094d, 0x7f0cfc40, 0x59603f54, 0x3220afbc, | |
1205 | 0xb5dfd962, 0x125d21c0, 0x13f8d243, 0xacfefb4e, 0x86c2c147, 0x3d8bbd59, 0xbd02a21f, 0x2593042e, | |
1206 | 0xc6a17a7c, 0x28925861, 0xb487ed44, 0xb5f4fd6d, 0x90c28a45, 0x5a14f74d, 0x43d71b4c, 0x728ebb5d, | |
1207 | 0x885bf950, 0x08134dd0, 0x38ec046e, 0xc575684b, 0x50082d2e, 0xa2f47757, 0x270f86ae, 0xf3ff6462, | |
1208 | 0x10ed3f4e, 0x4b58d462, 0xe01ce23e, 0x8c5b092e, 0x63e52f4e, 0x22c1e85d, 0xa908f54e, 0x8591624f, | |
1209 | 0x2c0fb94e, 0xa280ba3c, 0xb6f41b4c, 0x24f9aa47, 0x27201647, 0x3a3ea6dc, 0xa14fc3be, 0x3c34bdd5, | |
1210 | 0x5b8d4f5b, 0xaadeaf4b, 0xc71cab50, 0x15697a4c, 0x9a1a734c, 0x2a037d81, 0x2590bd59, 0x48ec2741, | |
1211 | 0x53489c5b, 0x7f00314b, 0x2170d362, 0xf2e92542, 0x42c10b44, 0x98f0f118, 0x883a3456, 0x099a932e, | |
1212 | 0xea38f7bc, 0x644e9247, 0xbb61b62e, 0x30e0863d, 0x5f51be54, 0x207215c7, 0x5f306c45, 0xaa7f3932, | |
1213 | 0x98da7d45, 0x4e339b59, 0x2e411581, 0xa808f618, 0xad2c0c59, 0x54476741, 0x09e99fd1, 0x5db8f752, | |
1214 | 0xc16df8bd, 0x1dd4b44f, 0x106edf2e, 0x9e15c180, 0x2ad6b56f, 0x633a5332, 0xff33787c, 0x077cb545, | |
1215 | 0x6610be6d, 0x75aad2c4, 0x72fb4d5b, 0xe81e0f59, 0x576f6332, 0x47333373, 0x351ed783, 0x2d90fb50, | |
1216 | 0x8d5e0f6c, 0x5b27a552, 0xdb293ebb, 0xe55ef950, 0x4b133ad8, 0x75df975a, 0x7b6a8740, 0xa899464b, | |
1217 | 0xfab15161, 0x10f8b64d, 0xd055ea4d, 0xee8e146b, 0x4b14afb8, 0x4bc1c44a, 0x9b961dcc, 0xd111ff43, | |
1218 | 0xfca0b745, 0xc800e412, 0x0afad9d1, 0xf751c350, 0xf9f0cccf, 0xa290a545, 0x8ef13763, 0x7ec70d59, | |
1219 | 0x2b066acf, 0x65496c45, 0xade02c1b, 0xae6eb077, 0x92c1e65b, 0xc064e6a9, 0xc649e56d, 0x5287a243, | |
1220 | 0x36de4f5b, 0x5b1df6ad, 0x65c39a59, 0xdba805b2, 0x20067aa8, 0x6457e56d, 0x3cee26cf, 0xfd3ff26d, | |
1221 | 0x04f86d4a, 0x06b8e048, 0xa93bcd5c, 0x91135852, 0xbe90a643, 0x8fa0094d, 0x06d8215f, 0x2677094d, | |
1222 | 0xd735685c, 0x164a00c9, 0x5209ac5f, 0xa9564c5c, 0x3b504f5f, 0xcc826bd0, 0x4615042e, 0x5fe13b4a, | |
1223 | 0x8c81b86d, 0x879ab68c, 0x1de564b8, 0x434487d8, 0x2dcb1b63, 0x82ab524a, 0xb0676abb, 0xa13d9c62, | |
1224 | 0xdbb5b86d, 0x5b7f4b59, 0xaddfb44d, 0xad773532, 0x3997054c, 0x72cebd89, 0xb194544c, 0xc5b8046e, | |
1225 | 0x6e1adeb2, 0xaa5abb51, 0xefb54b44, 0x15efc54f, 0xe9f1bc4d, 0x5f401b6c, 0x97f018ad, 0xc82f9252, | |
1226 | 0x2cdc762e, 0x8e52e56d, 0x1827175e, 0x9b7d7d80, 0xb2ad6845, 0x51065140, 0x71180a18, 0x5b27006c, | |
1227 | 0x0621e255, 0x721cbe58, 0x670c0cb8, 0xf8bd715d, 0xe0bdc5d9, 0xed843501, 0x4b84554d, 0x7f1a18bc, | |
1228 | 0x53bcaf47, 0x5729d35f, 0xf0dda246, 0x22382bd0, 0x4d641fb0, 0x316afcde, 0x50a22f1f, 0x73608046, | |
1229 | 0xc461d84a, 0xb2dbe247, | |
0a61b0df | 1230 | }; |
1231 | ||
1232 | ||
1233 | ||
1234 | void ThreadOpenConnections(void* parg) | |
1235 | { | |
1236 | IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg)); | |
1237 | try | |
1238 | { | |
1239 | vnThreadsRunning[1]++; | |
1240 | ThreadOpenConnections2(parg); | |
1241 | vnThreadsRunning[1]--; | |
1242 | } | |
1243 | catch (std::exception& e) { | |
1244 | vnThreadsRunning[1]--; | |
1245 | PrintException(&e, "ThreadOpenConnections()"); | |
1246 | } catch (...) { | |
1247 | vnThreadsRunning[1]--; | |
1248 | PrintException(NULL, "ThreadOpenConnections()"); | |
1249 | } | |
1250 | printf("ThreadOpenConnections exiting\n"); | |
1251 | } | |
1252 | ||
1253 | void ThreadOpenConnections2(void* parg) | |
1254 | { | |
1255 | printf("ThreadOpenConnections started\n"); | |
1256 | ||
1257 | // Connect to specific addresses | |
1258 | if (mapArgs.count("-connect")) | |
1259 | { | |
bde280b9 | 1260 | for (int64 nLoop = 0;; nLoop++) |
0a61b0df | 1261 | { |
223b6f1b | 1262 | BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"]) |
0a61b0df | 1263 | { |
c981d768 | 1264 | CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS)); |
0a61b0df | 1265 | if (addr.IsValid()) |
1266 | OpenNetworkConnection(addr); | |
1267 | for (int i = 0; i < 10 && i < nLoop; i++) | |
1268 | { | |
1269 | Sleep(500); | |
1270 | if (fShutdown) | |
1271 | return; | |
1272 | } | |
1273 | } | |
1274 | } | |
1275 | } | |
1276 | ||
0a61b0df | 1277 | // Initiate network connections |
bde280b9 | 1278 | int64 nStart = GetTime(); |
0a61b0df | 1279 | loop |
1280 | { | |
0a61b0df | 1281 | vnThreadsRunning[1]--; |
1282 | Sleep(500); | |
cc201e01 PW |
1283 | vnThreadsRunning[1]++; |
1284 | if (fShutdown) | |
1285 | return; | |
1286 | ||
1287 | // Limit outbound connections | |
0a61b0df | 1288 | loop |
1289 | { | |
1290 | int nOutbound = 0; | |
1291 | CRITICAL_BLOCK(cs_vNodes) | |
223b6f1b | 1292 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 1293 | if (!pnode->fInbound) |
1294 | nOutbound++; | |
1295 | int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS; | |
5a3e82f9 | 1296 | nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125)); |
0a61b0df | 1297 | if (nOutbound < nMaxOutboundConnections) |
1298 | break; | |
cc201e01 | 1299 | vnThreadsRunning[1]--; |
0a61b0df | 1300 | Sleep(2000); |
cc201e01 | 1301 | vnThreadsRunning[1]++; |
0a61b0df | 1302 | if (fShutdown) |
1303 | return; | |
1304 | } | |
0a61b0df | 1305 | |
a75d7066 PW |
1306 | bool fAddSeeds = false; |
1307 | ||
0a61b0df | 1308 | CRITICAL_BLOCK(cs_mapAddresses) |
1309 | { | |
1310 | // Add seed nodes if IRC isn't working | |
67a42f92 PW |
1311 | bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050); |
1312 | if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet) | |
a75d7066 PW |
1313 | fAddSeeds = true; |
1314 | } | |
1315 | ||
1316 | if (fAddSeeds) | |
1317 | { | |
1318 | for (int i = 0; i < ARRAYLEN(pnSeed); i++) | |
0a61b0df | 1319 | { |
a75d7066 PW |
1320 | // It'll only connect to one or two seed nodes because once it connects, |
1321 | // it'll get a pile of addresses with newer timestamps. | |
1322 | // Seed nodes are given a random 'last seen time' of between one and two | |
1323 | // weeks ago. | |
1324 | const int64 nOneWeek = 7*24*60*60; | |
67a42f92 PW |
1325 | struct in_addr ip; |
1326 | memcpy(&ip, &pnSeed[i], sizeof(ip)); | |
1327 | CAddress addr(CService(ip, GetDefaultPort())); | |
a75d7066 PW |
1328 | addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek; |
1329 | AddAddress(addr); | |
0a61b0df | 1330 | } |
1331 | } | |
1332 | ||
0a61b0df | 1333 | // |
1334 | // Choose an address to connect to based on most recently seen | |
1335 | // | |
1336 | CAddress addrConnect; | |
bde280b9 | 1337 | int64 nBest = std::numeric_limits<int64>::min(); |
0a61b0df | 1338 | |
1339 | // Only connect to one address per a.b.?.? range. | |
1340 | // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. | |
67a42f92 | 1341 | set<vector<unsigned char> > setConnected; |
0a61b0df | 1342 | CRITICAL_BLOCK(cs_vNodes) |
223b6f1b | 1343 | BOOST_FOREACH(CNode* pnode, vNodes) |
67a42f92 | 1344 | setConnected.insert(pnode->addr.GetGroup()); |
0a61b0df | 1345 | |
bde280b9 | 1346 | int64 nANow = GetAdjustedTime(); |
a4e6ae10 | 1347 | |
0a61b0df | 1348 | CRITICAL_BLOCK(cs_mapAddresses) |
1349 | { | |
223b6f1b | 1350 | BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses) |
0a61b0df | 1351 | { |
1352 | const CAddress& addr = item.second; | |
67a42f92 | 1353 | if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup())) |
0a61b0df | 1354 | continue; |
bde280b9 WL |
1355 | int64 nSinceLastSeen = nANow - addr.nTime; |
1356 | int64 nSinceLastTry = nANow - addr.nLastTry; | |
0a61b0df | 1357 | |
1358 | // Randomize the order in a deterministic way, putting the standard port first | |
67a42f92 PW |
1359 | int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.GetHash()) % (2 * 60 * 60); |
1360 | if (addr.GetPort() != GetDefaultPort()) | |
0a61b0df | 1361 | nRandomizer += 2 * 60 * 60; |
1362 | ||
1363 | // Last seen Base retry frequency | |
1364 | // <1 hour 10 min | |
1365 | // 1 hour 1 hour | |
1366 | // 4 hours 2 hours | |
1367 | // 24 hours 5 hours | |
1368 | // 48 hours 7 hours | |
1369 | // 7 days 13 hours | |
1370 | // 30 days 27 hours | |
1371 | // 90 days 46 hours | |
1372 | // 365 days 93 hours | |
bde280b9 | 1373 | int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer); |
0a61b0df | 1374 | |
1375 | // Fast reconnect for one hour after last seen | |
1376 | if (nSinceLastSeen < 60 * 60) | |
1377 | nDelay = 10 * 60; | |
1378 | ||
1379 | // Limit retry frequency | |
1380 | if (nSinceLastTry < nDelay) | |
1381 | continue; | |
1382 | ||
1383 | // If we have IRC, we'll be notified when they first come online, | |
1384 | // and again every 24 hours by the refresh broadcast. | |
1385 | if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60) | |
1386 | continue; | |
1387 | ||
1388 | // Only try the old stuff if we don't have enough connections | |
1389 | if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60) | |
1390 | continue; | |
1391 | ||
1392 | // If multiple addresses are ready, prioritize by time since | |
1393 | // last seen and time since last tried. | |
bde280b9 | 1394 | int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer; |
0a61b0df | 1395 | if (nScore > nBest) |
1396 | { | |
1397 | nBest = nScore; | |
1398 | addrConnect = addr; | |
1399 | } | |
1400 | } | |
1401 | } | |
1402 | ||
1403 | if (addrConnect.IsValid()) | |
1404 | OpenNetworkConnection(addrConnect); | |
1405 | } | |
1406 | } | |
1407 | ||
b24e6e4d MC |
1408 | void ThreadOpenAddedConnections(void* parg) |
1409 | { | |
1410 | IMPLEMENT_RANDOMIZE_STACK(ThreadOpenAddedConnections(parg)); | |
1411 | try | |
1412 | { | |
1413 | vnThreadsRunning[7]++; | |
1414 | ThreadOpenAddedConnections2(parg); | |
1415 | vnThreadsRunning[7]--; | |
1416 | } | |
1417 | catch (std::exception& e) { | |
1418 | vnThreadsRunning[7]--; | |
1419 | PrintException(&e, "ThreadOpenAddedConnections()"); | |
1420 | } catch (...) { | |
1421 | vnThreadsRunning[7]--; | |
1422 | PrintException(NULL, "ThreadOpenAddedConnections()"); | |
1423 | } | |
1424 | printf("ThreadOpenAddedConnections exiting\n"); | |
1425 | } | |
1426 | ||
1427 | void ThreadOpenAddedConnections2(void* parg) | |
1428 | { | |
1429 | printf("ThreadOpenAddedConnections started\n"); | |
1430 | ||
1431 | if (mapArgs.count("-addnode") == 0) | |
1432 | return; | |
1433 | ||
1434 | vector<vector<CService> > vservAddressesToAdd(0); | |
1435 | BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) | |
1436 | { | |
1437 | vector<CService> vservNode(0); | |
1438 | if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0)) | |
1439 | { | |
1440 | vservAddressesToAdd.push_back(vservNode); | |
1441 | CRITICAL_BLOCK(cs_setservAddNodeAddresses) | |
1442 | BOOST_FOREACH(CService& serv, vservNode) | |
1443 | setservAddNodeAddresses.insert(serv); | |
1444 | } | |
1445 | } | |
1446 | loop | |
1447 | { | |
1448 | vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd; | |
1449 | // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry | |
1450 | // (keeping in mind that addnode entries can have many IPs if fAllowDNS) | |
1451 | CRITICAL_BLOCK(cs_vNodes) | |
1452 | BOOST_FOREACH(CNode* pnode, vNodes) | |
1453 | for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++) | |
1454 | BOOST_FOREACH(CService& addrNode, *(it)) | |
1455 | if (pnode->addr == addrNode) | |
1456 | { | |
1457 | it = vservConnectAddresses.erase(it); | |
1458 | it--; | |
1459 | break; | |
1460 | } | |
1461 | BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses) | |
1462 | { | |
1463 | OpenNetworkConnection(CAddress(*(vserv.begin()))); | |
1464 | Sleep(500); | |
1465 | if (fShutdown) | |
1466 | return; | |
1467 | } | |
1468 | if (fShutdown) | |
1469 | return; | |
1470 | vnThreadsRunning[7]--; | |
1471 | Sleep(120000); // Retry every 2 minutes | |
1472 | vnThreadsRunning[7]++; | |
1473 | if (fShutdown) | |
1474 | return; | |
1475 | } | |
1476 | } | |
1477 | ||
0a61b0df | 1478 | bool OpenNetworkConnection(const CAddress& addrConnect) |
1479 | { | |
1480 | // | |
1481 | // Initiate outbound network connection | |
1482 | // | |
1483 | if (fShutdown) | |
1484 | return false; | |
67a42f92 PW |
1485 | if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() || |
1486 | FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect)) | |
0a61b0df | 1487 | return false; |
1488 | ||
1489 | vnThreadsRunning[1]--; | |
1490 | CNode* pnode = ConnectNode(addrConnect); | |
1491 | vnThreadsRunning[1]++; | |
1492 | if (fShutdown) | |
1493 | return false; | |
1494 | if (!pnode) | |
1495 | return false; | |
1496 | pnode->fNetworkNode = true; | |
1497 | ||
0a61b0df | 1498 | return true; |
1499 | } | |
1500 | ||
1501 | ||
1502 | ||
1503 | ||
1504 | ||
1505 | ||
1506 | ||
1507 | ||
1508 | void ThreadMessageHandler(void* parg) | |
1509 | { | |
1510 | IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg)); | |
1511 | try | |
1512 | { | |
1513 | vnThreadsRunning[2]++; | |
1514 | ThreadMessageHandler2(parg); | |
1515 | vnThreadsRunning[2]--; | |
1516 | } | |
1517 | catch (std::exception& e) { | |
1518 | vnThreadsRunning[2]--; | |
1519 | PrintException(&e, "ThreadMessageHandler()"); | |
1520 | } catch (...) { | |
1521 | vnThreadsRunning[2]--; | |
1522 | PrintException(NULL, "ThreadMessageHandler()"); | |
1523 | } | |
1524 | printf("ThreadMessageHandler exiting\n"); | |
1525 | } | |
1526 | ||
1527 | void ThreadMessageHandler2(void* parg) | |
1528 | { | |
1529 | printf("ThreadMessageHandler started\n"); | |
1530 | SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); | |
1531 | while (!fShutdown) | |
1532 | { | |
1533 | vector<CNode*> vNodesCopy; | |
1534 | CRITICAL_BLOCK(cs_vNodes) | |
1535 | { | |
1536 | vNodesCopy = vNodes; | |
223b6f1b | 1537 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 1538 | pnode->AddRef(); |
1539 | } | |
1540 | ||
1541 | // Poll the connected nodes for messages | |
1542 | CNode* pnodeTrickle = NULL; | |
1543 | if (!vNodesCopy.empty()) | |
1544 | pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())]; | |
223b6f1b | 1545 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 1546 | { |
1547 | // Receive messages | |
1548 | TRY_CRITICAL_BLOCK(pnode->cs_vRecv) | |
1549 | ProcessMessages(pnode); | |
1550 | if (fShutdown) | |
1551 | return; | |
1552 | ||
1553 | // Send messages | |
1554 | TRY_CRITICAL_BLOCK(pnode->cs_vSend) | |
1555 | SendMessages(pnode, pnode == pnodeTrickle); | |
1556 | if (fShutdown) | |
1557 | return; | |
1558 | } | |
1559 | ||
1560 | CRITICAL_BLOCK(cs_vNodes) | |
1561 | { | |
223b6f1b | 1562 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 1563 | pnode->Release(); |
1564 | } | |
1565 | ||
7629d36a | 1566 | // Wait and allow messages to bunch up. |
1567 | // Reduce vnThreadsRunning so StopNode has permission to exit while | |
1568 | // we're sleeping, but we must always check fShutdown after doing this. | |
0a61b0df | 1569 | vnThreadsRunning[2]--; |
1570 | Sleep(100); | |
3f647537 | 1571 | if (fRequestShutdown) |
1572 | Shutdown(NULL); | |
0a61b0df | 1573 | vnThreadsRunning[2]++; |
1574 | if (fShutdown) | |
1575 | return; | |
1576 | } | |
1577 | } | |
1578 | ||
1579 | ||
1580 | ||
1581 | ||
1582 | ||
1583 | ||
0a61b0df | 1584 | bool BindListenPort(string& strError) |
1585 | { | |
1586 | strError = ""; | |
1587 | int nOne = 1; | |
67a42f92 | 1588 | addrLocalHost.SetPort(GetListenPort()); |
0a61b0df | 1589 | |
6853e627 | 1590 | #ifdef WIN32 |
0a61b0df | 1591 | // Initialize Windows Sockets |
1592 | WSADATA wsadata; | |
1593 | int ret = WSAStartup(MAKEWORD(2,2), &wsadata); | |
1594 | if (ret != NO_ERROR) | |
1595 | { | |
1596 | strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret); | |
1597 | printf("%s\n", strError.c_str()); | |
1598 | return false; | |
1599 | } | |
1600 | #endif | |
1601 | ||
1602 | // Create socket for listening for incoming connections | |
1603 | hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | |
1604 | if (hListenSocket == INVALID_SOCKET) | |
1605 | { | |
1606 | strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); | |
1607 | printf("%s\n", strError.c_str()); | |
1608 | return false; | |
1609 | } | |
1610 | ||
ec93a0e2 | 1611 | #ifdef SO_NOSIGPIPE |
0a61b0df | 1612 | // Different way of disabling SIGPIPE on BSD |
1613 | setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)); | |
1614 | #endif | |
1615 | ||
6853e627 | 1616 | #ifndef WIN32 |
0a61b0df | 1617 | // Allow binding if the port is still in TIME_WAIT state after |
1618 | // the program was closed and restarted. Not an issue on windows. | |
1619 | setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); | |
1620 | #endif | |
1621 | ||
6853e627 | 1622 | #ifdef WIN32 |
0a61b0df | 1623 | // Set to nonblocking, incoming connections will also inherit this |
1624 | if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) | |
1625 | #else | |
1626 | if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) | |
1627 | #endif | |
1628 | { | |
1629 | strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError()); | |
1630 | printf("%s\n", strError.c_str()); | |
1631 | return false; | |
1632 | } | |
1633 | ||
1634 | // The sockaddr_in structure specifies the address family, | |
1635 | // IP address, and port for the socket that is being bound | |
1636 | struct sockaddr_in sockaddr; | |
1637 | memset(&sockaddr, 0, sizeof(sockaddr)); | |
1638 | sockaddr.sin_family = AF_INET; | |
1639 | sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer | |
00bcfe0b | 1640 | sockaddr.sin_port = htons(GetListenPort()); |
0a61b0df | 1641 | if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) |
1642 | { | |
1643 | int nErr = WSAGetLastError(); | |
1644 | if (nErr == WSAEADDRINUSE) | |
d9c6b09a | 1645 | strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), ntohs(sockaddr.sin_port)); |
0a61b0df | 1646 | else |
1647 | strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr); | |
1648 | printf("%s\n", strError.c_str()); | |
1649 | return false; | |
1650 | } | |
1651 | printf("Bound to port %d\n", ntohs(sockaddr.sin_port)); | |
1652 | ||
1653 | // Listen for incoming connections | |
1654 | if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) | |
1655 | { | |
1656 | strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError()); | |
1657 | printf("%s\n", strError.c_str()); | |
1658 | return false; | |
1659 | } | |
1660 | ||
1661 | return true; | |
1662 | } | |
1663 | ||
1664 | void StartNode(void* parg) | |
1665 | { | |
1666 | if (pnodeLocalHost == NULL) | |
67a42f92 | 1667 | pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); |
0a61b0df | 1668 | |
6853e627 | 1669 | #ifdef WIN32 |
0a61b0df | 1670 | // Get local host ip |
1671 | char pszHostName[1000] = ""; | |
1672 | if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) | |
1673 | { | |
67a42f92 PW |
1674 | vector<CNetAddr> vaddr; |
1675 | if (LookupHost(pszHostName, vaddr)) | |
1676 | BOOST_FOREACH (const CNetAddr &addr, vaddr) | |
1677 | if (!addr.IsLocal()) | |
0a61b0df | 1678 | { |
67a42f92 | 1679 | addrLocalHost.SetIP(addr); |
0a61b0df | 1680 | break; |
1681 | } | |
0a61b0df | 1682 | } |
1683 | #else | |
1684 | // Get local host ip | |
1685 | struct ifaddrs* myaddrs; | |
1686 | if (getifaddrs(&myaddrs) == 0) | |
1687 | { | |
1688 | for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) | |
1689 | { | |
1690 | if (ifa->ifa_addr == NULL) continue; | |
1691 | if ((ifa->ifa_flags & IFF_UP) == 0) continue; | |
1692 | if (strcmp(ifa->ifa_name, "lo") == 0) continue; | |
1693 | if (strcmp(ifa->ifa_name, "lo0") == 0) continue; | |
1694 | char pszIP[100]; | |
1695 | if (ifa->ifa_addr->sa_family == AF_INET) | |
1696 | { | |
1697 | struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr); | |
1698 | if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL) | |
1699 | printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP); | |
1700 | ||
1701 | // Take the first IP that isn't loopback 127.x.x.x | |
67a42f92 PW |
1702 | CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices); |
1703 | if (addr.IsValid() && !addr.IsLocal()) | |
0a61b0df | 1704 | { |
1705 | addrLocalHost = addr; | |
1706 | break; | |
1707 | } | |
1708 | } | |
1709 | else if (ifa->ifa_addr->sa_family == AF_INET6) | |
1710 | { | |
1711 | struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr); | |
1712 | if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL) | |
1713 | printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP); | |
1714 | } | |
1715 | } | |
1716 | freeifaddrs(myaddrs); | |
1717 | } | |
1718 | #endif | |
1719 | printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); | |
1720 | ||
5f88e888 | 1721 | if (fUseProxy || mapArgs.count("-connect") || fNoListen) |
0a61b0df | 1722 | { |
1723 | // Proxies can't take incoming connections | |
67a42f92 | 1724 | addrLocalHost.SetIP(CNetAddr("0.0.0.0")); |
0a61b0df | 1725 | printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); |
1726 | } | |
1727 | else | |
1728 | { | |
629e37dd | 1729 | CreateThread(ThreadGetMyExternalIP, NULL); |
0a61b0df | 1730 | } |
1731 | ||
1732 | // | |
1733 | // Start threads | |
1734 | // | |
1735 | ||
9d952d17 | 1736 | if (!GetBoolArg("-dnsseed", true)) |
2bc6cece MC |
1737 | printf("DNS seeding disabled\n"); |
1738 | else | |
1739 | if (!CreateThread(ThreadDNSAddressSeed, NULL)) | |
1740 | printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n"); | |
1741 | ||
8bb5edc1 MC |
1742 | // Map ports with UPnP |
1743 | if (fHaveUPnP) | |
1744 | MapPort(fUseUPnP); | |
1745 | ||
0a61b0df | 1746 | // Get addresses from IRC and advertise ours |
1747 | if (!CreateThread(ThreadIRCSeed, NULL)) | |
1748 | printf("Error: CreateThread(ThreadIRCSeed) failed\n"); | |
1749 | ||
1750 | // Send and receive from sockets, accept connections | |
65ba3e2f LD |
1751 | if (!CreateThread(ThreadSocketHandler, NULL)) |
1752 | printf("Error: CreateThread(ThreadSocketHandler) failed\n"); | |
0a61b0df | 1753 | |
b24e6e4d MC |
1754 | // Initiate outbound connections from -addnode |
1755 | if (!CreateThread(ThreadOpenAddedConnections, NULL)) | |
1756 | printf("Error: CreateThread(ThreadOpenAddedConnections) failed\n"); | |
1757 | ||
0a61b0df | 1758 | // Initiate outbound connections |
1759 | if (!CreateThread(ThreadOpenConnections, NULL)) | |
1760 | printf("Error: CreateThread(ThreadOpenConnections) failed\n"); | |
1761 | ||
1762 | // Process messages | |
1763 | if (!CreateThread(ThreadMessageHandler, NULL)) | |
1764 | printf("Error: CreateThread(ThreadMessageHandler) failed\n"); | |
1765 | ||
1766 | // Generate coins in the background | |
64c7ee7e | 1767 | GenerateBitcoins(fGenerateBitcoins, pwalletMain); |
0a61b0df | 1768 | } |
1769 | ||
1770 | bool StopNode() | |
1771 | { | |
1772 | printf("StopNode()\n"); | |
1773 | fShutdown = true; | |
1774 | nTransactionsUpdated++; | |
bde280b9 | 1775 | int64 nStart = GetTime(); |
cc201e01 | 1776 | while (vnThreadsRunning[0] > 0 || vnThreadsRunning[1] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0 |
10ba0a3e | 1777 | || (fHaveUPnP && vnThreadsRunning[5] > 0) || vnThreadsRunning[6] > 0 || vnThreadsRunning[7] > 0 |
8bb5edc1 | 1778 | ) |
0a61b0df | 1779 | { |
1780 | if (GetTime() - nStart > 20) | |
1781 | break; | |
1782 | Sleep(20); | |
1783 | } | |
1784 | if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n"); | |
1785 | if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n"); | |
1786 | if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n"); | |
1787 | if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n"); | |
1788 | if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n"); | |
8bb5edc1 | 1789 | if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n"); |
2bc6cece | 1790 | if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n"); |
b24e6e4d | 1791 | if (vnThreadsRunning[7] > 0) printf("ThreadOpenAddedConnections still running\n"); |
0a61b0df | 1792 | while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0) |
1793 | Sleep(20); | |
1794 | Sleep(50); | |
1795 | ||
1796 | return true; | |
1797 | } | |
1798 | ||
1799 | class CNetCleanup | |
1800 | { | |
1801 | public: | |
1802 | CNetCleanup() | |
1803 | { | |
1804 | } | |
1805 | ~CNetCleanup() | |
1806 | { | |
1807 | // Close sockets | |
223b6f1b | 1808 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 1809 | if (pnode->hSocket != INVALID_SOCKET) |
1810 | closesocket(pnode->hSocket); | |
1811 | if (hListenSocket != INVALID_SOCKET) | |
1812 | if (closesocket(hListenSocket) == SOCKET_ERROR) | |
1813 | printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); | |
1814 | ||
6853e627 | 1815 | #ifdef WIN32 |
0a61b0df | 1816 | // Shutdown Windows Sockets |
1817 | WSACleanup(); | |
1818 | #endif | |
1819 | } | |
1820 | } | |
1821 | instance_of_cnetcleanup; |