diff options
| author | Bitflash-sh <btf01@proton.me> | 2026-07-24 11:18:11 -0300 |
|---|---|---|
| committer | Bitflash-sh <btf01@proton.me> | 2026-07-24 11:18:11 -0300 |
| commit | 51d617e70f90a972185917ea0096c1ecef2bfa8b (patch) | |
| tree | 9fbbcd867de9de9d0776afdd02f594ba312c46eb /src/net.h | |
Bitflash: fair-launch release
Satoshi's bitcoin-0.1.0 reborn with RandomX CPU proof of work, anonymous .btf
addressing over Nostr with CGNAT rendezvous, automatic peer discovery, a
headless Linux node, and Windows GUI wallet. Fair launch, no premine, 21M cap.
Diffstat (limited to 'src/net.h')
| -rw-r--r-- | src/net.h | 863 |
1 files changed, 863 insertions, 0 deletions
diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..6e62126 --- /dev/null +++ b/src/net.h | |||
| @@ -0,0 +1,863 @@ | |||
| 1 | // Copyright (c) 2009 Satoshi Nakamoto | ||
| 2 | // Distributed under the MIT/X11 software license, see the accompanying | ||
| 3 | // file license.txt or http://www.opensource.org/licenses/mit-license.php. | ||
| 4 | |||
| 5 | class CMessageHeader; | ||
| 6 | class CAddress; | ||
| 7 | class CInv; | ||
| 8 | class CRequestTracker; | ||
| 9 | class CNode; | ||
| 10 | |||
| 11 | |||
| 12 | |||
| 13 | static const unsigned short DEFAULT_PORT = htons(8433); | ||
| 14 | static const unsigned int PUBLISH_HOPS = 5; | ||
| 15 | enum | ||
| 16 | { | ||
| 17 | NODE_NETWORK = (1 << 0), | ||
| 18 | }; | ||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet); | ||
| 26 | bool GetMyExternalIP(unsigned int& ipRet); | ||
| 27 | bool AddAddress(CAddrDB& addrdb, const CAddress& addr); | ||
| 28 | CNode* FindNode(unsigned int ip); | ||
| 29 | CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0); | ||
| 30 | CNode* ConnectNodeBtf(const string& strBtfAddr); | ||
| 31 | void ThreadBtfAccept(void* parg); | ||
| 32 | void ThreadBtfConnect(void* parg); | ||
| 33 | extern string strBtfConnect; | ||
| 34 | void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); | ||
| 35 | bool AnySubscribed(unsigned int nChannel); | ||
| 36 | void ThreadBitcoinMiner(void* parg); | ||
| 37 | bool StartNode(string& strError=REF(string())); | ||
| 38 | bool StopNode(); | ||
| 39 | void CheckForShutdown(int n); | ||
| 40 | |||
| 41 | |||
| 42 | |||
| 43 | |||
| 44 | |||
| 45 | |||
| 46 | |||
| 47 | |||
| 48 | |||
| 49 | // | ||
| 50 | // Message header | ||
| 51 | // (4) message start | ||
| 52 | // (12) command | ||
| 53 | // (4) size | ||
| 54 | |||
| 55 | // The message start string is designed to be unlikely to occur in normal data. | ||
| 56 | // The characters are rarely used upper ascii, not valid as UTF-8, and produce | ||
| 57 | // a large 4-byte int at any alignment. | ||
| 58 | // Magic bytes unique to the Bitflash network (0xbf = "BF"). Second byte bumped | ||
| 59 | // to 0x20 for the 2026 stable relaunch so the old test chain can't interfere. | ||
| 60 | static const char pchMessageStart[4] = { 0xbf, 0x20, 0x5c, 0xfd }; | ||
| 61 | |||
| 62 | class CMessageHeader | ||
| 63 | { | ||
| 64 | public: | ||
| 65 | enum { COMMAND_SIZE=12 }; | ||
| 66 | char pchMessageStart[sizeof(::pchMessageStart)]; | ||
| 67 | char pchCommand[COMMAND_SIZE]; | ||
| 68 | unsigned int nMessageSize; | ||
| 69 | |||
| 70 | CMessageHeader() | ||
| 71 | { | ||
| 72 | memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); | ||
| 73 | memset(pchCommand, 0, sizeof(pchCommand)); | ||
| 74 | pchCommand[1] = 1; | ||
| 75 | nMessageSize = -1; | ||
| 76 | } | ||
| 77 | |||
| 78 | CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) | ||
| 79 | { | ||
| 80 | memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); | ||
| 81 | strncpy(pchCommand, pszCommand, COMMAND_SIZE); | ||
| 82 | nMessageSize = nMessageSizeIn; | ||
| 83 | } | ||
| 84 | |||
| 85 | IMPLEMENT_SERIALIZE | ||
| 86 | ( | ||
| 87 | READWRITE(FLATDATA(pchMessageStart)); | ||
| 88 | READWRITE(FLATDATA(pchCommand)); | ||
| 89 | READWRITE(nMessageSize); | ||
| 90 | ) | ||
| 91 | |||
| 92 | string GetCommand() | ||
| 93 | { | ||
| 94 | if (pchCommand[COMMAND_SIZE-1] == 0) | ||
| 95 | return string(pchCommand, pchCommand + strlen(pchCommand)); | ||
| 96 | else | ||
| 97 | return string(pchCommand, pchCommand + COMMAND_SIZE); | ||
| 98 | } | ||
| 99 | |||
| 100 | bool IsValid() | ||
| 101 | { | ||
| 102 | // Check start string | ||
| 103 | if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0) | ||
| 104 | return false; | ||
| 105 | |||
| 106 | // Check the command string for errors | ||
| 107 | for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++) | ||
| 108 | { | ||
| 109 | if (*p1 == 0) | ||
| 110 | { | ||
| 111 | // Must be all zeros after the first zero | ||
| 112 | for (; p1 < pchCommand + COMMAND_SIZE; p1++) | ||
| 113 | if (*p1 != 0) | ||
| 114 | return false; | ||
| 115 | } | ||
| 116 | else if (*p1 < ' ' || *p1 > 0x7E) | ||
| 117 | return false; | ||
| 118 | } | ||
| 119 | |||
| 120 | // Message size | ||
| 121 | if (nMessageSize > 0x10000000) | ||
| 122 | { | ||
| 123 | printf("CMessageHeader::IsValid() : nMessageSize too large %u\n", nMessageSize); | ||
| 124 | return false; | ||
| 125 | } | ||
| 126 | |||
| 127 | return true; | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | |||
| 131 | |||
| 132 | |||
| 133 | |||
| 134 | |||
| 135 | |||
| 136 | static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; | ||
| 137 | |||
| 138 | class CAddress | ||
| 139 | { | ||
| 140 | public: | ||
| 141 | uint64 nServices; | ||
| 142 | unsigned char pchReserved[12]; | ||
| 143 | unsigned int ip; | ||
| 144 | unsigned short port; | ||
| 145 | |||
| 146 | // disk only | ||
| 147 | unsigned int nTime; | ||
| 148 | |||
| 149 | // memory only | ||
| 150 | unsigned int nLastFailed; | ||
| 151 | |||
| 152 | CAddress() | ||
| 153 | { | ||
| 154 | nServices = 0; | ||
| 155 | memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); | ||
| 156 | ip = 0; | ||
| 157 | port = DEFAULT_PORT; | ||
| 158 | nTime = GetAdjustedTime(); | ||
| 159 | nLastFailed = 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | CAddress(unsigned int ipIn, unsigned short portIn, uint64 nServicesIn=0) | ||
| 163 | { | ||
| 164 | nServices = nServicesIn; | ||
| 165 | memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); | ||
| 166 | ip = ipIn; | ||
| 167 | port = portIn; | ||
| 168 | nTime = GetAdjustedTime(); | ||
| 169 | nLastFailed = 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=0) | ||
| 173 | { | ||
| 174 | nServices = nServicesIn; | ||
| 175 | memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); | ||
| 176 | ip = sockaddr.sin_addr.s_addr; | ||
| 177 | port = sockaddr.sin_port; | ||
| 178 | nTime = GetAdjustedTime(); | ||
| 179 | nLastFailed = 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | explicit CAddress(const char* pszIn, uint64 nServicesIn=0) | ||
| 183 | { | ||
| 184 | nServices = nServicesIn; | ||
| 185 | memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); | ||
| 186 | ip = 0; | ||
| 187 | port = DEFAULT_PORT; | ||
| 188 | nTime = GetAdjustedTime(); | ||
| 189 | nLastFailed = 0; | ||
| 190 | |||
| 191 | char psz[100]; | ||
| 192 | if (strlen(pszIn) > ARRAYLEN(psz)-1) | ||
| 193 | return; | ||
| 194 | strcpy(psz, pszIn); | ||
| 195 | unsigned int a, b, c, d, e; | ||
| 196 | if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4) | ||
| 197 | return; | ||
| 198 | char* pszPort = strchr(psz, ':'); | ||
| 199 | if (pszPort) | ||
| 200 | { | ||
| 201 | *pszPort++ = '\0'; | ||
| 202 | port = htons(atoi(pszPort)); | ||
| 203 | } | ||
| 204 | ip = inet_addr(psz); | ||
| 205 | } | ||
| 206 | |||
| 207 | IMPLEMENT_SERIALIZE | ||
| 208 | ( | ||
| 209 | if (nType & SER_DISK) | ||
| 210 | { | ||
| 211 | READWRITE(nVersion); | ||
| 212 | READWRITE(nTime); | ||
| 213 | } | ||
| 214 | READWRITE(nServices); | ||
| 215 | READWRITE(FLATDATA(pchReserved)); | ||
| 216 | READWRITE(ip); | ||
| 217 | READWRITE(port); | ||
| 218 | ) | ||
| 219 | |||
| 220 | friend inline bool operator==(const CAddress& a, const CAddress& b) | ||
| 221 | { | ||
| 222 | return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 && | ||
| 223 | a.ip == b.ip && | ||
| 224 | a.port == b.port); | ||
| 225 | } | ||
| 226 | |||
| 227 | friend inline bool operator<(const CAddress& a, const CAddress& b) | ||
| 228 | { | ||
| 229 | int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)); | ||
| 230 | if (ret < 0) | ||
| 231 | return true; | ||
| 232 | else if (ret == 0) | ||
| 233 | { | ||
| 234 | if (ntohl(a.ip) < ntohl(b.ip)) | ||
| 235 | return true; | ||
| 236 | else if (a.ip == b.ip) | ||
| 237 | return ntohs(a.port) < ntohs(b.port); | ||
| 238 | } | ||
| 239 | return false; | ||
| 240 | } | ||
| 241 | |||
| 242 | vector<unsigned char> GetKey() const | ||
| 243 | { | ||
| 244 | CDataStream ss; | ||
| 245 | ss.reserve(18); | ||
| 246 | ss << FLATDATA(pchReserved) << ip << port; | ||
| 247 | |||
| 248 | #if defined(_MSC_VER) && _MSC_VER < 1300 | ||
| 249 | return vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]); | ||
| 250 | #else | ||
| 251 | return vector<unsigned char>(ss.begin(), ss.end()); | ||
| 252 | #endif | ||
| 253 | } | ||
| 254 | |||
| 255 | struct sockaddr_in GetSockAddr() const | ||
| 256 | { | ||
| 257 | struct sockaddr_in sockaddr; | ||
| 258 | sockaddr.sin_family = AF_INET; | ||
| 259 | sockaddr.sin_addr.s_addr = ip; | ||
| 260 | sockaddr.sin_port = port; | ||
| 261 | return sockaddr; | ||
| 262 | } | ||
| 263 | |||
| 264 | bool IsIPv4() const | ||
| 265 | { | ||
| 266 | return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0); | ||
| 267 | } | ||
| 268 | |||
| 269 | bool IsRoutable() const | ||
| 270 | { | ||
| 271 | return !(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168)); | ||
| 272 | } | ||
| 273 | |||
| 274 | unsigned char GetByte(int n) const | ||
| 275 | { | ||
| 276 | return ((unsigned char*)&ip)[3-n]; | ||
| 277 | } | ||
| 278 | |||
| 279 | string ToStringIPPort() const | ||
| 280 | { | ||
| 281 | return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port)); | ||
| 282 | } | ||
| 283 | |||
| 284 | string ToStringIP() const | ||
| 285 | { | ||
| 286 | return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); | ||
| 287 | } | ||
| 288 | |||
| 289 | string ToString() const | ||
| 290 | { | ||
| 291 | return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port)); | ||
| 292 | //return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); | ||
| 293 | } | ||
| 294 | |||
| 295 | void print() const | ||
| 296 | { | ||
| 297 | printf("CAddress(%s)\n", ToString().c_str()); | ||
| 298 | } | ||
| 299 | }; | ||
| 300 | |||
| 301 | |||
| 302 | |||
| 303 | |||
| 304 | |||
| 305 | |||
| 306 | |||
| 307 | enum | ||
| 308 | { | ||
| 309 | MSG_TX = 1, | ||
| 310 | MSG_BLOCK, | ||
| 311 | MSG_REVIEW, | ||
| 312 | MSG_PRODUCT, | ||
| 313 | MSG_TABLE, | ||
| 314 | }; | ||
| 315 | |||
| 316 | static const char* ppszTypeName[] = | ||
| 317 | { | ||
| 318 | "ERROR", | ||
| 319 | "tx", | ||
| 320 | "block", | ||
| 321 | "review", | ||
| 322 | "product", | ||
| 323 | "table", | ||
| 324 | }; | ||
| 325 | |||
| 326 | class CInv | ||
| 327 | { | ||
| 328 | public: | ||
| 329 | int type; | ||
| 330 | uint256 hash; | ||
| 331 | |||
| 332 | CInv() | ||
| 333 | { | ||
| 334 | type = 0; | ||
| 335 | hash = 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | CInv(int typeIn, const uint256& hashIn) | ||
| 339 | { | ||
| 340 | type = typeIn; | ||
| 341 | hash = hashIn; | ||
| 342 | } | ||
| 343 | |||
| 344 | CInv(const string& strType, const uint256& hashIn) | ||
| 345 | { | ||
| 346 | int i; | ||
| 347 | for (i = 1; i < ARRAYLEN(ppszTypeName); i++) | ||
| 348 | { | ||
| 349 | if (strType == ppszTypeName[i]) | ||
| 350 | { | ||
| 351 | type = i; | ||
| 352 | break; | ||
| 353 | } | ||
| 354 | } | ||
| 355 | if (i == ARRAYLEN(ppszTypeName)) | ||
| 356 | throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str())); | ||
| 357 | hash = hashIn; | ||
| 358 | } | ||
| 359 | |||
| 360 | IMPLEMENT_SERIALIZE | ||
| 361 | ( | ||
| 362 | READWRITE(type); | ||
| 363 | READWRITE(hash); | ||
| 364 | ) | ||
| 365 | |||
| 366 | friend inline bool operator<(const CInv& a, const CInv& b) | ||
| 367 | { | ||
| 368 | return (a.type < b.type || (a.type == b.type && a.hash < b.hash)); | ||
| 369 | } | ||
| 370 | |||
| 371 | bool IsKnownType() const | ||
| 372 | { | ||
| 373 | return (type >= 1 && type < ARRAYLEN(ppszTypeName)); | ||
| 374 | } | ||
| 375 | |||
| 376 | const char* GetCommand() const | ||
| 377 | { | ||
| 378 | if (!IsKnownType()) | ||
| 379 | throw std::out_of_range(strprintf("CInv::GetCommand() : type=% unknown type", type)); | ||
| 380 | return ppszTypeName[type]; | ||
| 381 | } | ||
| 382 | |||
| 383 | string ToString() const | ||
| 384 | { | ||
| 385 | return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,14).c_str()); | ||
| 386 | } | ||
| 387 | |||
| 388 | void print() const | ||
| 389 | { | ||
| 390 | printf("CInv(%s)\n", ToString().c_str()); | ||
| 391 | } | ||
| 392 | }; | ||
| 393 | |||
| 394 | |||
| 395 | |||
| 396 | |||
| 397 | |||
| 398 | class CRequestTracker | ||
| 399 | { | ||
| 400 | public: | ||
| 401 | void (*fn)(void*, CDataStream&); | ||
| 402 | void* param1; | ||
| 403 | |||
| 404 | explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL) | ||
| 405 | { | ||
| 406 | fn = fnIn; | ||
| 407 | param1 = param1In; | ||
| 408 | } | ||
| 409 | |||
| 410 | bool IsNull() | ||
| 411 | { | ||
| 412 | return fn == NULL; | ||
| 413 | } | ||
| 414 | }; | ||
| 415 | |||
| 416 | |||
| 417 | |||
| 418 | |||
| 419 | |||
| 420 | extern bool fClient; | ||
| 421 | extern uint64 nLocalServices; | ||
| 422 | extern CAddress addrLocalHost; | ||
| 423 | extern unsigned short nListenPort; | ||
| 424 | extern CNode* pnodeLocalHost; | ||
| 425 | extern bool fShutdown; | ||
| 426 | extern array<bool, 10> vfThreadRunning; | ||
| 427 | extern vector<CNode*> vNodes; | ||
| 428 | extern CCriticalSection cs_vNodes; | ||
| 429 | extern map<vector<unsigned char>, CAddress> mapAddresses; | ||
| 430 | extern CCriticalSection cs_mapAddresses; | ||
| 431 | extern map<CInv, CDataStream> mapRelay; | ||
| 432 | extern deque<pair<int64, CInv> > vRelayExpiration; | ||
| 433 | extern CCriticalSection cs_mapRelay; | ||
| 434 | extern map<CInv, int64> mapAlreadyAskedFor; | ||
| 435 | extern CAddress addrProxy; | ||
| 436 | |||
| 437 | |||
| 438 | |||
| 439 | |||
| 440 | |||
| 441 | class CNode | ||
| 442 | { | ||
| 443 | public: | ||
| 444 | // socket | ||
| 445 | uint64 nServices; | ||
| 446 | SOCKET hSocket; | ||
| 447 | CDataStream vSend; | ||
| 448 | CDataStream vRecv; | ||
| 449 | CCriticalSection cs_vSend; | ||
| 450 | CCriticalSection cs_vRecv; | ||
| 451 | unsigned int nPushPos; | ||
| 452 | CAddress addr; | ||
| 453 | int nVersion; | ||
| 454 | bool fClient; | ||
| 455 | bool fInbound; | ||
| 456 | bool fNetworkNode; | ||
| 457 | bool fDisconnect; | ||
| 458 | protected: | ||
| 459 | int nRefCount; | ||
| 460 | public: | ||
| 461 | int64 nReleaseTime; | ||
| 462 | map<uint256, CRequestTracker> mapRequests; | ||
| 463 | CCriticalSection cs_mapRequests; | ||
| 464 | |||
| 465 | // flood | ||
| 466 | vector<CAddress> vAddrToSend; | ||
| 467 | set<CAddress> setAddrKnown; | ||
| 468 | |||
| 469 | // inventory based relay | ||
| 470 | set<CInv> setInventoryKnown; | ||
| 471 | set<CInv> setInventoryKnown2; | ||
| 472 | vector<CInv> vInventoryToSend; | ||
| 473 | CCriticalSection cs_inventory; | ||
| 474 | multimap<int64, CInv> mapAskFor; | ||
| 475 | |||
| 476 | // publish and subscription | ||
| 477 | vector<char> vfSubscribe; | ||
| 478 | |||
| 479 | |||
| 480 | CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) | ||
| 481 | { | ||
| 482 | nServices = 0; | ||
| 483 | hSocket = hSocketIn; | ||
| 484 | vSend.SetType(SER_NETWORK); | ||
| 485 | vRecv.SetType(SER_NETWORK); | ||
| 486 | nPushPos = -1; | ||
| 487 | addr = addrIn; | ||
| 488 | nVersion = 0; | ||
| 489 | fClient = false; // set by version message | ||
| 490 | fInbound = fInboundIn; | ||
| 491 | fNetworkNode = false; | ||
| 492 | fDisconnect = false; | ||
| 493 | nRefCount = 0; | ||
| 494 | nReleaseTime = 0; | ||
| 495 | vfSubscribe.assign(256, false); | ||
| 496 | |||
| 497 | // Push a version message | ||
| 498 | /// when NTP implemented, change to just nTime = GetAdjustedTime() | ||
| 499 | int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); | ||
| 500 | PushMessage("version", VERSION, nLocalServices, nTime, addr); | ||
| 501 | } | ||
| 502 | |||
| 503 | ~CNode() | ||
| 504 | { | ||
| 505 | if (hSocket != INVALID_SOCKET) | ||
| 506 | closesocket(hSocket); | ||
| 507 | } | ||
| 508 | |||
| 509 | private: | ||
| 510 | CNode(const CNode&); | ||
| 511 | void operator=(const CNode&); | ||
| 512 | public: | ||
| 513 | |||
| 514 | |||
| 515 | bool ReadyToDisconnect() | ||
| 516 | { | ||
| 517 | return fDisconnect || GetRefCount() <= 0; | ||
| 518 | } | ||
| 519 | |||
| 520 | int GetRefCount() | ||
| 521 | { | ||
| 522 | return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0); | ||
| 523 | } | ||
| 524 | |||
| 525 | void AddRef(int64 nTimeout=0) | ||
| 526 | { | ||
| 527 | if (nTimeout != 0) | ||
| 528 | nReleaseTime = max(nReleaseTime, GetTime() + nTimeout); | ||
| 529 | else | ||
| 530 | nRefCount++; | ||
| 531 | } | ||
| 532 | |||
| 533 | void Release() | ||
| 534 | { | ||
| 535 | nRefCount--; | ||
| 536 | } | ||
| 537 | |||
| 538 | |||
| 539 | |||
| 540 | void AddInventoryKnown(const CInv& inv) | ||
| 541 | { | ||
| 542 | CRITICAL_BLOCK(cs_inventory) | ||
| 543 | setInventoryKnown.insert(inv); | ||
| 544 | } | ||
| 545 | |||
| 546 | void PushInventory(const CInv& inv) | ||
| 547 | { | ||
| 548 | CRITICAL_BLOCK(cs_inventory) | ||
| 549 | if (!setInventoryKnown.count(inv)) | ||
| 550 | vInventoryToSend.push_back(inv); | ||
| 551 | } | ||
| 552 | |||
| 553 | void AskFor(const CInv& inv) | ||
| 554 | { | ||
| 555 | // We're using mapAskFor as a priority queue, | ||
| 556 | // the key is the earliest time the request can be sent | ||
| 557 | int64& nRequestTime = mapAlreadyAskedFor[inv]; | ||
| 558 | printf("askfor %s %I64d\n", inv.ToString().c_str(), nRequestTime); | ||
| 559 | |||
| 560 | // Make sure not to reuse time indexes to keep things in the same order | ||
| 561 | int64 nNow = (GetTime() - 1) * 1000000; | ||
| 562 | static int64 nLastTime; | ||
| 563 | nLastTime = nNow = max(nNow, ++nLastTime); | ||
| 564 | |||
| 565 | // Each retry is 2 minutes after the last | ||
| 566 | nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow); | ||
| 567 | mapAskFor.insert(make_pair(nRequestTime, inv)); | ||
| 568 | } | ||
| 569 | |||
| 570 | |||
| 571 | |||
| 572 | void BeginMessage(const char* pszCommand) | ||
| 573 | { | ||
| 574 | EnterCriticalSection(&cs_vSend); | ||
| 575 | if (nPushPos != -1) | ||
| 576 | AbortMessage(); | ||
| 577 | nPushPos = vSend.size(); | ||
| 578 | vSend << CMessageHeader(pszCommand, 0); | ||
| 579 | printf("sending: %-12s ", pszCommand); | ||
| 580 | } | ||
| 581 | |||
| 582 | void AbortMessage() | ||
| 583 | { | ||
| 584 | if (nPushPos == -1) | ||
| 585 | return; | ||
| 586 | vSend.resize(nPushPos); | ||
| 587 | nPushPos = -1; | ||
| 588 | LeaveCriticalSection(&cs_vSend); | ||
| 589 | printf("(aborted)\n"); | ||
| 590 | } | ||
| 591 | |||
| 592 | void EndMessage() | ||
| 593 | { | ||
| 594 | extern int nDropMessagesTest; | ||
| 595 | if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) | ||
| 596 | { | ||
| 597 | printf("dropmessages DROPPING SEND MESSAGE\n"); | ||
| 598 | AbortMessage(); | ||
| 599 | return; | ||
| 600 | } | ||
| 601 | |||
| 602 | if (nPushPos == -1) | ||
| 603 | return; | ||
| 604 | |||
| 605 | // Patch in the size | ||
| 606 | unsigned int nSize = vSend.size() - nPushPos - sizeof(CMessageHeader); | ||
| 607 | memcpy((char*)&vSend[nPushPos] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); | ||
| 608 | |||
| 609 | printf("(%d bytes) ", nSize); | ||
| 610 | //for (int i = nPushPos+sizeof(CMessageHeader); i < min(vSend.size(), nPushPos+sizeof(CMessageHeader)+20U); i++) | ||
| 611 | // printf("%02x ", vSend[i] & 0xff); | ||
| 612 | printf("\n"); | ||
| 613 | |||
| 614 | nPushPos = -1; | ||
| 615 | LeaveCriticalSection(&cs_vSend); | ||
| 616 | } | ||
| 617 | |||
| 618 | void EndMessageAbortIfEmpty() | ||
| 619 | { | ||
| 620 | if (nPushPos == -1) | ||
| 621 | return; | ||
| 622 | int nSize = vSend.size() - nPushPos - sizeof(CMessageHeader); | ||
| 623 | if (nSize > 0) | ||
| 624 | EndMessage(); | ||
| 625 | else | ||
| 626 | AbortMessage(); | ||
| 627 | } | ||
| 628 | |||
| 629 | const char* GetMessageCommand() const | ||
| 630 | { | ||
| 631 | if (nPushPos == -1) | ||
| 632 | return ""; | ||
| 633 | return &vSend[nPushPos] + offsetof(CMessageHeader, pchCommand); | ||
| 634 | } | ||
| 635 | |||
| 636 | |||
| 637 | |||
| 638 | |||
| 639 | void PushMessage(const char* pszCommand) | ||
| 640 | { | ||
| 641 | try | ||
| 642 | { | ||
| 643 | BeginMessage(pszCommand); | ||
| 644 | EndMessage(); | ||
| 645 | } | ||
| 646 | catch (...) | ||
| 647 | { | ||
| 648 | AbortMessage(); | ||
| 649 | throw; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | template<typename T1> | ||
| 654 | void PushMessage(const char* pszCommand, const T1& a1) | ||
| 655 | { | ||
| 656 | try | ||
| 657 | { | ||
| 658 | BeginMessage(pszCommand); | ||
| 659 | vSend << a1; | ||
| 660 | EndMessage(); | ||
| 661 | } | ||
| 662 | catch (...) | ||
| 663 | { | ||
| 664 | AbortMessage(); | ||
| 665 | throw; | ||
| 666 | } | ||
| 667 | } | ||
| 668 | |||
| 669 | template<typename T1, typename T2> | ||
| 670 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2) | ||
| 671 | { | ||
| 672 | try | ||
| 673 | { | ||
| 674 | BeginMessage(pszCommand); | ||
| 675 | vSend << a1 << a2; | ||
| 676 | EndMessage(); | ||
| 677 | } | ||
| 678 | catch (...) | ||
| 679 | { | ||
| 680 | AbortMessage(); | ||
| 681 | throw; | ||
| 682 | } | ||
| 683 | } | ||
| 684 | |||
| 685 | template<typename T1, typename T2, typename T3> | ||
| 686 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3) | ||
| 687 | { | ||
| 688 | try | ||
| 689 | { | ||
| 690 | BeginMessage(pszCommand); | ||
| 691 | vSend << a1 << a2 << a3; | ||
| 692 | EndMessage(); | ||
| 693 | } | ||
| 694 | catch (...) | ||
| 695 | { | ||
| 696 | AbortMessage(); | ||
| 697 | throw; | ||
| 698 | } | ||
| 699 | } | ||
| 700 | |||
| 701 | template<typename T1, typename T2, typename T3, typename T4> | ||
| 702 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4) | ||
| 703 | { | ||
| 704 | try | ||
| 705 | { | ||
| 706 | BeginMessage(pszCommand); | ||
| 707 | vSend << a1 << a2 << a3 << a4; | ||
| 708 | EndMessage(); | ||
| 709 | } | ||
| 710 | catch (...) | ||
| 711 | { | ||
| 712 | AbortMessage(); | ||
| 713 | throw; | ||
| 714 | } | ||
| 715 | } | ||
| 716 | |||
| 717 | |||
| 718 | void PushRequest(const char* pszCommand, | ||
| 719 | void (*fn)(void*, CDataStream&), void* param1) | ||
| 720 | { | ||
| 721 | uint256 hashReply; | ||
| 722 | RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); | ||
| 723 | |||
| 724 | CRITICAL_BLOCK(cs_mapRequests) | ||
| 725 | mapRequests[hashReply] = CRequestTracker(fn, param1); | ||
| 726 | |||
| 727 | PushMessage(pszCommand, hashReply); | ||
| 728 | } | ||
| 729 | |||
| 730 | template<typename T1> | ||
| 731 | void PushRequest(const char* pszCommand, const T1& a1, | ||
| 732 | void (*fn)(void*, CDataStream&), void* param1) | ||
| 733 | { | ||
| 734 | uint256 hashReply; | ||
| 735 | RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); | ||
| 736 | |||
| 737 | CRITICAL_BLOCK(cs_mapRequests) | ||
| 738 | mapRequests[hashReply] = CRequestTracker(fn, param1); | ||
| 739 | |||
| 740 | PushMessage(pszCommand, hashReply, a1); | ||
| 741 | } | ||
| 742 | |||
| 743 | template<typename T1, typename T2> | ||
| 744 | void PushRequest(const char* pszCommand, const T1& a1, const T2& a2, | ||
| 745 | void (*fn)(void*, CDataStream&), void* param1) | ||
| 746 | { | ||
| 747 | uint256 hashReply; | ||
| 748 | RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); | ||
| 749 | |||
| 750 | CRITICAL_BLOCK(cs_mapRequests) | ||
| 751 | mapRequests[hashReply] = CRequestTracker(fn, param1); | ||
| 752 | |||
| 753 | PushMessage(pszCommand, hashReply, a1, a2); | ||
| 754 | } | ||
| 755 | |||
| 756 | |||
| 757 | |||
| 758 | bool IsSubscribed(unsigned int nChannel); | ||
| 759 | void Subscribe(unsigned int nChannel, unsigned int nHops=0); | ||
| 760 | void CancelSubscribe(unsigned int nChannel); | ||
| 761 | void Disconnect(); | ||
| 762 | }; | ||
| 763 | |||
| 764 | |||
| 765 | |||
| 766 | |||
| 767 | |||
| 768 | |||
| 769 | |||
| 770 | |||
| 771 | |||
| 772 | |||
| 773 | inline void RelayInventory(const CInv& inv) | ||
| 774 | { | ||
| 775 | // Put on lists to offer to the other nodes | ||
| 776 | CRITICAL_BLOCK(cs_vNodes) | ||
| 777 | foreach(CNode* pnode, vNodes) | ||
| 778 | pnode->PushInventory(inv); | ||
| 779 | } | ||
| 780 | |||
| 781 | template<typename T> | ||
| 782 | void RelayMessage(const CInv& inv, const T& a) | ||
| 783 | { | ||
| 784 | CDataStream ss(SER_NETWORK); | ||
| 785 | ss.reserve(10000); | ||
| 786 | ss << a; | ||
| 787 | RelayMessage(inv, ss); | ||
| 788 | } | ||
| 789 | |||
| 790 | template<> | ||
| 791 | inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) | ||
| 792 | { | ||
| 793 | CRITICAL_BLOCK(cs_mapRelay) | ||
| 794 | { | ||
| 795 | // Expire old relay messages | ||
| 796 | while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) | ||
| 797 | { | ||
| 798 | mapRelay.erase(vRelayExpiration.front().second); | ||
| 799 | vRelayExpiration.pop_front(); | ||
| 800 | } | ||
| 801 | |||
| 802 | // Save original serialized message so newer versions are preserved | ||
| 803 | mapRelay[inv] = ss; | ||
| 804 | vRelayExpiration.push_back(make_pair(GetTime() + 15 * 60, inv)); | ||
| 805 | } | ||
| 806 | |||
| 807 | RelayInventory(inv); | ||
| 808 | } | ||
| 809 | |||
| 810 | |||
| 811 | |||
| 812 | |||
| 813 | |||
| 814 | |||
| 815 | |||
| 816 | |||
| 817 | // | ||
| 818 | // Templates for the publish and subscription system. | ||
| 819 | // The object being published as T& obj needs to have: | ||
| 820 | // a set<unsigned int> setSources member | ||
| 821 | // specializations of AdvertInsert and AdvertErase | ||
| 822 | // Currently implemented for CTable and CProduct. | ||
| 823 | // | ||
| 824 | |||
| 825 | template<typename T> | ||
| 826 | void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) | ||
| 827 | { | ||
| 828 | // Add to sources | ||
| 829 | obj.setSources.insert(pfrom->addr.ip); | ||
| 830 | |||
| 831 | if (!AdvertInsert(obj)) | ||
| 832 | return; | ||
| 833 | |||
| 834 | // Relay | ||
| 835 | CRITICAL_BLOCK(cs_vNodes) | ||
| 836 | foreach(CNode* pnode, vNodes) | ||
| 837 | if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel))) | ||
| 838 | pnode->PushMessage("publish", nChannel, nHops, obj); | ||
| 839 | } | ||
| 840 | |||
| 841 | template<typename T> | ||
| 842 | void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) | ||
| 843 | { | ||
| 844 | uint256 hash = obj.GetHash(); | ||
| 845 | |||
| 846 | CRITICAL_BLOCK(cs_vNodes) | ||
| 847 | foreach(CNode* pnode, vNodes) | ||
| 848 | if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel))) | ||
| 849 | pnode->PushMessage("pub-cancel", nChannel, nHops, hash); | ||
| 850 | |||
| 851 | AdvertErase(obj); | ||
| 852 | } | ||
| 853 | |||
| 854 | template<typename T> | ||
| 855 | void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj) | ||
| 856 | { | ||
| 857 | // Remove a source | ||
| 858 | obj.setSources.erase(pfrom->addr.ip); | ||
| 859 | |||
| 860 | // If no longer supported by any sources, cancel it | ||
| 861 | if (obj.setSources.empty()) | ||
| 862 | AdvertStopPublish(pfrom, nChannel, nHops, obj); | ||
| 863 | } | ||