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