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:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp143
1 files changed, 92 insertions, 51 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 31afaf5..bdfb9c3 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -98,46 +98,79 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
98 98
99bool GetMyExternalIP(unsigned int& ipRet) 99bool GetMyExternalIP(unsigned int& ipRet)
100{ 100{
101 // The 2009 whatismyip.com service (fixed IP) no longer exists; this avoids 101 // Try several plain-text IP echo services in order.
102 // stalling startup on TCP timeouts. The external IP may come from Nostr 102 // Each returns just the IPv4 address as the first line of the HTTP body.
103 // relays in the future. 103 struct { const char* host; const char* path; } services[] = {
104 return false; 104 { "api4.ipify.org", "/" },
105 { "icanhazip.com", "/" },
106 { "ipecho.net", "/plain" },
107 { "checkip.amazonaws.com", "/" },
108 };
109
110 for (auto& svc : services)
111 {
112 struct addrinfo hints, *res = NULL;
113 memset(&hints, 0, sizeof(hints));
114 hints.ai_family = AF_INET;
115 hints.ai_socktype = SOCK_STREAM;
116 if (getaddrinfo(svc.host, "80", &hints, &res) != 0 || !res)
117 continue;
105 118
106 CAddress addrConnect("72.233.89.199:80"); // whatismyip.com 198-200 119 SOCKET hSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
120 if (hSocket == INVALID_SOCKET) { freeaddrinfo(res); continue; }
107 121
108 SOCKET hSocket; 122 // 5-second timeout so a dead service doesn't stall startup
109 if (!ConnectSocket(addrConnect, hSocket)) 123#ifdef _WIN32
110 return error("GetMyExternalIP() : connection to %s failed\n", addrConnect.ToString().c_str()); 124 DWORD tv = 5000;
111 125 setsockopt(hSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
112 char* pszGet = 126 setsockopt(hSocket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv));
113 "GET /automation/n09230945.asp HTTP/1.1\r\n" 127#else
114 "Host: www.whatismyip.com\r\n" 128 struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0;
115 "User-Agent: Bitcoin/0.1\r\n" 129 setsockopt(hSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
116 "Connection: close\r\n" 130 setsockopt(hSocket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
117 "\r\n"; 131#endif
118 send(hSocket, pszGet, strlen(pszGet), 0); 132
119 133 if (connect(hSocket, res->ai_addr, (int)res->ai_addrlen) != 0)
120 string strLine;
121 while (RecvLine(hSocket, strLine))
122 {
123 if (strLine.empty())
124 { 134 {
125 if (!RecvLine(hSocket, strLine)) 135 freeaddrinfo(res); closesocket(hSocket); continue;
126 { 136 }
127 closesocket(hSocket); 137 freeaddrinfo(res);
128 return false; 138
129 } 139 string req = string("GET ") + svc.path + " HTTP/1.0\r\nHost: " + svc.host + "\r\nConnection: close\r\n\r\n";
130 closesocket(hSocket); 140 send(hSocket, req.c_str(), (int)req.size(), 0);
131 CAddress addr(strLine.c_str()); 141
132 printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); 142 // Read response, skip HTTP headers, grab first line of body
133 if (addr.ip == 0) 143 string response;
134 return false; 144 char buf[256];
135 ipRet = addr.ip; 145 int n;
136 return true; 146 while ((n = recv(hSocket, buf, sizeof(buf)-1, 0)) > 0)
147 {
148 buf[n] = 0;
149 response += buf;
150 if (response.size() > 4096) break;
137 } 151 }
152 closesocket(hSocket);
153
154 // Find blank line separating headers from body
155 size_t bodyPos = response.find("\r\n\r\n");
156 if (bodyPos == string::npos) bodyPos = response.find("\n\n");
157 if (bodyPos == string::npos) continue;
158 string body = response.substr(bodyPos + (response[bodyPos+2]=='\r' ? 4 : 2));
159
160 // Trim whitespace
161 while (!body.empty() && (body.back() == '\n' || body.back() == '\r' || body.back() == ' '))
162 body.pop_back();
163
164 // Parse as IP
165 CAddress addr(body.c_str());
166 if (addr.ip == 0) continue;
167
168 printf("GetMyExternalIP() via %s: %s\n", svc.host, body.c_str());
169 ipRet = addr.ip;
170 return true;
138 } 171 }
139 closesocket(hSocket); 172
140 return error("GetMyExternalIP() : connection closed\n"); 173 return error("GetMyExternalIP() : all services failed\n");
141} 174}
142 175
143 176
@@ -324,15 +357,15 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
324 return pnode; 357 return pnode;
325 } 358 }
326 359
327 /// debug print 360 if (fDebug)
328 printf("trying %s\n", addrConnect.ToString().c_str()); 361 printf("trying %s\n", addrConnect.ToString().c_str());
329 362
330 // Connect 363 // Connect
331 SOCKET hSocket; 364 SOCKET hSocket;
332 if (ConnectSocket(addrConnect, hSocket)) 365 if (ConnectSocket(addrConnect, hSocket))
333 { 366 {
334 /// debug print 367 if (fDebug)
335 printf("connected %s\n", addrConnect.ToString().c_str()); 368 printf("connected %s\n", addrConnect.ToString().c_str());
336 369
337 // Add node 370 // Add node
338 CNode* pnode = new CNode(hSocket, addrConnect, false); 371 CNode* pnode = new CNode(hSocket, addrConnect, false);
@@ -390,14 +423,15 @@ CNode* ConnectNodeBtf(const string& strBtfAddr)
390 return pnode; 423 return pnode;
391 } 424 }
392 425
393 /// debug print 426 if (fDebug)
394 printf("trying %s\n", strBtfAddr.c_str()); 427 printf("trying %s\n", strBtfAddr.c_str());
395 428
396 string strMeeting; 429 string strMeeting;
397 unsigned char enc_pub[32]; 430 unsigned char enc_pub[32];
398 if (!BtfResolve(strBtfAddr, strMeeting, enc_pub)) 431 if (!BtfResolve(strBtfAddr, strMeeting, enc_pub))
399 { 432 {
400 printf("ConnectNodeBtf: could not resolve a descriptor for %s\n", strBtfAddr.c_str()); 433 if (fDebug)
434 printf("ConnectNodeBtf: could not resolve a descriptor for %s\n", strBtfAddr.c_str());
401 return NULL; 435 return NULL;
402 } 436 }
403 size_t colon = strMeeting.rfind(':'); 437 size_t colon = strMeeting.rfind(':');
@@ -411,12 +445,13 @@ CNode* ConnectNodeBtf(const string& strBtfAddr)
411 btf_socket_t hSocket = btf::BtfClientTunnel(strHost.c_str(), (unsigned short)nPort, pk, enc_pub); 445 btf_socket_t hSocket = btf::BtfClientTunnel(strHost.c_str(), (unsigned short)nPort, pk, enc_pub);
412 if (hSocket == INVALID_SOCKET) 446 if (hSocket == INVALID_SOCKET)
413 { 447 {
414 printf("ConnectNodeBtf: tunnel to %s via %s failed\n", strBtfAddr.c_str(), strMeeting.c_str()); 448 if (fDebug)
449 printf("ConnectNodeBtf: tunnel to %s via %s failed\n", strBtfAddr.c_str(), strMeeting.c_str());
415 return NULL; 450 return NULL;
416 } 451 }
417 452
418 /// debug print 453 if (fDebug)
419 printf("connected %s via rendezvous %s\n", strBtfAddr.c_str(), strMeeting.c_str()); 454 printf("connected %s via rendezvous %s\n", strBtfAddr.c_str(), strMeeting.c_str());
420 455
421 // Add node 456 // Add node
422 pnode = new CNode(hSocket, addr, false); 457 pnode = new CNode(hSocket, addr, false);
@@ -1152,15 +1187,21 @@ bool StartNode(string& strError)
1152 return false; 1187 return false;
1153 } 1188 }
1154 1189
1155 // Get our external IP address for incoming connections 1190 // Get our external IP in a background thread — up to 4 HTTP requests with
1191 // 5s timeouts each could otherwise delay startup by 20s on first run.
1192 // addrIncoming from a previous session is used immediately as a fallback.
1156 if (addrIncoming.ip) 1193 if (addrIncoming.ip)
1157 addrLocalHost.ip = addrIncoming.ip; 1194 addrLocalHost.ip = addrIncoming.ip;
1158 1195
1159 if (GetMyExternalIP(addrLocalHost.ip)) 1196 _beginthread([](void*) {
1160 { 1197 unsigned int ip = addrLocalHost.ip;
1161 addrIncoming = addrLocalHost; 1198 if (GetMyExternalIP(ip)) {
1162 CWalletDB().WriteSetting("addrIncoming", addrIncoming); 1199 addrLocalHost.ip = ip;
1163 } 1200 addrIncoming = addrLocalHost;
1201 CWalletDB().WriteSetting("addrIncoming", addrIncoming);
1202 printf("External IP updated: %s\n", addrLocalHost.ToStringIP().c_str());
1203 }
1204 }, 0, NULL);
1164 1205
1165 // Peer discovery over Nostr relays (replaces the old IRC seed) 1206 // Peer discovery over Nostr relays (replaces the old IRC seed)
1166 if (_beginthread(ThreadNostrSeed, 0, NULL) == -1) 1207 if (_beginthread(ThreadNostrSeed, 0, NULL) == -1)