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