raw
genesis                 1 // Copyright (c) 2009-2010 Satoshi Nakamoto
genesis 2 // Copyright (c) 2009-2012 The Bitcoin developers
genesis 3 // Distributed under the MIT/X11 software license, see the accompanying
genesis 4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
genesis 5
genesis 6 #include "headers.h"
genesis 7 #include "irc.h"
genesis 8 #include "db.h"
genesis 9 #include "net.h"
genesis 10 #include "init.h"
genesis 11 #include "strlcpy.h"
genesis 12
genesis 13
genesis 14 using namespace std;
genesis 15 using namespace boost;
genesis 16
genesis 17 static const int MAX_OUTBOUND_CONNECTIONS = 8;
genesis 18
genesis 19 void ThreadMessageHandler2(void* parg);
genesis 20 void ThreadSocketHandler2(void* parg);
genesis 21 void ThreadOpenConnections2(void* parg);
genesis 22 bool OpenNetworkConnection(const CAddress& addrConnect);
genesis 23
genesis 24
genesis 25
genesis 26
genesis 27
genesis 28 //
genesis 29 // Global state variables
genesis 30 //
genesis 31 bool fClient = false;
genesis 32 bool fAllowDNS = false;
genesis 33 uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
genesis 34 CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices);
genesis 35 static CNode* pnodeLocalHost = NULL;
genesis 36 uint64 nLocalHostNonce = 0;
genesis 37 array<int, 10> vnThreadsRunning;
genesis 38 static SOCKET hListenSocket = INVALID_SOCKET;
genesis 39
genesis 40 vector<CNode*> vNodes;
genesis 41 CCriticalSection cs_vNodes;
genesis 42 map<vector<unsigned char>, CAddress> mapAddresses;
genesis 43 CCriticalSection cs_mapAddresses;
genesis 44 map<CInv, CDataStream> mapRelay;
genesis 45 deque<pair<int64, CInv> > vRelayExpiration;
genesis 46 CCriticalSection cs_mapRelay;
genesis 47 map<CInv, int64> mapAlreadyAskedFor;
genesis 48
genesis 49 // Settings
genesis 50 int fUseProxy = false;
genesis 51 int nConnectTimeout = 5000;
genesis 52 CAddress addrProxy("127.0.0.1",9050);
genesis 53
genesis 54
genesis 55
genesis 56
genesis 57 unsigned short GetListenPort()
genesis 58 {
genesis 59 return (unsigned short)(GetArg("-port", GetDefaultPort()));
genesis 60 }
genesis 61
genesis 62 void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
genesis 63 {
genesis 64 // Filter out duplicate requests
genesis 65 if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
genesis 66 return;
genesis 67 pindexLastGetBlocksBegin = pindexBegin;
genesis 68 hashLastGetBlocksEnd = hashEnd;
genesis 69
genesis 70 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
genesis 71 }
genesis 72
genesis 73
genesis 74
genesis 75
genesis 76
genesis 77 bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout)
genesis 78 {
genesis 79 hSocketRet = INVALID_SOCKET;
genesis 80
genesis 81 SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
genesis 82 if (hSocket == INVALID_SOCKET)
genesis 83 return false;
genesis 84 #ifdef SO_NOSIGPIPE
genesis 85 int set = 1;
genesis 86 setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
genesis 87 #endif
genesis 88
genesis 89 bool fProxy = (fUseProxy && addrConnect.IsRoutable());
genesis 90 struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
genesis 91
genesis 92 int fFlags = fcntl(hSocket, F_GETFL, 0);
genesis 93 if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
bitcoin-asciilife... 94
genesis 95 {
genesis 96 closesocket(hSocket);
genesis 97 return false;
genesis 98 }
genesis 99
genesis 100
genesis 101 if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
genesis 102 {
genesis 103 // WSAEINVAL is here because some legacy version of winsock uses it
genesis 104 if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
genesis 105 {
genesis 106 struct timeval timeout;
genesis 107 timeout.tv_sec = nTimeout / 1000;
genesis 108 timeout.tv_usec = (nTimeout % 1000) * 1000;
genesis 109
genesis 110 fd_set fdset;
genesis 111 FD_ZERO(&fdset);
genesis 112 FD_SET(hSocket, &fdset);
genesis 113 int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
genesis 114 if (nRet == 0)
genesis 115 {
genesis 116 printf("connection timeout\n");
genesis 117 closesocket(hSocket);
genesis 118 return false;
genesis 119 }
genesis 120 if (nRet == SOCKET_ERROR)
genesis 121 {
genesis 122 printf("select() for connection failed: %i\n",WSAGetLastError());
genesis 123 closesocket(hSocket);
genesis 124 return false;
genesis 125 }
genesis 126 socklen_t nRetSize = sizeof(nRet);
genesis 127 if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
genesis 128 {
genesis 129 printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
genesis 130 closesocket(hSocket);
genesis 131 return false;
genesis 132 }
genesis 133 if (nRet != 0)
genesis 134 {
genesis 135 printf("connect() failed after select(): %s\n",strerror(nRet));
genesis 136 closesocket(hSocket);
genesis 137 return false;
genesis 138 }
genesis 139 }
genesis 140 else
genesis 141 {
genesis 142 printf("connect() failed: %i\n",WSAGetLastError());
genesis 143 closesocket(hSocket);
genesis 144 return false;
genesis 145 }
genesis 146 }
genesis 147
genesis 148 /*
genesis 149 this isn't even strictly necessary
genesis 150 CNode::ConnectNode immediately turns the socket back to non-blocking
genesis 151 but we'll turn it back to blocking just in case
genesis 152 */
genesis 153 fFlags = fcntl(hSocket, F_GETFL, 0);
genesis 154 if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
genesis 155 {
genesis 156 closesocket(hSocket);
genesis 157 return false;
genesis 158 }
genesis 159
genesis 160 if (fProxy)
genesis 161 {
genesis 162 printf("proxy connecting %s\n", addrConnect.ToString().c_str());
genesis 163 char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
genesis 164 memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
genesis 165 memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
genesis 166 char* pszSocks4 = pszSocks4IP;
genesis 167 int nSize = sizeof(pszSocks4IP);
genesis 168
genesis 169 int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
genesis 170 if (ret != nSize)
genesis 171 {
genesis 172 closesocket(hSocket);
genesis 173 return error("Error sending to proxy");
genesis 174 }
genesis 175 char pchRet[8];
genesis 176 if (recv(hSocket, pchRet, 8, 0) != 8)
genesis 177 {
genesis 178 closesocket(hSocket);
genesis 179 return error("Error reading proxy response");
genesis 180 }
genesis 181 if (pchRet[1] != 0x5a)
genesis 182 {
genesis 183 closesocket(hSocket);
genesis 184 if (pchRet[1] != 0x5b)
genesis 185 printf("ERROR: Proxy returned error %d\n", pchRet[1]);
genesis 186 return false;
genesis 187 }
genesis 188 printf("proxy connected %s\n", addrConnect.ToString().c_str());
genesis 189 }
genesis 190
genesis 191 hSocketRet = hSocket;
genesis 192 return true;
genesis 193 }
genesis 194
genesis 195 // portDefault is in host order
genesis 196 bool Lookup(const char *pszName, vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup, int portDefault, bool fAllowPort)
genesis 197 {
genesis 198 vaddr.clear();
genesis 199 if (pszName[0] == 0)
genesis 200 return false;
genesis 201 int port = portDefault;
genesis 202 char psz[256];
genesis 203 char *pszHost = psz;
genesis 204 strlcpy(psz, pszName, sizeof(psz));
genesis 205 if (fAllowPort)
genesis 206 {
genesis 207 char* pszColon = strrchr(psz+1,':');
genesis 208 char *pszPortEnd = NULL;
genesis 209 int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
genesis 210 if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
genesis 211 {
genesis 212 if (psz[0] == '[' && pszColon[-1] == ']')
genesis 213 {
genesis 214 // Future: enable IPv6 colon-notation inside []
genesis 215 pszHost = psz+1;
genesis 216 pszColon[-1] = 0;
genesis 217 }
genesis 218 else
genesis 219 pszColon[0] = 0;
genesis 220 port = portParsed;
genesis 221 if (port < 0 || port > USHRT_MAX)
genesis 222 port = USHRT_MAX;
genesis 223 }
genesis 224 }
genesis 225
genesis 226 unsigned int addrIP = inet_addr(pszHost);
genesis 227 if (addrIP != INADDR_NONE)
genesis 228 {
genesis 229 // valid IP address passed
genesis 230 vaddr.push_back(CAddress(addrIP, port, nServices));
genesis 231 return true;
genesis 232 }
genesis 233
genesis 234 if (!fAllowLookup)
genesis 235 return false;
genesis 236
genesis 237 struct hostent* phostent = gethostbyname(pszHost);
genesis 238 if (!phostent)
genesis 239 return false;
genesis 240
genesis 241 if (phostent->h_addrtype != AF_INET)
genesis 242 return false;
genesis 243
genesis 244 char** ppAddr = phostent->h_addr_list;
genesis 245 while (*ppAddr != NULL && vaddr.size() != nMaxSolutions)
genesis 246 {
genesis 247 CAddress addr(((struct in_addr*)ppAddr[0])->s_addr, port, nServices);
genesis 248 if (addr.IsValid())
genesis 249 vaddr.push_back(addr);
genesis 250 ppAddr++;
genesis 251 }
genesis 252
genesis 253 return (vaddr.size() > 0);
genesis 254 }
genesis 255
genesis 256 // portDefault is in host order
genesis 257 bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup, int portDefault, bool fAllowPort)
genesis 258 {
genesis 259 vector<CAddress> vaddr;
genesis 260 bool fRet = Lookup(pszName, vaddr, nServices, 1, fAllowLookup, portDefault, fAllowPort);
genesis 261 if (fRet)
genesis 262 addr = vaddr[0];
genesis 263 return fRet;
genesis 264 }
genesis 265
genesis 266 bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
genesis 267 {
genesis 268 SOCKET hSocket;
genesis 269 if (!ConnectSocket(addrConnect, hSocket))
genesis 270 return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());
genesis 271
genesis 272 send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);
genesis 273
genesis 274 string strLine;
genesis 275 while (RecvLine(hSocket, strLine))
genesis 276 {
genesis 277 if (strLine.empty()) // HTTP response is separated from headers by blank line
genesis 278 {
genesis 279 loop
genesis 280 {
genesis 281 if (!RecvLine(hSocket, strLine))
genesis 282 {
genesis 283 closesocket(hSocket);
genesis 284 return false;
genesis 285 }
genesis 286 if (pszKeyword == NULL)
genesis 287 break;
genesis 288 if (strLine.find(pszKeyword) != -1)
genesis 289 {
genesis 290 strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
genesis 291 break;
genesis 292 }
genesis 293 }
genesis 294 closesocket(hSocket);
genesis 295 if (strLine.find("<") != -1)
genesis 296 strLine = strLine.substr(0, strLine.find("<"));
genesis 297 strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
genesis 298 while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
genesis 299 strLine.resize(strLine.size()-1);
genesis 300 CAddress addr(strLine,0,true);
genesis 301 printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
genesis 302 if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
genesis 303 return false;
genesis 304 ipRet = addr.ip;
genesis 305 return true;
genesis 306 }
genesis 307 }
genesis 308 closesocket(hSocket);
genesis 309 return error("GetMyExternalIP() : connection closed");
genesis 310 }
genesis 311
genesis 312 // We now get our external IP from the IRC server first and only use this as a backup
genesis 313 bool GetMyExternalIP(unsigned int& ipRet)
genesis 314 {
genesis 315 CAddress addrConnect;
genesis 316 const char* pszGet;
genesis 317 const char* pszKeyword;
genesis 318
genesis 319 if (fUseProxy)
genesis 320 return false;
genesis 321
genesis 322 for (int nLookup = 0; nLookup <= 1; nLookup++)
genesis 323 for (int nHost = 1; nHost <= 2; nHost++)
genesis 324 {
genesis 325 // We should be phasing out our use of sites like these. If we need
genesis 326 // replacements, we should ask for volunteers to put this simple
genesis 327 // php file on their webserver that prints the client IP:
genesis 328 // <?php echo $_SERVER["REMOTE_ADDR"]; ?>
genesis 329 if (nHost == 1)
genesis 330 {
genesis 331 addrConnect = CAddress("91.198.22.70",80); // checkip.dyndns.org
genesis 332
genesis 333 if (nLookup == 1)
genesis 334 {
genesis 335 CAddress addrIP("checkip.dyndns.org", 80, true);
genesis 336 if (addrIP.IsValid())
genesis 337 addrConnect = addrIP;
genesis 338 }
genesis 339
genesis 340 pszGet = "GET / HTTP/1.1\r\n"
genesis 341 "Host: checkip.dyndns.org\r\n"
genesis 342 "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
genesis 343 "Connection: close\r\n"
genesis 344 "\r\n";
genesis 345
genesis 346 pszKeyword = "Address:";
genesis 347 }
genesis 348 else if (nHost == 2)
genesis 349 {
genesis 350 addrConnect = CAddress("74.208.43.192", 80); // www.showmyip.com
genesis 351
genesis 352 if (nLookup == 1)
genesis 353 {
genesis 354 CAddress addrIP("www.showmyip.com", 80, true);
genesis 355 if (addrIP.IsValid())
genesis 356 addrConnect = addrIP;
genesis 357 }
genesis 358
genesis 359 pszGet = "GET /simple/ HTTP/1.1\r\n"
genesis 360 "Host: www.showmyip.com\r\n"
genesis 361 "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
genesis 362 "Connection: close\r\n"
genesis 363 "\r\n";
genesis 364
genesis 365 pszKeyword = NULL; // Returns just IP address
genesis 366 }
genesis 367
genesis 368 if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
genesis 369 return true;
genesis 370 }
genesis 371
genesis 372 return false;
genesis 373 }
genesis 374
genesis 375 void ThreadGetMyExternalIP(void* parg)
genesis 376 {
genesis 377 // Wait for IRC to get it first
genesis 378 if (!GetBoolArg("-noirc"))
genesis 379 {
genesis 380 for (int i = 0; i < 2 * 60; i++)
genesis 381 {
genesis 382 Sleep(1000);
genesis 383 if (fGotExternalIP || fShutdown)
genesis 384 return;
genesis 385 }
genesis 386 }
genesis 387
genesis 388 // Fallback in case IRC fails to get it
genesis 389 if (GetMyExternalIP(addrLocalHost.ip))
genesis 390 {
genesis 391 printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
genesis 392 if (addrLocalHost.IsRoutable())
genesis 393 {
genesis 394 // If we already connected to a few before we had our IP, go back and addr them.
genesis 395 // setAddrKnown automatically filters any duplicate sends.
genesis 396 CAddress addr(addrLocalHost);
genesis 397 addr.nTime = GetAdjustedTime();
genesis 398 CRITICAL_BLOCK(cs_vNodes)
genesis 399 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 400 pnode->PushAddress(addr);
genesis 401 }
genesis 402 }
genesis 403 }
genesis 404
genesis 405
genesis 406
genesis 407
genesis 408
genesis 409 bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
genesis 410 {
genesis 411 if (!addr.IsRoutable())
genesis 412 return false;
genesis 413 if (addr.ip == addrLocalHost.ip)
genesis 414 return false;
genesis 415 addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
genesis 416 bool fUpdated = false;
genesis 417 bool fNew = false;
genesis 418 CAddress addrFound = addr;
genesis 419
genesis 420 CRITICAL_BLOCK(cs_mapAddresses)
genesis 421 {
genesis 422 map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
genesis 423 if (it == mapAddresses.end())
genesis 424 {
genesis 425 // New address
genesis 426 printf("AddAddress(%s)\n", addr.ToString().c_str());
genesis 427 mapAddresses.insert(make_pair(addr.GetKey(), addr));
genesis 428 fUpdated = true;
genesis 429 fNew = true;
genesis 430 }
genesis 431 else
genesis 432 {
genesis 433 addrFound = (*it).second;
genesis 434 if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
genesis 435 {
genesis 436 // Services have been added
genesis 437 addrFound.nServices |= addr.nServices;
genesis 438 fUpdated = true;
genesis 439 }
genesis 440 bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
genesis 441 int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
genesis 442 if (addrFound.nTime < addr.nTime - nUpdateInterval)
genesis 443 {
genesis 444 // Periodically update most recently seen time
genesis 445 addrFound.nTime = addr.nTime;
genesis 446 fUpdated = true;
genesis 447 }
genesis 448 }
genesis 449 }
genesis 450 // There is a nasty deadlock bug if this is done inside the cs_mapAddresses
genesis 451 // CRITICAL_BLOCK:
genesis 452 // Thread 1: begin db transaction (locks inside-db-mutex)
genesis 453 // then AddAddress (locks cs_mapAddresses)
genesis 454 // Thread 2: AddAddress (locks cs_mapAddresses)
genesis 455 // ... then db operation hangs waiting for inside-db-mutex
genesis 456 if (fUpdated)
genesis 457 {
genesis 458 if (pAddrDB)
genesis 459 pAddrDB->WriteAddress(addrFound);
genesis 460 else
genesis 461 CAddrDB().WriteAddress(addrFound);
genesis 462 }
genesis 463 return fNew;
genesis 464 }
genesis 465
genesis 466 void AddressCurrentlyConnected(const CAddress& addr)
genesis 467 {
genesis 468 CAddress *paddrFound = NULL;
genesis 469
genesis 470 CRITICAL_BLOCK(cs_mapAddresses)
genesis 471 {
genesis 472 // Only if it's been published already
genesis 473 map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
genesis 474 if (it != mapAddresses.end())
genesis 475 paddrFound = &(*it).second;
genesis 476 }
genesis 477
genesis 478 if (paddrFound)
genesis 479 {
genesis 480 int64 nUpdateInterval = 20 * 60;
genesis 481 if (paddrFound->nTime < GetAdjustedTime() - nUpdateInterval)
genesis 482 {
genesis 483 // Periodically update most recently seen time
genesis 484 paddrFound->nTime = GetAdjustedTime();
genesis 485 CAddrDB addrdb;
genesis 486 addrdb.WriteAddress(*paddrFound);
genesis 487 }
genesis 488 }
genesis 489 }
genesis 490
genesis 491
genesis 492
genesis 493
genesis 494
genesis 495 void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
genesis 496 {
genesis 497 // If the dialog might get closed before the reply comes back,
genesis 498 // call this in the destructor so it doesn't get called after it's deleted.
genesis 499 CRITICAL_BLOCK(cs_vNodes)
genesis 500 {
genesis 501 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 502 {
genesis 503 CRITICAL_BLOCK(pnode->cs_mapRequests)
genesis 504 {
genesis 505 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
genesis 506 {
genesis 507 CRequestTracker& tracker = (*mi).second;
genesis 508 if (tracker.fn == fn && tracker.param1 == param1)
genesis 509 pnode->mapRequests.erase(mi++);
genesis 510 else
genesis 511 mi++;
genesis 512 }
genesis 513 }
genesis 514 }
genesis 515 }
genesis 516 }
genesis 517
genesis 518
genesis 519
genesis 520
genesis 521
genesis 522
genesis 523
genesis 524 //
genesis 525 // Subscription methods for the broadcast and subscription system.
genesis 526 // Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
genesis 527 //
genesis 528 // The subscription system uses a meet-in-the-middle strategy.
genesis 529 // With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
genesis 530 // subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
genesis 531 //
genesis 532
genesis 533 bool AnySubscribed(unsigned int nChannel)
genesis 534 {
genesis 535 if (pnodeLocalHost->IsSubscribed(nChannel))
genesis 536 return true;
genesis 537 CRITICAL_BLOCK(cs_vNodes)
genesis 538 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 539 if (pnode->IsSubscribed(nChannel))
genesis 540 return true;
genesis 541 return false;
genesis 542 }
genesis 543
genesis 544 bool CNode::IsSubscribed(unsigned int nChannel)
genesis 545 {
genesis 546 if (nChannel >= vfSubscribe.size())
genesis 547 return false;
genesis 548 return vfSubscribe[nChannel];
genesis 549 }
genesis 550
genesis 551 void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
genesis 552 {
genesis 553 if (nChannel >= vfSubscribe.size())
genesis 554 return;
genesis 555
genesis 556 if (!AnySubscribed(nChannel))
genesis 557 {
genesis 558 // Relay subscribe
genesis 559 CRITICAL_BLOCK(cs_vNodes)
genesis 560 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 561 if (pnode != this)
genesis 562 pnode->PushMessage("subscribe", nChannel, nHops);
genesis 563 }
genesis 564
genesis 565 vfSubscribe[nChannel] = true;
genesis 566 }
genesis 567
genesis 568 void CNode::CancelSubscribe(unsigned int nChannel)
genesis 569 {
genesis 570 if (nChannel >= vfSubscribe.size())
genesis 571 return;
genesis 572
genesis 573 // Prevent from relaying cancel if wasn't subscribed
genesis 574 if (!vfSubscribe[nChannel])
genesis 575 return;
genesis 576 vfSubscribe[nChannel] = false;
genesis 577
genesis 578 if (!AnySubscribed(nChannel))
genesis 579 {
genesis 580 // Relay subscription cancel
genesis 581 CRITICAL_BLOCK(cs_vNodes)
genesis 582 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 583 if (pnode != this)
genesis 584 pnode->PushMessage("sub-cancel", nChannel);
genesis 585 }
genesis 586 }
genesis 587
genesis 588
genesis 589
genesis 590
genesis 591
genesis 592
genesis 593
genesis 594
genesis 595
genesis 596 CNode* FindNode(unsigned int ip)
genesis 597 {
genesis 598 CRITICAL_BLOCK(cs_vNodes)
genesis 599 {
genesis 600 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 601 if (pnode->addr.ip == ip)
genesis 602 return (pnode);
genesis 603 }
genesis 604 return NULL;
genesis 605 }
genesis 606
genesis 607 CNode* FindNode(CAddress addr)
genesis 608 {
genesis 609 CRITICAL_BLOCK(cs_vNodes)
genesis 610 {
genesis 611 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 612 if (pnode->addr == addr)
genesis 613 return (pnode);
genesis 614 }
genesis 615 return NULL;
genesis 616 }
genesis 617
genesis 618 CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
genesis 619 {
genesis 620 if (addrConnect.ip == addrLocalHost.ip)
genesis 621 return NULL;
genesis 622
genesis 623 // Look for an existing connection
genesis 624 CNode* pnode = FindNode(addrConnect.ip);
genesis 625 if (pnode)
genesis 626 {
genesis 627 if (nTimeout != 0)
genesis 628 pnode->AddRef(nTimeout);
genesis 629 else
genesis 630 pnode->AddRef();
genesis 631 return pnode;
genesis 632 }
genesis 633
genesis 634 /// debug print
genesis 635 printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
genesis 636 addrConnect.ToString().c_str(),
genesis 637 (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
genesis 638 (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
genesis 639
genesis 640 CRITICAL_BLOCK(cs_mapAddresses)
genesis 641 mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
genesis 642
genesis 643 // Connect
genesis 644 SOCKET hSocket;
genesis 645 if (ConnectSocket(addrConnect, hSocket))
genesis 646 {
genesis 647 /// debug print
genesis 648 printf("connected %s\n", addrConnect.ToString().c_str());
genesis 649
genesis 650 // Set to nonblocking
genesis 651 if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
genesis 652 printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno);
genesis 653
genesis 654 // Add node
genesis 655 CNode* pnode = new CNode(hSocket, addrConnect, false);
genesis 656 if (nTimeout != 0)
genesis 657 pnode->AddRef(nTimeout);
genesis 658 else
genesis 659 pnode->AddRef();
genesis 660 CRITICAL_BLOCK(cs_vNodes)
genesis 661 vNodes.push_back(pnode);
genesis 662
genesis 663 pnode->nTimeConnected = GetTime();
genesis 664 return pnode;
genesis 665 }
genesis 666 else
genesis 667 {
genesis 668 return NULL;
genesis 669 }
genesis 670 }
genesis 671
genesis 672 void CNode::CloseSocketDisconnect()
genesis 673 {
genesis 674 fDisconnect = true;
genesis 675 if (hSocket != INVALID_SOCKET)
genesis 676 {
genesis 677 if (fDebug)
genesis 678 printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
genesis 679 printf("disconnecting node %s\n", addr.ToString().c_str());
genesis 680 closesocket(hSocket);
genesis 681 hSocket = INVALID_SOCKET;
genesis 682 }
genesis 683 }
genesis 684
genesis 685 void CNode::Cleanup()
genesis 686 {
genesis 687 // All of a nodes broadcasts and subscriptions are automatically torn down
genesis 688 // when it goes down, so a node has to stay up to keep its broadcast going.
genesis 689
genesis 690 // Cancel subscriptions
genesis 691 for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
genesis 692 if (vfSubscribe[nChannel])
genesis 693 CancelSubscribe(nChannel);
genesis 694 }
genesis 695
genesis 696
genesis 697 std::map<unsigned int, int64> CNode::setBanned;
genesis 698 CCriticalSection CNode::cs_setBanned;
genesis 699
genesis 700 void CNode::ClearBanned()
genesis 701 {
genesis 702 setBanned.clear();
genesis 703 }
genesis 704
genesis 705 bool CNode::IsBanned(unsigned int ip)
genesis 706 {
genesis 707 bool fResult = false;
genesis 708 CRITICAL_BLOCK(cs_setBanned)
genesis 709 {
genesis 710 std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
genesis 711 if (i != setBanned.end())
genesis 712 {
genesis 713 int64 t = (*i).second;
genesis 714 if (GetTime() < t)
genesis 715 fResult = true;
genesis 716 }
genesis 717 }
genesis 718 return fResult;
genesis 719 }
genesis 720
genesis 721 bool CNode::Misbehaving(int howmuch)
genesis 722 {
genesis 723 if (addr.IsLocal())
genesis 724 {
genesis 725 printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
genesis 726 return false;
genesis 727 }
genesis 728
genesis 729 nMisbehavior += howmuch;
genesis 730 if (nMisbehavior >= GetArg("-banscore", 100))
genesis 731 {
genesis 732 int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
genesis 733 CRITICAL_BLOCK(cs_setBanned)
genesis 734 if (setBanned[addr.ip] < banTime)
genesis 735 setBanned[addr.ip] = banTime;
genesis 736 CloseSocketDisconnect();
genesis 737 printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
genesis 738 return true;
genesis 739 }
genesis 740 return false;
genesis 741 }
genesis 742
genesis 743
genesis 744
genesis 745
genesis 746
genesis 747
genesis 748
genesis 749
genesis 750
genesis 751
genesis 752
genesis 753
genesis 754 void ThreadSocketHandler(void* parg)
genesis 755 {
genesis 756 IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
genesis 757 try
genesis 758 {
genesis 759 vnThreadsRunning[0]++;
genesis 760 ThreadSocketHandler2(parg);
genesis 761 vnThreadsRunning[0]--;
genesis 762 }
genesis 763 catch (std::exception& e) {
genesis 764 vnThreadsRunning[0]--;
genesis 765 PrintException(&e, "ThreadSocketHandler()");
genesis 766 } catch (...) {
genesis 767 vnThreadsRunning[0]--;
genesis 768 throw; // support pthread_cancel()
genesis 769 }
genesis 770 printf("ThreadSocketHandler exiting\n");
genesis 771 }
genesis 772
genesis 773 void ThreadSocketHandler2(void* parg)
genesis 774 {
genesis 775 printf("ThreadSocketHandler started\n");
genesis 776 list<CNode*> vNodesDisconnected;
genesis 777 int nPrevNodeCount = 0;
genesis 778
genesis 779 loop
genesis 780 {
genesis 781 //
genesis 782 // Disconnect nodes
genesis 783 //
genesis 784 CRITICAL_BLOCK(cs_vNodes)
genesis 785 {
genesis 786 // Disconnect unused nodes
genesis 787 vector<CNode*> vNodesCopy = vNodes;
genesis 788 BOOST_FOREACH(CNode* pnode, vNodesCopy)
genesis 789 {
genesis 790 if (pnode->fDisconnect ||
genesis 791 (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
genesis 792 {
genesis 793 // remove from vNodes
genesis 794 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
genesis 795
genesis 796 // close socket and cleanup
genesis 797 pnode->CloseSocketDisconnect();
genesis 798 pnode->Cleanup();
genesis 799
genesis 800 // hold in disconnected pool until all refs are released
genesis 801 pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
genesis 802 if (pnode->fNetworkNode || pnode->fInbound)
genesis 803 pnode->Release();
genesis 804 vNodesDisconnected.push_back(pnode);
genesis 805 }
genesis 806 }
genesis 807
genesis 808 // Delete disconnected nodes
genesis 809 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
genesis 810 BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
genesis 811 {
genesis 812 // wait until threads are done using it
genesis 813 if (pnode->GetRefCount() <= 0)
genesis 814 {
genesis 815 bool fDelete = false;
genesis 816 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
genesis 817 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
genesis 818 TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
genesis 819 TRY_CRITICAL_BLOCK(pnode->cs_inventory)
genesis 820 fDelete = true;
genesis 821 if (fDelete)
genesis 822 {
genesis 823 vNodesDisconnected.remove(pnode);
genesis 824 delete pnode;
genesis 825 }
genesis 826 }
genesis 827 }
genesis 828 }
genesis 829 if (vNodes.size() != nPrevNodeCount)
genesis 830 {
genesis 831 nPrevNodeCount = vNodes.size();
genesis 832 MainFrameRepaint();
genesis 833 }
genesis 834
genesis 835
genesis 836 //
genesis 837 // Find which sockets have data to receive
genesis 838 //
genesis 839 struct timeval timeout;
genesis 840 timeout.tv_sec = 0;
genesis 841 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
genesis 842
genesis 843 fd_set fdsetRecv;
genesis 844 fd_set fdsetSend;
genesis 845 fd_set fdsetError;
genesis 846 FD_ZERO(&fdsetRecv);
genesis 847 FD_ZERO(&fdsetSend);
genesis 848 FD_ZERO(&fdsetError);
genesis 849 SOCKET hSocketMax = 0;
genesis 850
genesis 851 if(hListenSocket != INVALID_SOCKET)
genesis 852 FD_SET(hListenSocket, &fdsetRecv);
genesis 853 hSocketMax = max(hSocketMax, hListenSocket);
genesis 854 CRITICAL_BLOCK(cs_vNodes)
genesis 855 {
genesis 856 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 857 {
genesis 858 if (pnode->hSocket == INVALID_SOCKET)
genesis 859 continue;
genesis 860 FD_SET(pnode->hSocket, &fdsetRecv);
genesis 861 FD_SET(pnode->hSocket, &fdsetError);
genesis 862 hSocketMax = max(hSocketMax, pnode->hSocket);
genesis 863 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
genesis 864 if (!pnode->vSend.empty())
genesis 865 FD_SET(pnode->hSocket, &fdsetSend);
genesis 866 }
genesis 867 }
genesis 868
genesis 869 vnThreadsRunning[0]--;
genesis 870 int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
genesis 871 vnThreadsRunning[0]++;
genesis 872 if (fShutdown)
genesis 873 return;
genesis 874 if (nSelect == SOCKET_ERROR)
genesis 875 {
genesis 876 int nErr = WSAGetLastError();
genesis 877 if (hSocketMax > -1)
genesis 878 {
genesis 879 printf("socket select error %d\n", nErr);
genesis 880 for (int i = 0; i <= hSocketMax; i++)
genesis 881 FD_SET(i, &fdsetRecv);
genesis 882 }
genesis 883 FD_ZERO(&fdsetSend);
genesis 884 FD_ZERO(&fdsetError);
genesis 885 Sleep(timeout.tv_usec/1000);
genesis 886 }
genesis 887
genesis 888
genesis 889 //
genesis 890 // Accept new connections
genesis 891 //
genesis 892 if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
genesis 893 {
genesis 894 struct sockaddr_in sockaddr;
genesis 895 socklen_t len = sizeof(sockaddr);
genesis 896 SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
genesis 897 CAddress addr;
genesis 898 int nInbound = 0;
genesis 899
genesis 900 if (hSocket != INVALID_SOCKET)
genesis 901 addr = CAddress(sockaddr);
genesis 902
genesis 903 CRITICAL_BLOCK(cs_vNodes)
genesis 904 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 905 if (pnode->fInbound)
genesis 906 nInbound++;
genesis 907
genesis 908 if (hSocket == INVALID_SOCKET)
genesis 909 {
genesis 910 if (WSAGetLastError() != WSAEWOULDBLOCK)
genesis 911 printf("socket error accept failed: %d\n", WSAGetLastError());
genesis 912 }
genesis 913 else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
genesis 914 {
genesis 915 closesocket(hSocket);
genesis 916 }
genesis 917 else if (CNode::IsBanned(addr.ip))
genesis 918 {
genesis 919 printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
genesis 920 closesocket(hSocket);
genesis 921 }
genesis 922 else
genesis 923 {
genesis 924 printf("accepted connection %s\n", addr.ToString().c_str());
genesis 925 CNode* pnode = new CNode(hSocket, addr, true);
genesis 926 pnode->AddRef();
genesis 927 CRITICAL_BLOCK(cs_vNodes)
genesis 928 vNodes.push_back(pnode);
genesis 929 }
genesis 930 }
genesis 931
genesis 932
genesis 933 //
genesis 934 // Service each socket
genesis 935 //
genesis 936 vector<CNode*> vNodesCopy;
genesis 937 CRITICAL_BLOCK(cs_vNodes)
genesis 938 {
genesis 939 vNodesCopy = vNodes;
genesis 940 BOOST_FOREACH(CNode* pnode, vNodesCopy)
genesis 941 pnode->AddRef();
genesis 942 }
genesis 943 BOOST_FOREACH(CNode* pnode, vNodesCopy)
genesis 944 {
genesis 945 if (fShutdown)
genesis 946 return;
genesis 947
genesis 948 //
genesis 949 // Receive
genesis 950 //
genesis 951 if (pnode->hSocket == INVALID_SOCKET)
genesis 952 continue;
genesis 953 if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
genesis 954 {
genesis 955 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
genesis 956 {
genesis 957 CDataStream& vRecv = pnode->vRecv;
genesis 958 unsigned int nPos = vRecv.size();
genesis 959
genesis 960 if (nPos > ReceiveBufferSize()) {
genesis 961 if (!pnode->fDisconnect)
genesis 962 printf("socket recv flood control disconnect (%d bytes)\n", vRecv.size());
genesis 963 pnode->CloseSocketDisconnect();
genesis 964 }
genesis 965 else {
genesis 966 // typical socket buffer is 8K-64K
genesis 967 char pchBuf[0x10000];
genesis 968 int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
genesis 969 if (nBytes > 0)
genesis 970 {
genesis 971 vRecv.resize(nPos + nBytes);
genesis 972 memcpy(&vRecv[nPos], pchBuf, nBytes);
genesis 973 pnode->nLastRecv = GetTime();
genesis 974 }
genesis 975 else if (nBytes == 0)
genesis 976 {
genesis 977 // socket closed gracefully
genesis 978 if (!pnode->fDisconnect)
genesis 979 printf("socket closed\n");
genesis 980 pnode->CloseSocketDisconnect();
genesis 981 }
genesis 982 else if (nBytes < 0)
genesis 983 {
genesis 984 // error
genesis 985 int nErr = WSAGetLastError();
genesis 986 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
genesis 987 {
genesis 988 if (!pnode->fDisconnect)
genesis 989 printf("socket recv error %d\n", nErr);
genesis 990 pnode->CloseSocketDisconnect();
genesis 991 }
genesis 992 }
genesis 993 }
genesis 994 }
genesis 995 }
genesis 996
genesis 997 //
genesis 998 // Send
genesis 999 //
genesis 1000 if (pnode->hSocket == INVALID_SOCKET)
genesis 1001 continue;
genesis 1002 if (FD_ISSET(pnode->hSocket, &fdsetSend))
genesis 1003 {
genesis 1004 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
genesis 1005 {
genesis 1006 CDataStream& vSend = pnode->vSend;
genesis 1007 if (!vSend.empty())
genesis 1008 {
genesis 1009 int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
genesis 1010 if (nBytes > 0)
genesis 1011 {
genesis 1012 vSend.erase(vSend.begin(), vSend.begin() + nBytes);
genesis 1013 pnode->nLastSend = GetTime();
genesis 1014 }
genesis 1015 else if (nBytes < 0)
genesis 1016 {
genesis 1017 // error
genesis 1018 int nErr = WSAGetLastError();
genesis 1019 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
genesis 1020 {
genesis 1021 printf("socket send error %d\n", nErr);
genesis 1022 pnode->CloseSocketDisconnect();
genesis 1023 }
genesis 1024 }
genesis 1025 if (vSend.size() > SendBufferSize()) {
genesis 1026 if (!pnode->fDisconnect)
genesis 1027 printf("socket send flood control disconnect (%d bytes)\n", vSend.size());
genesis 1028 pnode->CloseSocketDisconnect();
genesis 1029 }
genesis 1030 }
genesis 1031 }
genesis 1032 }
genesis 1033
genesis 1034 //
genesis 1035 // Inactivity checking
genesis 1036 //
genesis 1037 if (pnode->vSend.empty())
genesis 1038 pnode->nLastSendEmpty = GetTime();
genesis 1039 if (GetTime() - pnode->nTimeConnected > 60)
genesis 1040 {
genesis 1041 if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
genesis 1042 {
genesis 1043 printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
genesis 1044 pnode->fDisconnect = true;
genesis 1045 }
genesis 1046 else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
genesis 1047 {
genesis 1048 printf("socket not sending\n");
genesis 1049 pnode->fDisconnect = true;
genesis 1050 }
genesis 1051 else if (GetTime() - pnode->nLastRecv > 90*60)
genesis 1052 {
genesis 1053 printf("socket inactivity timeout\n");
genesis 1054 pnode->fDisconnect = true;
genesis 1055 }
genesis 1056 }
genesis 1057 }
genesis 1058 CRITICAL_BLOCK(cs_vNodes)
genesis 1059 {
genesis 1060 BOOST_FOREACH(CNode* pnode, vNodesCopy)
genesis 1061 pnode->Release();
genesis 1062 }
genesis 1063
genesis 1064 Sleep(10);
genesis 1065 }
genesis 1066 }
genesis 1067
genesis 1068
genesis 1069 void ThreadOpenConnections(void* parg)
genesis 1070 {
genesis 1071 IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
genesis 1072 try
genesis 1073 {
genesis 1074 vnThreadsRunning[1]++;
genesis 1075 ThreadOpenConnections2(parg);
genesis 1076 vnThreadsRunning[1]--;
genesis 1077 }
genesis 1078 catch (std::exception& e) {
genesis 1079 vnThreadsRunning[1]--;
genesis 1080 PrintException(&e, "ThreadOpenConnections()");
genesis 1081 } catch (...) {
genesis 1082 vnThreadsRunning[1]--;
genesis 1083 PrintException(NULL, "ThreadOpenConnections()");
genesis 1084 }
genesis 1085 printf("ThreadOpenConnections exiting\n");
genesis 1086 }
genesis 1087
genesis 1088 void ThreadOpenConnections2(void* parg)
genesis 1089 {
genesis 1090 printf("ThreadOpenConnections started\n");
genesis 1091
genesis 1092 // Connect to specific addresses
genesis 1093 if (mapArgs.count("-connect"))
genesis 1094 {
genesis 1095 for (int64 nLoop = 0;; nLoop++)
genesis 1096 {
genesis 1097 BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
genesis 1098 {
genesis 1099 CAddress addr(strAddr, fAllowDNS);
genesis 1100 if (addr.IsValid())
genesis 1101 OpenNetworkConnection(addr);
genesis 1102 for (int i = 0; i < 10 && i < nLoop; i++)
genesis 1103 {
genesis 1104 Sleep(500);
genesis 1105 if (fShutdown)
genesis 1106 return;
genesis 1107 }
genesis 1108 }
genesis 1109 }
genesis 1110 }
genesis 1111
genesis 1112 // Connect to manually added nodes first
genesis 1113 if (mapArgs.count("-addnode"))
genesis 1114 {
genesis 1115 BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
genesis 1116 {
genesis 1117 CAddress addr(strAddr, fAllowDNS);
genesis 1118 if (addr.IsValid())
genesis 1119 {
genesis 1120 OpenNetworkConnection(addr);
genesis 1121 Sleep(500);
genesis 1122 if (fShutdown)
genesis 1123 return;
genesis 1124 }
genesis 1125 }
genesis 1126 }
genesis 1127
genesis 1128 // Initiate network connections
genesis 1129 int64 nStart = GetTime();
genesis 1130 loop
genesis 1131 {
genesis 1132 vnThreadsRunning[1]--;
genesis 1133 Sleep(500);
genesis 1134 vnThreadsRunning[1]++;
genesis 1135 if (fShutdown)
genesis 1136 return;
genesis 1137
genesis 1138 // Limit outbound connections
genesis 1139 loop
genesis 1140 {
genesis 1141 int nOutbound = 0;
genesis 1142 CRITICAL_BLOCK(cs_vNodes)
genesis 1143 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 1144 if (!pnode->fInbound)
genesis 1145 nOutbound++;
genesis 1146 int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
genesis 1147 nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125));
genesis 1148 if (nOutbound < nMaxOutboundConnections)
genesis 1149 break;
genesis 1150 vnThreadsRunning[1]--;
genesis 1151 Sleep(2000);
genesis 1152 vnThreadsRunning[1]++;
genesis 1153 if (fShutdown)
genesis 1154 return;
genesis 1155 }
genesis 1156
genesis 1157 //
genesis 1158 // Choose an address to connect to based on most recently seen
genesis 1159 //
genesis 1160 CAddress addrConnect;
genesis 1161 int64 nBest = INT64_MIN;
genesis 1162
genesis 1163 // Only connect to one address per a.b.?.? range.
genesis 1164 // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
genesis 1165 set<unsigned int> setConnected;
genesis 1166 CRITICAL_BLOCK(cs_vNodes)
genesis 1167 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 1168 setConnected.insert(pnode->addr.ip & 0x0000ffff);
genesis 1169
genesis 1170 int64 nANow = GetAdjustedTime();
genesis 1171
genesis 1172 CRITICAL_BLOCK(cs_mapAddresses)
genesis 1173 {
genesis 1174 BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
genesis 1175 {
genesis 1176 const CAddress& addr = item.second;
genesis 1177 if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
genesis 1178 continue;
genesis 1179 int64 nSinceLastSeen = nANow - addr.nTime;
genesis 1180 int64 nSinceLastTry = nANow - addr.nLastTry;
genesis 1181
genesis 1182 // Randomize the order in a deterministic way, putting the standard port first
genesis 1183 int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
genesis 1184 if (addr.port != htons(GetDefaultPort()))
genesis 1185 nRandomizer += 2 * 60 * 60;
genesis 1186
genesis 1187 // Last seen Base retry frequency
genesis 1188 // <1 hour 10 min
genesis 1189 // 1 hour 1 hour
genesis 1190 // 4 hours 2 hours
genesis 1191 // 24 hours 5 hours
genesis 1192 // 48 hours 7 hours
genesis 1193 // 7 days 13 hours
genesis 1194 // 30 days 27 hours
genesis 1195 // 90 days 46 hours
genesis 1196 // 365 days 93 hours
genesis 1197 int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
genesis 1198
genesis 1199 // Fast reconnect for one hour after last seen
genesis 1200 if (nSinceLastSeen < 60 * 60)
genesis 1201 nDelay = 10 * 60;
genesis 1202
genesis 1203 // Limit retry frequency
genesis 1204 if (nSinceLastTry < nDelay)
genesis 1205 continue;
genesis 1206
genesis 1207 // If we have IRC, we'll be notified when they first come online,
genesis 1208 // and again every 24 hours by the refresh broadcast.
genesis 1209 if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
genesis 1210 continue;
genesis 1211
genesis 1212 // Only try the old stuff if we don't have enough connections
genesis 1213 if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
genesis 1214 continue;
genesis 1215
genesis 1216 // If multiple addresses are ready, prioritize by time since
genesis 1217 // last seen and time since last tried.
genesis 1218 int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
genesis 1219 if (nScore > nBest)
genesis 1220 {
genesis 1221 nBest = nScore;
genesis 1222 addrConnect = addr;
genesis 1223 }
genesis 1224 }
genesis 1225 }
genesis 1226
genesis 1227 if (addrConnect.IsValid())
genesis 1228 OpenNetworkConnection(addrConnect);
genesis 1229 }
genesis 1230 }
genesis 1231
genesis 1232 bool OpenNetworkConnection(const CAddress& addrConnect)
genesis 1233 {
genesis 1234 //
genesis 1235 // Initiate outbound network connection
genesis 1236 //
genesis 1237 if (fShutdown)
genesis 1238 return false;
genesis 1239 if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
genesis 1240 FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
genesis 1241 return false;
genesis 1242
genesis 1243 vnThreadsRunning[1]--;
genesis 1244 CNode* pnode = ConnectNode(addrConnect);
genesis 1245 vnThreadsRunning[1]++;
genesis 1246 if (fShutdown)
genesis 1247 return false;
genesis 1248 if (!pnode)
genesis 1249 return false;
genesis 1250 pnode->fNetworkNode = true;
genesis 1251
genesis 1252 return true;
genesis 1253 }
genesis 1254
genesis 1255
genesis 1256
genesis 1257
genesis 1258
genesis 1259
genesis 1260
genesis 1261
genesis 1262 void ThreadMessageHandler(void* parg)
genesis 1263 {
genesis 1264 IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
genesis 1265 try
genesis 1266 {
genesis 1267 vnThreadsRunning[2]++;
genesis 1268 ThreadMessageHandler2(parg);
genesis 1269 vnThreadsRunning[2]--;
genesis 1270 }
genesis 1271 catch (std::exception& e) {
genesis 1272 vnThreadsRunning[2]--;
genesis 1273 PrintException(&e, "ThreadMessageHandler()");
genesis 1274 } catch (...) {
genesis 1275 vnThreadsRunning[2]--;
genesis 1276 PrintException(NULL, "ThreadMessageHandler()");
genesis 1277 }
genesis 1278 printf("ThreadMessageHandler exiting\n");
genesis 1279 }
genesis 1280
genesis 1281 void ThreadMessageHandler2(void* parg)
genesis 1282 {
genesis 1283 printf("ThreadMessageHandler started\n");
genesis 1284 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
genesis 1285 while (!fShutdown)
genesis 1286 {
genesis 1287 vector<CNode*> vNodesCopy;
genesis 1288 CRITICAL_BLOCK(cs_vNodes)
genesis 1289 {
genesis 1290 vNodesCopy = vNodes;
genesis 1291 BOOST_FOREACH(CNode* pnode, vNodesCopy)
genesis 1292 pnode->AddRef();
genesis 1293 }
genesis 1294
genesis 1295 // Poll the connected nodes for messages
genesis 1296 CNode* pnodeTrickle = NULL;
genesis 1297 if (!vNodesCopy.empty())
genesis 1298 pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
genesis 1299 BOOST_FOREACH(CNode* pnode, vNodesCopy)
genesis 1300 {
genesis 1301 // Receive messages
genesis 1302 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
genesis 1303 ProcessMessages(pnode);
genesis 1304 if (fShutdown)
genesis 1305 return;
genesis 1306
genesis 1307 // Send messages
genesis 1308 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
genesis 1309 SendMessages(pnode, pnode == pnodeTrickle);
genesis 1310 if (fShutdown)
genesis 1311 return;
genesis 1312 }
genesis 1313
genesis 1314 CRITICAL_BLOCK(cs_vNodes)
genesis 1315 {
genesis 1316 BOOST_FOREACH(CNode* pnode, vNodesCopy)
genesis 1317 pnode->Release();
genesis 1318 }
genesis 1319
genesis 1320 // Wait and allow messages to bunch up.
genesis 1321 // Reduce vnThreadsRunning so StopNode has permission to exit while
genesis 1322 // we're sleeping, but we must always check fShutdown after doing this.
genesis 1323 vnThreadsRunning[2]--;
genesis 1324 Sleep(100);
genesis 1325 if (fRequestShutdown)
genesis 1326 Shutdown(NULL);
genesis 1327 vnThreadsRunning[2]++;
genesis 1328 if (fShutdown)
genesis 1329 return;
genesis 1330 }
genesis 1331 }
genesis 1332
genesis 1333
genesis 1334
genesis 1335
genesis 1336
genesis 1337
genesis 1338 bool BindListenPort(string& strError)
genesis 1339 {
genesis 1340 strError = "";
genesis 1341 int nOne = 1;
genesis 1342 addrLocalHost.port = htons(GetListenPort());
genesis 1343
genesis 1344 // Create socket for listening for incoming connections
genesis 1345 hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
genesis 1346 if (hListenSocket == INVALID_SOCKET)
genesis 1347 {
genesis 1348 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
genesis 1349 printf("%s\n", strError.c_str());
genesis 1350 return false;
genesis 1351 }
genesis 1352
genesis 1353 #ifdef SO_NOSIGPIPE
genesis 1354 // Different way of disabling SIGPIPE on BSD
genesis 1355 setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
genesis 1356 #endif
genesis 1357
genesis 1358 // Allow binding if the port is still in TIME_WAIT state after
genesis 1359 // the program was closed and restarted. Not an issue on windows.
genesis 1360 setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
genesis 1361
genesis 1362 if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
genesis 1363 {
genesis 1364 strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
genesis 1365 printf("%s\n", strError.c_str());
genesis 1366 return false;
genesis 1367 }
genesis 1368
genesis 1369 // The sockaddr_in structure specifies the address family,
genesis 1370 // IP address, and port for the socket that is being bound
genesis 1371 struct sockaddr_in sockaddr;
genesis 1372 memset(&sockaddr, 0, sizeof(sockaddr));
genesis 1373 sockaddr.sin_family = AF_INET;
genesis 1374 sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
genesis 1375 sockaddr.sin_port = htons(GetListenPort());
genesis 1376 if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
genesis 1377 {
genesis 1378 int nErr = WSAGetLastError();
genesis 1379 if (nErr == WSAEADDRINUSE)
genesis 1380 strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), ntohs(sockaddr.sin_port));
genesis 1381 else
genesis 1382 strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
genesis 1383 printf("%s\n", strError.c_str());
genesis 1384 return false;
genesis 1385 }
genesis 1386 printf("Bound to port %d\n", ntohs(sockaddr.sin_port));
genesis 1387
genesis 1388 // Listen for incoming connections
genesis 1389 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
genesis 1390 {
genesis 1391 strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
genesis 1392 printf("%s\n", strError.c_str());
genesis 1393 return false;
genesis 1394 }
genesis 1395
genesis 1396 return true;
genesis 1397 }
genesis 1398
genesis 1399 void StartNode(void* parg)
genesis 1400 {
genesis 1401 if (pnodeLocalHost == NULL)
genesis 1402 pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
genesis 1403
genesis 1404 // Get local host ip
genesis 1405 struct ifaddrs* myaddrs;
genesis 1406 if (getifaddrs(&myaddrs) == 0)
genesis 1407 {
genesis 1408 for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
genesis 1409 {
genesis 1410 if (ifa->ifa_addr == NULL) continue;
genesis 1411 if ((ifa->ifa_flags & IFF_UP) == 0) continue;
genesis 1412 if (strcmp(ifa->ifa_name, "lo") == 0) continue;
genesis 1413 if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
genesis 1414 char pszIP[100];
genesis 1415 if (ifa->ifa_addr->sa_family == AF_INET)
genesis 1416 {
genesis 1417 struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
genesis 1418 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
genesis 1419 printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
genesis 1420
genesis 1421 // Take the first IP that isn't loopback 127.x.x.x
genesis 1422 CAddress addr(*(unsigned int*)&s4->sin_addr, GetListenPort(), nLocalServices);
genesis 1423 if (addr.IsValid() && addr.GetByte(3) != 127)
genesis 1424 {
genesis 1425 addrLocalHost = addr;
genesis 1426 break;
genesis 1427 }
genesis 1428 }
genesis 1429 else if (ifa->ifa_addr->sa_family == AF_INET6)
genesis 1430 {
genesis 1431 struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
genesis 1432 if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
genesis 1433 printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
genesis 1434 }
genesis 1435 }
genesis 1436 freeifaddrs(myaddrs);
genesis 1437 }
bitcoin-asciilife... 1438
genesis 1439 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
genesis 1440
genesis 1441 if (fUseProxy || mapArgs.count("-connect") || fNoListen)
genesis 1442 {
genesis 1443 // Proxies can't take incoming connections
genesis 1444 addrLocalHost.ip = CAddress("0.0.0.0").ip;
genesis 1445 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
genesis 1446 }
genesis 1447 else
genesis 1448 {
genesis 1449 CreateThread(ThreadGetMyExternalIP, NULL);
genesis 1450 }
genesis 1451
genesis 1452 //
genesis 1453 // Start threads
genesis 1454 //
genesis 1455
genesis 1456 // Get addresses from IRC and advertise ours
genesis 1457 if (!CreateThread(ThreadIRCSeed, NULL))
genesis 1458 printf("Error: CreateThread(ThreadIRCSeed) failed\n");
genesis 1459
genesis 1460 // Send and receive from sockets, accept connections
genesis 1461 if (!CreateThread(ThreadSocketHandler, NULL))
genesis 1462 printf("Error: CreateThread(ThreadSocketHandler) failed\n");
genesis 1463
genesis 1464 // Initiate outbound connections
genesis 1465 if (!CreateThread(ThreadOpenConnections, NULL))
genesis 1466 printf("Error: CreateThread(ThreadOpenConnections) failed\n");
genesis 1467
genesis 1468 // Process messages
genesis 1469 if (!CreateThread(ThreadMessageHandler, NULL))
genesis 1470 printf("Error: CreateThread(ThreadMessageHandler) failed\n");
genesis 1471
genesis 1472 // Generate coins in the background
genesis 1473 GenerateBitcoins(fGenerateBitcoins, pwalletMain);
genesis 1474 }
genesis 1475
genesis 1476 bool StopNode()
genesis 1477 {
genesis 1478 printf("StopNode()\n");
genesis 1479 fShutdown = true;
genesis 1480 nTransactionsUpdated++;
genesis 1481 int64 nStart = GetTime();
genesis 1482 while (vnThreadsRunning[0] > 0 || vnThreadsRunning[1] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0
genesis 1483 )
genesis 1484 {
genesis 1485 if (GetTime() - nStart > 20)
genesis 1486 break;
genesis 1487 Sleep(20);
genesis 1488 }
genesis 1489 if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
genesis 1490 if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
genesis 1491 if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
genesis 1492 if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
genesis 1493 if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
genesis 1494 while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
genesis 1495 Sleep(20);
genesis 1496 Sleep(50);
genesis 1497
genesis 1498 return true;
genesis 1499 }
genesis 1500
genesis 1501 class CNetCleanup
genesis 1502 {
genesis 1503 public:
genesis 1504 CNetCleanup()
genesis 1505 {
genesis 1506 }
genesis 1507 ~CNetCleanup()
genesis 1508 {
genesis 1509 // Close sockets
genesis 1510 BOOST_FOREACH(CNode* pnode, vNodes)
genesis 1511 if (pnode->hSocket != INVALID_SOCKET)
genesis 1512 closesocket(pnode->hSocket);
genesis 1513 if (hListenSocket != INVALID_SOCKET)
genesis 1514 if (closesocket(hListenSocket) == SOCKET_ERROR)
genesis 1515 printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
genesis 1516
genesis 1517 }
genesis 1518 }
genesis 1519 instance_of_cnetcleanup;