upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
authorBitflash-sh <btf01@proton.me>2026-07-24 11:18:11 -0300
committerBitflash-sh <btf01@proton.me>2026-07-24 11:18:11 -0300
commit51d617e70f90a972185917ea0096c1ecef2bfa8b (patch)
tree9fbbcd867de9de9d0776afdd02f594ba312c46eb /src/net.cpp
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.cpp')
-rw-r--r--src/net.cpp1207
1 files changed, 1207 insertions, 0 deletions
diff --git a/src/net.cpp b/src/net.cpp
new file mode 100644
index 0000000..8ab9ccc
--- /dev/null
+++ b/src/net.cpp
@@ -0,0 +1,1207 @@
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#include "headers.h"
6#ifdef _WIN32
7#include <winsock2.h>
8#endif
9#include <openssl/rand.h>
10#include "btfaddr.h"
11#include "btftunnel.h"
12
13void ThreadMessageHandler2(void* parg);
14void ThreadSocketHandler2(void* parg);
15void ThreadOpenConnections2(void* parg);
16
17
18
19
20
21
22//
23// Global state variables
24//
25bool fClient = false;
26uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
27CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices);
28unsigned short nListenPort = DEFAULT_PORT; // local P2P port (tunable via /port)
29CNode nodeLocalHost(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));
30CNode* pnodeLocalHost = &nodeLocalHost;
31bool fShutdown = false;
32array<bool, 10> vfThreadRunning;
33vector<CNode*> vNodes;
34CCriticalSection cs_vNodes;
35map<vector<unsigned char>, CAddress> mapAddresses;
36CCriticalSection cs_mapAddresses;
37map<CInv, CDataStream> mapRelay;
38deque<pair<int64, CInv> > vRelayExpiration;
39CCriticalSection cs_mapRelay;
40map<CInv, int64> mapAlreadyAskedFor;
41string strBtfConnect; // .btf peer to keep connected to (from /connectbtf)
42
43
44
45CAddress addrProxy;
46
47bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
48{
49 hSocketRet = INVALID_SOCKET;
50
51 SOCKET hSocket = socket(AF_INET, SOCK_STREAM, 0);
52 if (hSocket == INVALID_SOCKET)
53 return false;
54
55 bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168));
56 bool fProxy = (addrProxy.ip && fRoutable);
57 struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
58
59 if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
60 {
61 closesocket(hSocket);
62 return false;
63 }
64
65 if (fProxy)
66 {
67 printf("Proxy connecting to %s\n", addrConnect.ToString().c_str());
68 char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
69 memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
70 memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
71 char* pszSocks4 = pszSocks4IP;
72 int nSize = sizeof(pszSocks4IP);
73
74 int ret = send(hSocket, pszSocks4, nSize, 0);
75 if (ret != nSize)
76 {
77 closesocket(hSocket);
78 return error("Error sending to proxy\n");
79 }
80 char pchRet[8];
81 if (recv(hSocket, pchRet, 8, 0) != 8)
82 {
83 closesocket(hSocket);
84 return error("Error reading proxy response\n");
85 }
86 if (pchRet[1] != 0x5a)
87 {
88 closesocket(hSocket);
89 return error("Proxy returned error %d\n", pchRet[1]);
90 }
91 printf("Proxy connection established %s\n", addrConnect.ToString().c_str());
92 }
93
94 hSocketRet = hSocket;
95 return true;
96}
97
98
99bool GetMyExternalIP(unsigned int& ipRet)
100{
101 // The 2009 whatismyip.com service (fixed IP) no longer exists; this avoids
102 // stalling startup on TCP timeouts. The external IP may come from Nostr
103 // relays in the future.
104 return false;
105
106 CAddress addrConnect("72.233.89.199:80"); // whatismyip.com 198-200
107
108 SOCKET hSocket;
109 if (!ConnectSocket(addrConnect, hSocket))
110 return error("GetMyExternalIP() : connection to %s failed\n", addrConnect.ToString().c_str());
111
112 char* pszGet =
113 "GET /automation/n09230945.asp HTTP/1.1\r\n"
114 "Host: www.whatismyip.com\r\n"
115 "User-Agent: Bitcoin/0.1\r\n"
116 "Connection: close\r\n"
117 "\r\n";
118 send(hSocket, pszGet, strlen(pszGet), 0);
119
120 string strLine;
121 while (RecvLine(hSocket, strLine))
122 {
123 if (strLine.empty())
124 {
125 if (!RecvLine(hSocket, strLine))
126 {
127 closesocket(hSocket);
128 return false;
129 }
130 closesocket(hSocket);
131 CAddress addr(strLine.c_str());
132 printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
133 if (addr.ip == 0)
134 return false;
135 ipRet = addr.ip;
136 return true;
137 }
138 }
139 closesocket(hSocket);
140 return error("GetMyExternalIP() : connection closed\n");
141}
142
143
144
145
146
147
148bool AddAddress(CAddrDB& addrdb, const CAddress& addr)
149{
150 if (!addr.IsRoutable())
151 return false;
152 if (addr.ip == addrLocalHost.ip)
153 return false;
154 CRITICAL_BLOCK(cs_mapAddresses)
155 {
156 map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
157 if (it == mapAddresses.end())
158 {
159 // New address
160 mapAddresses.insert(make_pair(addr.GetKey(), addr));
161 addrdb.WriteAddress(addr);
162 return true;
163 }
164 else
165 {
166 CAddress& addrFound = (*it).second;
167 if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
168 {
169 // Services have been added
170 addrFound.nServices |= addr.nServices;
171 addrdb.WriteAddress(addrFound);
172 return true;
173 }
174 }
175 }
176 return false;
177}
178
179
180
181
182
183void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
184{
185 // If the dialog might get closed before the reply comes back,
186 // call this in the destructor so it doesn't get called after it's deleted.
187 CRITICAL_BLOCK(cs_vNodes)
188 {
189 foreach(CNode* pnode, vNodes)
190 {
191 CRITICAL_BLOCK(pnode->cs_mapRequests)
192 {
193 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
194 {
195 CRequestTracker& tracker = (*mi).second;
196 if (tracker.fn == fn && tracker.param1 == param1)
197 pnode->mapRequests.erase(mi++);
198 else
199 mi++;
200 }
201 }
202 }
203 }
204}
205
206
207
208
209
210
211
212//
213// Subscription methods for the broadcast and subscription system.
214// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
215//
216// The subscription system uses a meet-in-the-middle strategy.
217// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
218// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
219//
220
221bool AnySubscribed(unsigned int nChannel)
222{
223 if (pnodeLocalHost->IsSubscribed(nChannel))
224 return true;
225 CRITICAL_BLOCK(cs_vNodes)
226 foreach(CNode* pnode, vNodes)
227 if (pnode->IsSubscribed(nChannel))
228 return true;
229 return false;
230}
231
232bool CNode::IsSubscribed(unsigned int nChannel)
233{
234 if (nChannel >= vfSubscribe.size())
235 return false;
236 return vfSubscribe[nChannel];
237}
238
239void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
240{
241 if (nChannel >= vfSubscribe.size())
242 return;
243
244 if (!AnySubscribed(nChannel))
245 {
246 // Relay subscribe
247 CRITICAL_BLOCK(cs_vNodes)
248 foreach(CNode* pnode, vNodes)
249 if (pnode != this)
250 pnode->PushMessage("subscribe", nChannel, nHops);
251 }
252
253 vfSubscribe[nChannel] = true;
254}
255
256void CNode::CancelSubscribe(unsigned int nChannel)
257{
258 if (nChannel >= vfSubscribe.size())
259 return;
260
261 // Prevent from relaying cancel if wasn't subscribed
262 if (!vfSubscribe[nChannel])
263 return;
264 vfSubscribe[nChannel] = false;
265
266 if (!AnySubscribed(nChannel))
267 {
268 // Relay subscription cancel
269 CRITICAL_BLOCK(cs_vNodes)
270 foreach(CNode* pnode, vNodes)
271 if (pnode != this)
272 pnode->PushMessage("sub-cancel", nChannel);
273
274 // Clear memory, no longer subscribed
275 if (nChannel == MSG_PRODUCT)
276 CRITICAL_BLOCK(cs_mapProducts)
277 mapProducts.clear();
278 }
279}
280
281
282
283
284
285
286
287
288
289CNode* FindNode(unsigned int ip)
290{
291 CRITICAL_BLOCK(cs_vNodes)
292 {
293 foreach(CNode* pnode, vNodes)
294 if (pnode->addr.ip == ip)
295 return (pnode);
296 }
297 return NULL;
298}
299
300CNode* FindNode(CAddress addr)
301{
302 CRITICAL_BLOCK(cs_vNodes)
303 {
304 foreach(CNode* pnode, vNodes)
305 if (pnode->addr == addr)
306 return (pnode);
307 }
308 return NULL;
309}
310
311CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
312{
313 if (addrConnect.ip == addrLocalHost.ip)
314 return NULL;
315
316 // Look for an existing connection
317 CNode* pnode = FindNode(addrConnect.ip);
318 if (pnode)
319 {
320 if (nTimeout != 0)
321 pnode->AddRef(nTimeout);
322 else
323 pnode->AddRef();
324 return pnode;
325 }
326
327 /// debug print
328 printf("trying %s\n", addrConnect.ToString().c_str());
329
330 // Connect
331 SOCKET hSocket;
332 if (ConnectSocket(addrConnect, hSocket))
333 {
334 /// debug print
335 printf("connected %s\n", addrConnect.ToString().c_str());
336
337 // Add node
338 CNode* pnode = new CNode(hSocket, addrConnect, false);
339 if (nTimeout != 0)
340 pnode->AddRef(nTimeout);
341 else
342 pnode->AddRef();
343 CRITICAL_BLOCK(cs_vNodes)
344 vNodes.push_back(pnode);
345
346 CRITICAL_BLOCK(cs_mapAddresses)
347 mapAddresses[addrConnect.GetKey()].nLastFailed = 0;
348 return pnode;
349 }
350 else
351 {
352 CRITICAL_BLOCK(cs_mapAddresses)
353 mapAddresses[addrConnect.GetKey()].nLastFailed = GetTime();
354 return NULL;
355 }
356}
357
358// Synthetic marker address for a tunneled `.btf` peer. The real endpoint is
359// unknown by design (the tunnel hides it), so tag the CNode with a non-routable
360// 10.x.x.x address (fails IsRoutable, so it is never gossiped as a real peer)
361// that is stable per identity, keeping FindNode and the duplicate check working.
362static CAddress BtfMarkerAddr(const unsigned char b5[5])
363{
364 unsigned int ip;
365 unsigned char b[4] = { 10, b5[0], b5[1], b5[2] };
366 memcpy(&ip, b, 4);
367 unsigned short port = htons((unsigned short)((b5[3] << 8) | b5[4]));
368 return CAddress(ip, port, nLocalServices);
369}
370
371// Connect to a peer by its `.btf` address: resolve the self-certified
372// descriptor over Nostr, then tunnel through its meeting node with the
373// end-to-end channel. Neither side ever learns the other's IP.
374CNode* ConnectNodeBtf(const string& strBtfAddr)
375{
376 unsigned char pk[32];
377 if (!btf::ParseAddress(strBtfAddr, pk))
378 {
379 printf("ConnectNodeBtf: invalid address %s\n", strBtfAddr.c_str());
380 return NULL;
381 }
382 if (BtfLocalAddress() == strBtfAddr)
383 return NULL; // ourselves
384
385 CAddress addr = BtfMarkerAddr(pk);
386 CNode* pnode = FindNode(addr.ip);
387 if (pnode)
388 {
389 pnode->AddRef();
390 return pnode;
391 }
392
393 /// debug print
394 printf("trying %s\n", strBtfAddr.c_str());
395
396 string strMeeting;
397 unsigned char enc_pub[32];
398 if (!BtfResolve(strBtfAddr, strMeeting, enc_pub))
399 {
400 printf("ConnectNodeBtf: could not resolve a descriptor for %s\n", strBtfAddr.c_str());
401 return NULL;
402 }
403 size_t colon = strMeeting.rfind(':');
404 if (colon == string::npos)
405 return NULL;
406 string strHost = strMeeting.substr(0, colon);
407 int nPort = atoi(strMeeting.substr(colon + 1).c_str());
408 if (nPort <= 0 || nPort > 65535)
409 return NULL;
410
411 btf_socket_t hSocket = btf::BtfClientTunnel(strHost.c_str(), (unsigned short)nPort, pk, enc_pub);
412 if (hSocket == INVALID_SOCKET)
413 {
414 printf("ConnectNodeBtf: tunnel to %s via %s failed\n", strBtfAddr.c_str(), strMeeting.c_str());
415 return NULL;
416 }
417
418 /// debug print
419 printf("connected %s via rendezvous %s\n", strBtfAddr.c_str(), strMeeting.c_str());
420
421 // Add node
422 pnode = new CNode(hSocket, addr, false);
423 pnode->AddRef();
424 CRITICAL_BLOCK(cs_vNodes)
425 vNodes.push_back(pnode);
426 return pnode;
427}
428
429// Anonymous inbound listener (this node's `.btf` hidden service). Registers at
430// the meeting relay and blocks until a client dials our address; each pairing
431// becomes a normal inbound CNode riding the end-to-end channel, then we
432// register again for the next caller.
433void ThreadBtfAccept(void* parg)
434{
435 printf("ThreadBtfAccept started\n");
436 unsigned char pk[32];
437 unsigned char sk[32];
438 while (!BtfGetIdentity(pk, sk))
439 {
440 if (fShutdown)
441 return;
442 Sleep(5000);
443 }
444 loop
445 {
446 if (fShutdown)
447 return;
448 string strMeeting = strBtfMeetingRelay;
449 size_t colon = strMeeting.rfind(':');
450 if (colon == string::npos)
451 {
452 Sleep(10000); // no meeting relay configured
453 continue;
454 }
455 string strHost = strMeeting.substr(0, colon);
456 int nPort = atoi(strMeeting.substr(colon + 1).c_str());
457
458 // Blocks until a client is paired to us (or the relay drops us)
459 btf::RvSocket rv = btf::RvServiceRegister(strHost.c_str(), (unsigned short)nPort, pk);
460 if (fShutdown)
461 {
462 if (rv != btf::RV_INVALID)
463 btf::RvClose(rv);
464 return;
465 }
466 if (rv == btf::RV_INVALID)
467 {
468 Sleep(10000); // relay unreachable; retry
469 continue;
470 }
471 btf_socket_t hSocket = btf::BtfServiceWrap(rv, sk);
472 if (hSocket == INVALID_SOCKET)
473 continue;
474
475 // The dialer is anonymous (its pubkey never reaches us), so tag the
476 // connection with a random marker address.
477 unsigned char rnd[5];
478 RAND_bytes(rnd, sizeof(rnd));
479 CAddress addr = BtfMarkerAddr(rnd);
480
481 printf("accepted .btf connection via rendezvous %s\n", strMeeting.c_str());
482 CNode* pnode = new CNode(hSocket, addr, true);
483 pnode->AddRef();
484 CRITICAL_BLOCK(cs_vNodes)
485 vNodes.push_back(pnode);
486 }
487}
488
489// Keep an outbound connection to a specific `.btf` peer (from /connectbtf) --
490// the rendezvous analogue of addnode. Retries until connected, reconnects if
491// the tunnel drops.
492void ThreadBtfConnect(void* parg)
493{
494 printf("ThreadBtfConnect started\n");
495 string strAddr = *(string*)parg;
496 delete (string*)parg;
497 loop
498 {
499 if (fShutdown)
500 return;
501 try
502 {
503 CNode* pnode = ConnectNodeBtf(strAddr);
504 if (pnode)
505 {
506 if (!pnode->fNetworkNode)
507 pnode->fNetworkNode = true; // keep the ref from ConnectNodeBtf
508 else
509 pnode->Release(); // already pinned; drop the extra ref
510 }
511 }
512 CATCH_PRINT_EXCEPTION("ThreadBtfConnect")
513 for (int i = 0; i < 30 && !fShutdown; i++)
514 Sleep(1000);
515 }
516}
517
518void CNode::Disconnect()
519{
520 printf("disconnecting node %s\n", addr.ToString().c_str());
521
522 closesocket(hSocket);
523
524 // All of a nodes broadcasts and subscriptions are automatically torn down
525 // when it goes down, so a node has to stay up to keep its broadcast going.
526
527 CRITICAL_BLOCK(cs_mapProducts)
528 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end();)
529 AdvertRemoveSource(this, MSG_PRODUCT, 0, (*(mi++)).second);
530
531 // Cancel subscriptions
532 for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
533 if (vfSubscribe[nChannel])
534 CancelSubscribe(nChannel);
535}
536
537
538
539
540
541
542
543
544
545
546
547
548
549void ThreadSocketHandler(void* parg)
550{
551 IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
552
553 loop
554 {
555 vfThreadRunning[0] = true;
556 CheckForShutdown(0);
557 try
558 {
559 ThreadSocketHandler2(parg);
560 }
561 CATCH_PRINT_EXCEPTION("ThreadSocketHandler()")
562 vfThreadRunning[0] = false;
563 Sleep(5000);
564 }
565}
566
567void ThreadSocketHandler2(void* parg)
568{
569 printf("ThreadSocketHandler started\n");
570 SOCKET hListenSocket = *(SOCKET*)parg;
571 list<CNode*> vNodesDisconnected;
572 int nPrevNodeCount = 0;
573
574 loop
575 {
576 //
577 // Disconnect nodes
578 //
579 CRITICAL_BLOCK(cs_vNodes)
580 {
581 // Disconnect duplicate connections
582 map<unsigned int, CNode*> mapFirst;
583 foreach(CNode* pnode, vNodes)
584 {
585 if (pnode->fDisconnect)
586 continue;
587 unsigned int ip = pnode->addr.ip;
588 if (mapFirst.count(ip) && addrLocalHost.ip < ip)
589 {
590 // In case two nodes connect to each other at once,
591 // the lower ip disconnects its outbound connection
592 CNode* pnodeExtra = mapFirst[ip];
593
594 if (pnodeExtra->GetRefCount() > (pnodeExtra->fNetworkNode ? 1 : 0))
595 swap(pnodeExtra, pnode);
596
597 if (pnodeExtra->GetRefCount() <= (pnodeExtra->fNetworkNode ? 1 : 0))
598 {
599 printf("(%d nodes) disconnecting duplicate: %s\n", vNodes.size(), pnodeExtra->addr.ToString().c_str());
600 if (pnodeExtra->fNetworkNode && !pnode->fNetworkNode)
601 {
602 pnode->AddRef();
603 swap(pnodeExtra->fNetworkNode, pnode->fNetworkNode);
604 pnodeExtra->Release();
605 }
606 pnodeExtra->fDisconnect = true;
607 }
608 }
609 mapFirst[ip] = pnode;
610 }
611
612 // Disconnect unused nodes
613 vector<CNode*> vNodesCopy = vNodes;
614 foreach(CNode* pnode, vNodesCopy)
615 {
616 if (pnode->ReadyToDisconnect() && pnode->vRecv.empty() && pnode->vSend.empty())
617 {
618 // remove from vNodes
619 vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
620 pnode->Disconnect();
621
622 // hold in disconnected pool until all refs are released
623 pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 5 * 60);
624 if (pnode->fNetworkNode)
625 pnode->Release();
626 vNodesDisconnected.push_back(pnode);
627 }
628 }
629
630 // Delete disconnected nodes
631 list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
632 foreach(CNode* pnode, vNodesDisconnectedCopy)
633 {
634 // wait until threads are done using it
635 if (pnode->GetRefCount() <= 0)
636 {
637 bool fDelete = false;
638 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
639 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
640 TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
641 TRY_CRITICAL_BLOCK(pnode->cs_inventory)
642 fDelete = true;
643 if (fDelete)
644 {
645 vNodesDisconnected.remove(pnode);
646 delete pnode;
647 }
648 }
649 }
650 }
651 if (vNodes.size() != nPrevNodeCount)
652 {
653 nPrevNodeCount = vNodes.size();
654 MainFrameRepaint();
655 }
656
657
658 //
659 // Find which sockets have data to receive
660 //
661 struct timeval timeout;
662 timeout.tv_sec = 0;
663 timeout.tv_usec = 50000; // frequency to poll pnode->vSend
664
665 fd_set fdsetRecv;
666 fd_set fdsetSend;
667 FD_ZERO(&fdsetRecv);
668 FD_ZERO(&fdsetSend);
669 SOCKET hSocketMax = 0;
670 FD_SET(hListenSocket, &fdsetRecv);
671 hSocketMax = max(hSocketMax, hListenSocket);
672 CRITICAL_BLOCK(cs_vNodes)
673 {
674 foreach(CNode* pnode, vNodes)
675 {
676 FD_SET(pnode->hSocket, &fdsetRecv);
677 hSocketMax = max(hSocketMax, pnode->hSocket);
678 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
679 if (!pnode->vSend.empty())
680 FD_SET(pnode->hSocket, &fdsetSend);
681 }
682 }
683
684 vfThreadRunning[0] = false;
685 int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, NULL, &timeout);
686 vfThreadRunning[0] = true;
687 CheckForShutdown(0);
688 if (nSelect == SOCKET_ERROR)
689 {
690 int nErr = WSAGetLastError();
691 printf("select failed: %d\n", nErr);
692 for (int i = 0; i <= hSocketMax; i++)
693 {
694 FD_SET(i, &fdsetRecv);
695 FD_SET(i, &fdsetSend);
696 }
697 Sleep(timeout.tv_usec/1000);
698 }
699 RandAddSeed();
700
701 //// debug print
702 //foreach(CNode* pnode, vNodes)
703 //{
704 // printf("vRecv = %-5d ", pnode->vRecv.size());
705 // printf("vSend = %-5d ", pnode->vSend.size());
706 //}
707 //printf("\n");
708
709
710 //
711 // Accept new connections
712 //
713 if (FD_ISSET(hListenSocket, &fdsetRecv))
714 {
715 struct sockaddr_in sockaddr;
716#ifdef _WIN32
717 int len = sizeof(sockaddr);
718#else
719 socklen_t len = sizeof(sockaddr);
720#endif
721 SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
722 CAddress addr(sockaddr);
723 if (hSocket == INVALID_SOCKET)
724 {
725 if (WSAGetLastError() != WSAEWOULDBLOCK)
726 printf("ERROR ThreadSocketHandler accept failed: %d\n", WSAGetLastError());
727 }
728 else
729 {
730 printf("accepted connection from %s\n", addr.ToString().c_str());
731 CNode* pnode = new CNode(hSocket, addr, true);
732 pnode->AddRef();
733 CRITICAL_BLOCK(cs_vNodes)
734 vNodes.push_back(pnode);
735 }
736 }
737
738
739 //
740 // Service each socket
741 //
742 vector<CNode*> vNodesCopy;
743 CRITICAL_BLOCK(cs_vNodes)
744 vNodesCopy = vNodes;
745 foreach(CNode* pnode, vNodesCopy)
746 {
747 CheckForShutdown(0);
748 SOCKET hSocket = pnode->hSocket;
749
750 //
751 // Receive
752 //
753 if (FD_ISSET(hSocket, &fdsetRecv))
754 {
755 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
756 {
757 CDataStream& vRecv = pnode->vRecv;
758 unsigned int nPos = vRecv.size();
759
760 // typical socket buffer is 8K-64K
761 const unsigned int nBufSize = 0x10000;
762 vRecv.resize(nPos + nBufSize);
763 int nBytes = recv(hSocket, &vRecv[nPos], nBufSize, 0);
764 vRecv.resize(nPos + max(nBytes, 0));
765 if (nBytes == 0)
766 {
767 // socket closed gracefully
768 if (!pnode->fDisconnect)
769 printf("recv: socket closed\n");
770 pnode->fDisconnect = true;
771 }
772 else if (nBytes < 0)
773 {
774 // socket error
775 int nErr = WSAGetLastError();
776 if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
777 {
778 if (!pnode->fDisconnect)
779 printf("recv failed: %d\n", nErr);
780 pnode->fDisconnect = true;
781 }
782 }
783 }
784 }
785
786 //
787 // Send
788 //
789 if (FD_ISSET(hSocket, &fdsetSend))
790 {
791 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
792 {
793 CDataStream& vSend = pnode->vSend;
794 if (!vSend.empty())
795 {
796 int nBytes = send(hSocket, &vSend[0], vSend.size(), 0);
797 if (nBytes > 0)
798 {
799 vSend.erase(vSend.begin(), vSend.begin() + nBytes);
800 }
801 else if (nBytes == 0)
802 {
803 if (pnode->ReadyToDisconnect())
804 pnode->vSend.clear();
805 }
806 else
807 {
808 printf("send error %d\n", nBytes);
809 if (pnode->ReadyToDisconnect())
810 pnode->vSend.clear();
811 }
812 }
813 }
814 }
815 }
816
817
818 Sleep(10);
819 }
820}
821
822
823
824
825
826
827
828
829
830
831void ThreadOpenConnections(void* parg)
832{
833 IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
834
835 loop
836 {
837 vfThreadRunning[1] = true;
838 CheckForShutdown(1);
839 try
840 {
841 ThreadOpenConnections2(parg);
842 }
843 CATCH_PRINT_EXCEPTION("ThreadOpenConnections()")
844 vfThreadRunning[1] = false;
845 Sleep(5000);
846 }
847}
848
849void ThreadOpenConnections2(void* parg)
850{
851 printf("ThreadOpenConnections started\n");
852
853 // Initiate network connections
854 const int nMaxConnections = 15;
855 loop
856 {
857 // Wait
858 vfThreadRunning[1] = false;
859 Sleep(500);
860 while (vNodes.size() >= nMaxConnections || vNodes.size() >= mapAddresses.size())
861 {
862 CheckForShutdown(1);
863 Sleep(2000);
864 }
865 vfThreadRunning[1] = true;
866 CheckForShutdown(1);
867
868
869 // Make a list of unique class C's
870 unsigned char pchIPCMask[4] = { 0xff, 0xff, 0xff, 0x00 };
871 unsigned int nIPCMask = *(unsigned int*)pchIPCMask;
872 vector<unsigned int> vIPC;
873 CRITICAL_BLOCK(cs_mapAddresses)
874 {
875 vIPC.reserve(mapAddresses.size());
876 unsigned int nPrev = 0;
877 foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
878 {
879 const CAddress& addr = item.second;
880 if (!addr.IsIPv4())
881 continue;
882
883 // Taking advantage of mapAddresses being in sorted order,
884 // with IPs of the same class C grouped together.
885 unsigned int ipC = addr.ip & nIPCMask;
886 if (ipC != nPrev)
887 vIPC.push_back(nPrev = ipC);
888 }
889 }
890
891 //
892 // The IP selection process is designed to limit vulnerability to address flooding.
893 // Any class C (a.b.c.?) has an equal chance of being chosen, then an IP is
894 // chosen within the class C. An attacker may be able to allocate many IPs, but
895 // they would normally be concentrated in blocks of class C's. They can hog the
896 // attention within their class C, but not the whole IP address space overall.
897 // A lone node in a class C will get as much attention as someone holding all 255
898 // IPs in another class C.
899 //
900 bool fSuccess = false;
901 int nLimit = vIPC.size();
902 while (!fSuccess && nLimit-- > 0)
903 {
904 // Choose a random class C
905 unsigned int ipC = vIPC[GetRand(vIPC.size())];
906
907 // Organize all addresses in the class C by IP
908 map<unsigned int, vector<CAddress> > mapIP;
909 CRITICAL_BLOCK(cs_mapAddresses)
910 {
911 unsigned int nDelay = ((30 * 60) << vNodes.size());
912 if (nDelay > 8 * 60 * 60)
913 nDelay = 8 * 60 * 60;
914 for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.lower_bound(CAddress(ipC, 0).GetKey());
915 mi != mapAddresses.upper_bound(CAddress(ipC | ~nIPCMask, 0xffff).GetKey());
916 ++mi)
917 {
918 const CAddress& addr = (*mi).second;
919 unsigned int nRandomizer = (addr.nLastFailed * addr.ip * 7777U) % 20000;
920 if (GetTime() - addr.nLastFailed > nDelay * nRandomizer / 10000)
921 mapIP[addr.ip].push_back(addr);
922 }
923 }
924 if (mapIP.empty())
925 break;
926
927 // Choose a random IP in the class C
928 map<unsigned int, vector<CAddress> >::iterator mi = mapIP.begin();
929 advance(mi, GetRand(mapIP.size()));
930
931 // Once we've chosen an IP, we'll try every given port before moving on
932 foreach(const CAddress& addrConnect, (*mi).second)
933 {
934 if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
935 continue;
936
937 CNode* pnode = ConnectNode(addrConnect);
938 if (!pnode)
939 continue;
940 pnode->fNetworkNode = true;
941
942 if (addrLocalHost.IsRoutable())
943 {
944 // Advertise our address
945 vector<CAddress> vAddrToSend;
946 vAddrToSend.push_back(addrLocalHost);
947 pnode->PushMessage("addr", vAddrToSend);
948 }
949
950 // Get as many addresses as we can
951 pnode->PushMessage("getaddr");
952
953 ////// should the one on the receiving end do this too?
954 // Subscribe our local subscription list
955 const unsigned int nHops = 0;
956 for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++)
957 if (pnodeLocalHost->vfSubscribe[nChannel])
958 pnode->PushMessage("subscribe", nChannel, nHops);
959
960 fSuccess = true;
961 break;
962 }
963 }
964 }
965}
966
967
968
969
970
971
972
973
974void ThreadMessageHandler(void* parg)
975{
976 IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
977
978 loop
979 {
980 vfThreadRunning[2] = true;
981 CheckForShutdown(2);
982 try
983 {
984 ThreadMessageHandler2(parg);
985 }
986 CATCH_PRINT_EXCEPTION("ThreadMessageHandler()")
987 vfThreadRunning[2] = false;
988 Sleep(5000);
989 }
990}
991
992void ThreadMessageHandler2(void* parg)
993{
994 printf("ThreadMessageHandler started\n");
995 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
996 loop
997 {
998 // Poll the connected nodes for messages
999 vector<CNode*> vNodesCopy;
1000 CRITICAL_BLOCK(cs_vNodes)
1001 vNodesCopy = vNodes;
1002 foreach(CNode* pnode, vNodesCopy)
1003 {
1004 pnode->AddRef();
1005
1006 // Receive messages
1007 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
1008 ProcessMessages(pnode);
1009
1010 // Send messages
1011 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
1012 SendMessages(pnode);
1013
1014 pnode->Release();
1015 }
1016
1017 // Wait and allow messages to bunch up
1018 vfThreadRunning[2] = false;
1019 Sleep(100);
1020 vfThreadRunning[2] = true;
1021 CheckForShutdown(2);
1022 }
1023}
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033//// todo: start one thread per processor, use getenv("NUMBER_OF_PROCESSORS")
1034void ThreadBitcoinMiner(void* parg)
1035{
1036 vfThreadRunning[3] = true;
1037 CheckForShutdown(3);
1038 try
1039 {
1040 bool fRet = BitcoinMiner();
1041 printf("BitcoinMiner returned %s\n\n\n", fRet ? "true" : "false");
1042 }
1043 CATCH_PRINT_EXCEPTION("BitcoinMiner()")
1044 vfThreadRunning[3] = false;
1045}
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057bool StartNode(string& strError)
1058{
1059 strError = "";
1060
1061 // Sockets startup
1062 WSADATA wsadata;
1063 int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
1064 if (ret != NO_ERROR)
1065 {
1066 strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
1067 printf("%s\n", strError.c_str());
1068 return false;
1069 }
1070
1071 // Get local host ip
1072 char pszHostName[255];
1073 if (gethostname(pszHostName, 255) == SOCKET_ERROR)
1074 {
1075 strError = strprintf("Error: Unable to get IP address of this computer (gethostname returned error %d)", WSAGetLastError());
1076 printf("%s\n", strError.c_str());
1077 return false;
1078 }
1079 struct hostent* pHostEnt = gethostbyname(pszHostName);
1080 if (!pHostEnt)
1081 {
1082 strError = strprintf("Error: Unable to get IP address of this computer (gethostbyname returned error %d)", WSAGetLastError());
1083 printf("%s\n", strError.c_str());
1084 return false;
1085 }
1086 addrLocalHost = CAddress(*(long*)(pHostEnt->h_addr_list[0]),
1087 nListenPort,
1088 nLocalServices);
1089 printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
1090
1091 // Create socket for listening for incoming connections
1092 SOCKET hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1093 if (hListenSocket == INVALID_SOCKET)
1094 {
1095 strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
1096 printf("%s\n", strError.c_str());
1097 return false;
1098 }
1099
1100 // Set to nonblocking, incoming connections will also inherit this
1101 u_long nOne = 1;
1102 if (ioctlsocket(hListenSocket, FIONBIO, &nOne) == SOCKET_ERROR)
1103 {
1104 strError = strprintf("Error: Couldn't set properties on socket for incoming connections (ioctlsocket returned error %d)", WSAGetLastError());
1105 printf("%s\n", strError.c_str());
1106 return false;
1107 }
1108
1109 // The sockaddr_in structure specifies the address family,
1110 // IP address, and port for the socket that is being bound
1111 int nRetryLimit = 15;
1112 struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr();
1113 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
1114 {
1115 int nErr = WSAGetLastError();
1116 if (nErr == WSAEADDRINUSE)
1117 strError = strprintf("Error: Unable to bind to port %s on this computer. The program is probably already running.", addrLocalHost.ToString().c_str());
1118 else
1119 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr);
1120 printf("%s\n", strError.c_str());
1121 return false;
1122 }
1123 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str());
1124
1125 // Listen for incoming connections
1126 if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
1127 {
1128 strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
1129 printf("%s\n", strError.c_str());
1130 return false;
1131 }
1132
1133 // Get our external IP address for incoming connections
1134 if (addrIncoming.ip)
1135 addrLocalHost.ip = addrIncoming.ip;
1136
1137 if (GetMyExternalIP(addrLocalHost.ip))
1138 {
1139 addrIncoming = addrLocalHost;
1140 CWalletDB().WriteSetting("addrIncoming", addrIncoming);
1141 }
1142
1143 // Peer discovery over Nostr relays (replaces the old IRC seed)
1144 if (_beginthread(ThreadNostrSeed, 0, NULL) == -1)
1145 printf("Error: _beginthread(ThreadNostrSeed) failed\n");
1146
1147 // Anonymous inbound: this node's .btf hidden service, reachable through the
1148 // meeting relay without exposing our IP or needing a public port.
1149 if (!strBtfMeetingRelay.empty())
1150 if (_beginthread(ThreadBtfAccept, 0, NULL) == -1)
1151 printf("Error: _beginthread(ThreadBtfAccept) failed\n");
1152
1153 // Anonymous outbound: keep a connection to a specific .btf peer, if asked.
1154 if (!strBtfConnect.empty())
1155 if (_beginthread(ThreadBtfConnect, 0, new string(strBtfConnect)) == -1)
1156 printf("Error: _beginthread(ThreadBtfConnect) failed\n");
1157
1158 //
1159 // Start threads
1160 //
1161 if (_beginthread(ThreadSocketHandler, 0, new SOCKET(hListenSocket)) == -1)
1162 {
1163 strError = "Error: _beginthread(ThreadSocketHandler) failed";
1164 printf("%s\n", strError.c_str());
1165 return false;
1166 }
1167
1168 if (_beginthread(ThreadOpenConnections, 0, NULL) == -1)
1169 {
1170 strError = "Error: _beginthread(ThreadOpenConnections) failed";
1171 printf("%s\n", strError.c_str());
1172 return false;
1173 }
1174
1175 if (_beginthread(ThreadMessageHandler, 0, NULL) == -1)
1176 {
1177 strError = "Error: _beginthread(ThreadMessageHandler) failed";
1178 printf("%s\n", strError.c_str());
1179 return false;
1180 }
1181
1182 return true;
1183}
1184
1185bool StopNode()
1186{
1187 printf("StopNode()\n");
1188 fShutdown = true;
1189 nTransactionsUpdated++;
1190 while (count(vfThreadRunning.begin(), vfThreadRunning.end(), true))
1191 Sleep(10);
1192 Sleep(50);
1193
1194 // Sockets shutdown
1195 WSACleanup();
1196 return true;
1197}
1198
1199void CheckForShutdown(int n)
1200{
1201 if (fShutdown)
1202 {
1203 if (n != -1)
1204 vfThreadRunning[n] = false;
1205 _endthread();
1206 }
1207}