]>
Commit | Line | Data |
---|---|---|
0a61b0df | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
db0e8ccd | 2 | // Copyright (c) 2009-2013 The Bitcoin developers |
0a61b0df | 3 | // Distributed under the MIT/X11 software license, see the accompanying |
3a25a2b9 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
0a61b0df | 5 | |
35b8af92 CF |
6 | #if defined(HAVE_CONFIG_H) |
7 | #include "bitcoin-config.h" | |
8 | #endif | |
9 | ||
0e4b3175 | 10 | #include "chainparams.h" |
1512d5ce | 11 | #include "db.h" |
40c2614e | 12 | #include "net.h" |
6e68524e | 13 | #include "core.h" |
5fee401f | 14 | #include "addrman.h" |
ed6d0b5f | 15 | #include "ui_interface.h" |
269d9c64 | 16 | #include "script.h" |
0a61b0df | 17 | |
6853e627 | 18 | #ifdef WIN32 |
013df1cc MC |
19 | #include <string.h> |
20 | #endif | |
21 | ||
98148a71 | 22 | #ifndef WIN32 |
23 | #include <fcntl.h> | |
24 | #endif | |
25 | ||
8bb5edc1 MC |
26 | #ifdef USE_UPNP |
27 | #include <miniupnpc/miniwget.h> | |
28 | #include <miniupnpc/miniupnpc.h> | |
29 | #include <miniupnpc/upnpcommands.h> | |
30 | #include <miniupnpc/upnperrors.h> | |
31 | #endif | |
32 | ||
c43da3f1 PW |
33 | // Dump addresses to peers.dat every 15 minutes (900s) |
34 | #define DUMP_ADDRESSES_INTERVAL 900 | |
35b8af92 CF |
35 | #if !defined(HAVE_MSG_NOSIGNAL) |
36 | #define MSG_NOSIGNAL 0 | |
37 | #endif | |
c43da3f1 | 38 | |
223b6f1b WL |
39 | using namespace std; |
40 | using namespace boost; | |
41 | ||
0a61b0df | 42 | static const int MAX_OUTBOUND_CONNECTIONS = 8; |
43 | ||
c59abe25 | 44 | bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); |
0a61b0df | 45 | |
46 | ||
139d2f7c PW |
47 | struct LocalServiceInfo { |
48 | int nScore; | |
49 | int nPort; | |
50 | }; | |
0a61b0df | 51 | |
0a61b0df | 52 | // |
53 | // Global state variables | |
54 | // | |
587f929c | 55 | bool fDiscover = true; |
c2b72ba2 | 56 | uint64 nLocalServices = NODE_NETWORK; |
090e5b40 | 57 | static CCriticalSection cs_mapLocalHost; |
139d2f7c | 58 | static map<CNetAddr, LocalServiceInfo> mapLocalHost; |
090e5b40 | 59 | static bool vfReachable[NET_MAX] = {}; |
457754d2 | 60 | static bool vfLimited[NET_MAX] = {}; |
99860de3 | 61 | static CNode* pnodeLocalHost = NULL; |
6ed71b5e | 62 | static CNode* pnodeSync = NULL; |
bde280b9 | 63 | uint64 nLocalHostNonce = 0; |
8f10a288 | 64 | static std::vector<SOCKET> vhListenSocket; |
5fee401f | 65 | CAddrMan addrman; |
ba29a559 | 66 | int nMaxConnections = 125; |
0a61b0df | 67 | |
68 | vector<CNode*> vNodes; | |
69 | CCriticalSection cs_vNodes; | |
0a61b0df | 70 | map<CInv, CDataStream> mapRelay; |
bde280b9 | 71 | deque<pair<int64, CInv> > vRelayExpiration; |
0a61b0df | 72 | CCriticalSection cs_mapRelay; |
b5afda67 | 73 | limitedmap<CInv, int64> mapAlreadyAskedFor(MAX_INV_SZ); |
0a61b0df | 74 | |
478b01d9 PW |
75 | static deque<string> vOneShots; |
76 | CCriticalSection cs_vOneShots; | |
0a61b0df | 77 | |
b24e6e4d MC |
78 | set<CNetAddr> setservAddNodeAddresses; |
79 | CCriticalSection cs_setservAddNodeAddresses; | |
80 | ||
74088e86 MC |
81 | vector<std::string> vAddedNodes; |
82 | CCriticalSection cs_vAddedNodes; | |
83 | ||
c59abe25 | 84 | static CSemaphore *semOutbound = NULL; |
0a61b0df | 85 | |
501da250 EL |
86 | // Signals for message handling |
87 | static CNodeSignals g_signals; | |
88 | CNodeSignals& GetNodeSignals() { return g_signals; } | |
663224c2 | 89 | |
478b01d9 PW |
90 | void AddOneShot(string strDest) |
91 | { | |
92 | LOCK(cs_vOneShots); | |
93 | vOneShots.push_back(strDest); | |
94 | } | |
95 | ||
00bcfe0b GA |
96 | unsigned short GetListenPort() |
97 | { | |
0e4b3175 | 98 | return (unsigned short)(GetArg("-port", Params().GetDefaultPort())); |
00bcfe0b | 99 | } |
0a61b0df | 100 | |
39857190 | 101 | // find 'best' local address for a particular peer |
7fa4443f | 102 | bool GetLocal(CService& addr, const CNetAddr *paddrPeer) |
39857190 | 103 | { |
587f929c | 104 | if (fNoListen) |
39857190 | 105 | return false; |
0a61b0df | 106 | |
139d2f7c | 107 | int nBestScore = -1; |
39857190 PW |
108 | int nBestReachability = -1; |
109 | { | |
110 | LOCK(cs_mapLocalHost); | |
139d2f7c | 111 | for (map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) |
39857190 | 112 | { |
139d2f7c | 113 | int nScore = (*it).second.nScore; |
39857190 | 114 | int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); |
139d2f7c | 115 | if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) |
39857190 | 116 | { |
139d2f7c | 117 | addr = CService((*it).first, (*it).second.nPort); |
39857190 | 118 | nBestReachability = nReachability; |
139d2f7c | 119 | nBestScore = nScore; |
39857190 PW |
120 | } |
121 | } | |
122 | } | |
139d2f7c | 123 | return nBestScore >= 0; |
39857190 | 124 | } |
0a61b0df | 125 | |
39857190 PW |
126 | // get best local address for a particular peer as a CAddress |
127 | CAddress GetLocalAddress(const CNetAddr *paddrPeer) | |
128 | { | |
129 | CAddress ret(CService("0.0.0.0",0),0); | |
7fa4443f | 130 | CService addr; |
39857190 PW |
131 | if (GetLocal(addr, paddrPeer)) |
132 | { | |
7fa4443f | 133 | ret = CAddress(addr); |
39857190 PW |
134 | ret.nServices = nLocalServices; |
135 | ret.nTime = GetAdjustedTime(); | |
136 | } | |
137 | return ret; | |
138 | } | |
0a61b0df | 139 | |
a3342d09 PW |
140 | bool RecvLine(SOCKET hSocket, string& strLine) |
141 | { | |
142 | strLine = ""; | |
050d2e95 | 143 | while (true) |
a3342d09 PW |
144 | { |
145 | char c; | |
146 | int nBytes = recv(hSocket, &c, 1, 0); | |
147 | if (nBytes > 0) | |
148 | { | |
149 | if (c == '\n') | |
150 | continue; | |
151 | if (c == '\r') | |
152 | return true; | |
153 | strLine += c; | |
154 | if (strLine.size() >= 9000) | |
155 | return true; | |
156 | } | |
157 | else if (nBytes <= 0) | |
158 | { | |
b31499ec | 159 | boost::this_thread::interruption_point(); |
a3342d09 PW |
160 | if (nBytes < 0) |
161 | { | |
162 | int nErr = WSAGetLastError(); | |
163 | if (nErr == WSAEMSGSIZE) | |
164 | continue; | |
165 | if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS) | |
166 | { | |
1b43bf0d | 167 | MilliSleep(10); |
a3342d09 PW |
168 | continue; |
169 | } | |
170 | } | |
171 | if (!strLine.empty()) | |
172 | return true; | |
173 | if (nBytes == 0) | |
174 | { | |
175 | // socket closed | |
881a85a2 | 176 | LogPrint("net", "socket closed\n"); |
a3342d09 PW |
177 | return false; |
178 | } | |
179 | else | |
180 | { | |
181 | // socket error | |
182 | int nErr = WSAGetLastError(); | |
881a85a2 | 183 | LogPrint("net", "recv failed: %d\n", nErr); |
a3342d09 PW |
184 | return false; |
185 | } | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
39857190 PW |
190 | // used when scores of local addresses may have changed |
191 | // pushes better local address to peers | |
192 | void static AdvertizeLocal() | |
193 | { | |
194 | LOCK(cs_vNodes); | |
195 | BOOST_FOREACH(CNode* pnode, vNodes) | |
196 | { | |
197 | if (pnode->fSuccessfullyConnected) | |
198 | { | |
199 | CAddress addrLocal = GetLocalAddress(&pnode->addr); | |
7fa4443f | 200 | if (addrLocal.IsRoutable() && (CService)addrLocal != (CService)pnode->addrLocal) |
39857190 PW |
201 | { |
202 | pnode->PushAddress(addrLocal); | |
203 | pnode->addrLocal = addrLocal; | |
204 | } | |
205 | } | |
206 | } | |
207 | } | |
208 | ||
54ce3bad PW |
209 | void SetReachable(enum Network net, bool fFlag) |
210 | { | |
211 | LOCK(cs_mapLocalHost); | |
212 | vfReachable[net] = fFlag; | |
213 | if (net == NET_IPV6 && fFlag) | |
214 | vfReachable[NET_IPV4] = true; | |
215 | } | |
216 | ||
39857190 | 217 | // learn a new local address |
7fa4443f | 218 | bool AddLocal(const CService& addr, int nScore) |
39857190 PW |
219 | { |
220 | if (!addr.IsRoutable()) | |
221 | return false; | |
222 | ||
587f929c | 223 | if (!fDiscover && nScore < LOCAL_MANUAL) |
af4006b3 PW |
224 | return false; |
225 | ||
09b4e26a | 226 | if (IsLimited(addr)) |
1653f97c PW |
227 | return false; |
228 | ||
881a85a2 | 229 | LogPrintf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore); |
39857190 PW |
230 | |
231 | { | |
232 | LOCK(cs_mapLocalHost); | |
139d2f7c PW |
233 | bool fAlready = mapLocalHost.count(addr) > 0; |
234 | LocalServiceInfo &info = mapLocalHost[addr]; | |
235 | if (!fAlready || nScore >= info.nScore) { | |
af4da4be PW |
236 | info.nScore = nScore + (fAlready ? 1 : 0); |
237 | info.nPort = addr.GetPort(); | |
139d2f7c | 238 | } |
54ce3bad | 239 | SetReachable(addr.GetNetwork()); |
39857190 PW |
240 | } |
241 | ||
242 | AdvertizeLocal(); | |
243 | ||
244 | return true; | |
245 | } | |
246 | ||
5a3cb32e | 247 | bool AddLocal(const CNetAddr &addr, int nScore) |
7fa4443f | 248 | { |
5a3cb32e | 249 | return AddLocal(CService(addr, GetListenPort()), nScore); |
7fa4443f PW |
250 | } |
251 | ||
457754d2 PW |
252 | /** Make a particular network entirely off-limits (no automatic connects to it) */ |
253 | void SetLimited(enum Network net, bool fLimited) | |
254 | { | |
0f1707de PW |
255 | if (net == NET_UNROUTABLE) |
256 | return; | |
457754d2 PW |
257 | LOCK(cs_mapLocalHost); |
258 | vfLimited[net] = fLimited; | |
259 | } | |
260 | ||
0f1707de | 261 | bool IsLimited(enum Network net) |
457754d2 PW |
262 | { |
263 | LOCK(cs_mapLocalHost); | |
0f1707de PW |
264 | return vfLimited[net]; |
265 | } | |
266 | ||
267 | bool IsLimited(const CNetAddr &addr) | |
268 | { | |
269 | return IsLimited(addr.GetNetwork()); | |
457754d2 PW |
270 | } |
271 | ||
272 | /** vote for a local address */ | |
7fa4443f | 273 | bool SeenLocal(const CService& addr) |
39857190 PW |
274 | { |
275 | { | |
276 | LOCK(cs_mapLocalHost); | |
277 | if (mapLocalHost.count(addr) == 0) | |
278 | return false; | |
139d2f7c | 279 | mapLocalHost[addr].nScore++; |
39857190 PW |
280 | } |
281 | ||
282 | AdvertizeLocal(); | |
283 | ||
284 | return true; | |
285 | } | |
286 | ||
457754d2 | 287 | /** check whether a given address is potentially local */ |
7fa4443f | 288 | bool IsLocal(const CService& addr) |
39857190 PW |
289 | { |
290 | LOCK(cs_mapLocalHost); | |
291 | return mapLocalHost.count(addr) > 0; | |
292 | } | |
0a61b0df | 293 | |
457754d2 | 294 | /** check whether a given address is in a network we can probably connect to */ |
090e5b40 PW |
295 | bool IsReachable(const CNetAddr& addr) |
296 | { | |
297 | LOCK(cs_mapLocalHost); | |
457754d2 PW |
298 | enum Network net = addr.GetNetwork(); |
299 | return vfReachable[net] && !vfLimited[net]; | |
090e5b40 | 300 | } |
0a61b0df | 301 | |
67a42f92 | 302 | bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) |
0a61b0df | 303 | { |
304 | SOCKET hSocket; | |
305 | if (!ConnectSocket(addrConnect, hSocket)) | |
306 | return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str()); | |
307 | ||
308 | send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL); | |
309 | ||
310 | string strLine; | |
311 | while (RecvLine(hSocket, strLine)) | |
312 | { | |
222e3de4 | 313 | if (strLine.empty()) // HTTP response is separated from headers by blank line |
0a61b0df | 314 | { |
050d2e95 | 315 | while (true) |
0a61b0df | 316 | { |
317 | if (!RecvLine(hSocket, strLine)) | |
318 | { | |
319 | closesocket(hSocket); | |
320 | return false; | |
321 | } | |
222e3de4 | 322 | if (pszKeyword == NULL) |
323 | break; | |
ab9dc75a | 324 | if (strLine.find(pszKeyword) != string::npos) |
0a61b0df | 325 | { |
326 | strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword)); | |
327 | break; | |
328 | } | |
329 | } | |
330 | closesocket(hSocket); | |
ab9dc75a | 331 | if (strLine.find("<") != string::npos) |
0a61b0df | 332 | strLine = strLine.substr(0, strLine.find("<")); |
333 | strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r")); | |
334 | while (strLine.size() > 0 && isspace(strLine[strLine.size()-1])) | |
335 | strLine.resize(strLine.size()-1); | |
67a42f92 | 336 | CService addr(strLine,0,true); |
881a85a2 | 337 | LogPrintf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); |
67a42f92 | 338 | if (!addr.IsValid() || !addr.IsRoutable()) |
0a61b0df | 339 | return false; |
67a42f92 | 340 | ipRet.SetIP(addr); |
0a61b0df | 341 | return true; |
342 | } | |
343 | } | |
344 | closesocket(hSocket); | |
345 | return error("GetMyExternalIP() : connection closed"); | |
346 | } | |
347 | ||
67a42f92 | 348 | bool GetMyExternalIP(CNetAddr& ipRet) |
0a61b0df | 349 | { |
c981d768 | 350 | CService addrConnect; |
0a61b0df | 351 | const char* pszGet; |
352 | const char* pszKeyword; | |
353 | ||
0a61b0df | 354 | for (int nLookup = 0; nLookup <= 1; nLookup++) |
355 | for (int nHost = 1; nHost <= 2; nHost++) | |
356 | { | |
b001c871 | 357 | // We should be phasing out our use of sites like these. If we need |
629e37dd | 358 | // replacements, we should ask for volunteers to put this simple |
814efd6f | 359 | // php file on their web server that prints the client IP: |
629e37dd | 360 | // <?php echo $_SERVER["REMOTE_ADDR"]; ?> |
0a61b0df | 361 | if (nHost == 1) |
362 | { | |
b001c871 | 363 | addrConnect = CService("91.198.22.70", 80); // checkip.dyndns.org |
0a61b0df | 364 | |
365 | if (nLookup == 1) | |
366 | { | |
67a42f92 | 367 | CService addrIP("checkip.dyndns.org", 80, true); |
a6a5bb7c PW |
368 | if (addrIP.IsValid()) |
369 | addrConnect = addrIP; | |
0a61b0df | 370 | } |
371 | ||
683bcb91 | 372 | pszGet = "GET / HTTP/1.1\r\n" |
373 | "Host: checkip.dyndns.org\r\n" | |
374 | "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" | |
0a61b0df | 375 | "Connection: close\r\n" |
376 | "\r\n"; | |
377 | ||
683bcb91 | 378 | pszKeyword = "Address:"; |
0a61b0df | 379 | } |
380 | else if (nHost == 2) | |
381 | { | |
c981d768 | 382 | addrConnect = CService("74.208.43.192", 80); // www.showmyip.com |
0a61b0df | 383 | |
384 | if (nLookup == 1) | |
385 | { | |
67a42f92 | 386 | CService addrIP("www.showmyip.com", 80, true); |
a6a5bb7c PW |
387 | if (addrIP.IsValid()) |
388 | addrConnect = addrIP; | |
0a61b0df | 389 | } |
390 | ||
683bcb91 | 391 | pszGet = "GET /simple/ HTTP/1.1\r\n" |
392 | "Host: www.showmyip.com\r\n" | |
0a61b0df | 393 | "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" |
394 | "Connection: close\r\n" | |
395 | "\r\n"; | |
396 | ||
683bcb91 | 397 | pszKeyword = NULL; // Returns just IP address |
0a61b0df | 398 | } |
399 | ||
400 | if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet)) | |
401 | return true; | |
402 | } | |
403 | ||
404 | return false; | |
405 | } | |
406 | ||
53e71135 | 407 | void ThreadGetMyExternalIP() |
629e37dd | 408 | { |
39857190 | 409 | CNetAddr addrLocalHost; |
67a42f92 | 410 | if (GetMyExternalIP(addrLocalHost)) |
629e37dd | 411 | { |
881a85a2 | 412 | LogPrintf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str()); |
39857190 | 413 | AddLocal(addrLocalHost, LOCAL_HTTP); |
629e37dd | 414 | } |
415 | } | |
416 | ||
0a61b0df | 417 | |
418 | ||
419 | ||
420 | ||
67a42f92 | 421 | void AddressCurrentlyConnected(const CService& addr) |
0a61b0df | 422 | { |
5fee401f | 423 | addrman.Connected(addr); |
0a61b0df | 424 | } |
425 | ||
426 | ||
427 | ||
428 | ||
ce14345a SE |
429 | uint64 CNode::nTotalBytesRecv = 0; |
430 | uint64 CNode::nTotalBytesSent = 0; | |
431 | CCriticalSection CNode::cs_totalBytesRecv; | |
432 | CCriticalSection CNode::cs_totalBytesSent; | |
0a61b0df | 433 | |
67a42f92 | 434 | CNode* FindNode(const CNetAddr& ip) |
0a61b0df | 435 | { |
b001c871 PK |
436 | LOCK(cs_vNodes); |
437 | BOOST_FOREACH(CNode* pnode, vNodes) | |
438 | if ((CNetAddr)pnode->addr == ip) | |
439 | return (pnode); | |
0a61b0df | 440 | return NULL; |
441 | } | |
442 | ||
9bab521d PW |
443 | CNode* FindNode(std::string addrName) |
444 | { | |
445 | LOCK(cs_vNodes); | |
446 | BOOST_FOREACH(CNode* pnode, vNodes) | |
447 | if (pnode->addrName == addrName) | |
448 | return (pnode); | |
449 | return NULL; | |
450 | } | |
451 | ||
67a42f92 | 452 | CNode* FindNode(const CService& addr) |
0a61b0df | 453 | { |
b001c871 PK |
454 | LOCK(cs_vNodes); |
455 | BOOST_FOREACH(CNode* pnode, vNodes) | |
456 | if ((CService)pnode->addr == addr) | |
457 | return (pnode); | |
0a61b0df | 458 | return NULL; |
459 | } | |
460 | ||
cedaa714 | 461 | CNode* ConnectNode(CAddress addrConnect, const char *pszDest) |
0a61b0df | 462 | { |
478b01d9 | 463 | if (pszDest == NULL) { |
39857190 | 464 | if (IsLocal(addrConnect)) |
9bab521d | 465 | return NULL; |
0a61b0df | 466 | |
9bab521d PW |
467 | // Look for an existing connection |
468 | CNode* pnode = FindNode((CService)addrConnect); | |
469 | if (pnode) | |
470 | { | |
cedaa714 | 471 | pnode->AddRef(); |
9bab521d PW |
472 | return pnode; |
473 | } | |
0a61b0df | 474 | } |
475 | ||
9bab521d | 476 | |
0a61b0df | 477 | /// debug print |
881a85a2 | 478 | LogPrint("net", "trying connection %s lastseen=%.1fhrs\n", |
9bab521d | 479 | pszDest ? pszDest : addrConnect.ToString().c_str(), |
83e047ea | 480 | pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0); |
0a61b0df | 481 | |
482 | // Connect | |
483 | SOCKET hSocket; | |
0e4b3175 | 484 | if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort()) : ConnectSocket(addrConnect, hSocket)) |
0a61b0df | 485 | { |
9bab521d PW |
486 | addrman.Attempt(addrConnect); |
487 | ||
881a85a2 | 488 | LogPrint("net", "connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str()); |
0a61b0df | 489 | |
814efd6f | 490 | // Set to non-blocking |
6853e627 | 491 | #ifdef WIN32 |
0a61b0df | 492 | u_long nOne = 1; |
493 | if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) | |
881a85a2 | 494 | LogPrintf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError()); |
0a61b0df | 495 | #else |
496 | if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) | |
881a85a2 | 497 | LogPrintf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno); |
0a61b0df | 498 | #endif |
499 | ||
500 | // Add node | |
9bab521d | 501 | CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); |
cedaa714 | 502 | pnode->AddRef(); |
9bab521d | 503 | |
f8dcd5ca PW |
504 | { |
505 | LOCK(cs_vNodes); | |
0a61b0df | 506 | vNodes.push_back(pnode); |
f8dcd5ca | 507 | } |
0a61b0df | 508 | |
509 | pnode->nTimeConnected = GetTime(); | |
510 | return pnode; | |
511 | } | |
512 | else | |
513 | { | |
514 | return NULL; | |
515 | } | |
516 | } | |
517 | ||
518 | void CNode::CloseSocketDisconnect() | |
519 | { | |
520 | fDisconnect = true; | |
521 | if (hSocket != INVALID_SOCKET) | |
522 | { | |
881a85a2 | 523 | LogPrint("net", "disconnecting node %s\n", addrName.c_str()); |
0a61b0df | 524 | closesocket(hSocket); |
525 | hSocket = INVALID_SOCKET; | |
526 | } | |
6ed71b5e PW |
527 | |
528 | // in case this fails, we'll empty the recv buffer when the CNode is deleted | |
529 | TRY_LOCK(cs_vRecvMsg, lockRecv); | |
530 | if (lockRecv) | |
531 | vRecvMsg.clear(); | |
532 | ||
533 | // if this was the sync node, we'll need a new one | |
534 | if (this == pnodeSync) | |
535 | pnodeSync = NULL; | |
0a61b0df | 536 | } |
537 | ||
538 | void CNode::Cleanup() | |
539 | { | |
0a61b0df | 540 | } |
541 | ||
542 | ||
f8ded588 GA |
543 | void CNode::PushVersion() |
544 | { | |
4c6d41b8 PW |
545 | int nBestHeight = g_signals.GetHeight().get_value_or(0); |
546 | ||
f8ded588 | 547 | /// when NTP implemented, change to just nTime = GetAdjustedTime() |
bde280b9 | 548 | int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); |
587f929c | 549 | CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0))); |
39857190 | 550 | CAddress addrMe = GetLocalAddress(&addr); |
f8ded588 | 551 | RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); |
881a85a2 | 552 | LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString().c_str(), addrYou.ToString().c_str(), addr.ToString().c_str()); |
f8ded588 | 553 | PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, |
c87f462b | 554 | nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight, true); |
f8ded588 GA |
555 | } |
556 | ||
557 | ||
558 | ||
559 | ||
560 | ||
67a42f92 | 561 | std::map<CNetAddr, int64> CNode::setBanned; |
15f3ad4d GA |
562 | CCriticalSection CNode::cs_setBanned; |
563 | ||
564 | void CNode::ClearBanned() | |
565 | { | |
566 | setBanned.clear(); | |
567 | } | |
568 | ||
67a42f92 | 569 | bool CNode::IsBanned(CNetAddr ip) |
15f3ad4d GA |
570 | { |
571 | bool fResult = false; | |
15f3ad4d | 572 | { |
f8dcd5ca | 573 | LOCK(cs_setBanned); |
67a42f92 | 574 | std::map<CNetAddr, int64>::iterator i = setBanned.find(ip); |
15f3ad4d GA |
575 | if (i != setBanned.end()) |
576 | { | |
bde280b9 | 577 | int64 t = (*i).second; |
15f3ad4d GA |
578 | if (GetTime() < t) |
579 | fResult = true; | |
580 | } | |
581 | } | |
582 | return fResult; | |
583 | } | |
584 | ||
585 | bool CNode::Misbehaving(int howmuch) | |
586 | { | |
587 | if (addr.IsLocal()) | |
588 | { | |
881a85a2 | 589 | LogPrintf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch); |
15f3ad4d GA |
590 | return false; |
591 | } | |
592 | ||
593 | nMisbehavior += howmuch; | |
594 | if (nMisbehavior >= GetArg("-banscore", 100)) | |
595 | { | |
bde280b9 | 596 | int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban |
881a85a2 | 597 | LogPrintf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior); |
f8dcd5ca PW |
598 | { |
599 | LOCK(cs_setBanned); | |
67a42f92 PW |
600 | if (setBanned[addr] < banTime) |
601 | setBanned[addr] = banTime; | |
f8dcd5ca | 602 | } |
15f3ad4d | 603 | CloseSocketDisconnect(); |
15f3ad4d | 604 | return true; |
90c838da | 605 | } else |
881a85a2 | 606 | LogPrintf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior); |
15f3ad4d GA |
607 | return false; |
608 | } | |
609 | ||
1006f070 JG |
610 | #undef X |
611 | #define X(name) stats.name = name | |
612 | void CNode::copyStats(CNodeStats &stats) | |
613 | { | |
614 | X(nServices); | |
615 | X(nLastSend); | |
616 | X(nLastRecv); | |
617 | X(nTimeConnected); | |
618 | X(addrName); | |
619 | X(nVersion); | |
620 | X(strSubVer); | |
621 | X(fInbound); | |
1006f070 JG |
622 | X(nStartingHeight); |
623 | X(nMisbehavior); | |
86648a8d PW |
624 | X(nSendBytes); |
625 | X(nRecvBytes); | |
626 | stats.fSyncNode = (this == pnodeSync); | |
971bb3e9 JL |
627 | |
628 | // It is common for nodes with good ping times to suddenly become lagged, | |
629 | // due to a new block arriving or other large transfer. | |
630 | // Merely reporting pingtime might fool the caller into thinking the node was still responsive, | |
631 | // since pingtime does not update until the ping is complete, which might take a while. | |
632 | // So, if a ping is taking an unusually long time in flight, | |
633 | // the caller can immediately detect that this is happening. | |
634 | int64 nPingUsecWait = 0; | |
635 | if ((0 != nPingNonceSent) && (0 != nPingUsecStart)) { | |
636 | nPingUsecWait = GetTimeMicros() - nPingUsecStart; | |
637 | } | |
638 | ||
639 | // Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :) | |
640 | stats.dPingTime = (((double)nPingUsecTime) / 1e6); | |
641 | stats.dPingWait = (((double)nPingUsecWait) / 1e6); | |
1006f070 JG |
642 | } |
643 | #undef X | |
0a61b0df | 644 | |
607dbfde JG |
645 | // requires LOCK(cs_vRecvMsg) |
646 | bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes) | |
647 | { | |
648 | while (nBytes > 0) { | |
649 | ||
650 | // get current incomplete message, or create a new one | |
967f2459 | 651 | if (vRecvMsg.empty() || |
607dbfde JG |
652 | vRecvMsg.back().complete()) |
653 | vRecvMsg.push_back(CNetMessage(SER_NETWORK, nRecvVersion)); | |
654 | ||
655 | CNetMessage& msg = vRecvMsg.back(); | |
656 | ||
657 | // absorb network data | |
658 | int handled; | |
659 | if (!msg.in_data) | |
660 | handled = msg.readHeader(pch, nBytes); | |
661 | else | |
662 | handled = msg.readData(pch, nBytes); | |
663 | ||
664 | if (handled < 0) | |
665 | return false; | |
666 | ||
667 | pch += handled; | |
668 | nBytes -= handled; | |
669 | } | |
670 | ||
671 | return true; | |
672 | } | |
673 | ||
674 | int CNetMessage::readHeader(const char *pch, unsigned int nBytes) | |
675 | { | |
676 | // copy data to temporary parsing buffer | |
677 | unsigned int nRemaining = 24 - nHdrPos; | |
678 | unsigned int nCopy = std::min(nRemaining, nBytes); | |
679 | ||
680 | memcpy(&hdrbuf[nHdrPos], pch, nCopy); | |
681 | nHdrPos += nCopy; | |
682 | ||
683 | // if header incomplete, exit | |
684 | if (nHdrPos < 24) | |
685 | return nCopy; | |
686 | ||
687 | // deserialize to CMessageHeader | |
688 | try { | |
689 | hdrbuf >> hdr; | |
690 | } | |
691 | catch (std::exception &e) { | |
692 | return -1; | |
693 | } | |
694 | ||
695 | // reject messages larger than MAX_SIZE | |
696 | if (hdr.nMessageSize > MAX_SIZE) | |
697 | return -1; | |
698 | ||
699 | // switch state to reading message data | |
700 | in_data = true; | |
701 | vRecv.resize(hdr.nMessageSize); | |
702 | ||
703 | return nCopy; | |
704 | } | |
705 | ||
706 | int CNetMessage::readData(const char *pch, unsigned int nBytes) | |
707 | { | |
708 | unsigned int nRemaining = hdr.nMessageSize - nDataPos; | |
709 | unsigned int nCopy = std::min(nRemaining, nBytes); | |
710 | ||
711 | memcpy(&vRecv[nDataPos], pch, nCopy); | |
712 | nDataPos += nCopy; | |
713 | ||
714 | return nCopy; | |
715 | } | |
716 | ||
0a61b0df | 717 | |
718 | ||
719 | ||
720 | ||
721 | ||
722 | ||
723 | ||
724 | ||
bc2f5aa7 JG |
725 | // requires LOCK(cs_vSend) |
726 | void SocketSendData(CNode *pnode) | |
727 | { | |
41b052ad PW |
728 | std::deque<CSerializeData>::iterator it = pnode->vSendMsg.begin(); |
729 | ||
730 | while (it != pnode->vSendMsg.end()) { | |
731 | const CSerializeData &data = *it; | |
732 | assert(data.size() > pnode->nSendOffset); | |
733 | int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); | |
734 | if (nBytes > 0) { | |
735 | pnode->nLastSend = GetTime(); | |
86648a8d | 736 | pnode->nSendBytes += nBytes; |
41b052ad | 737 | pnode->nSendOffset += nBytes; |
ce14345a | 738 | pnode->RecordBytesSent(nBytes); |
41b052ad PW |
739 | if (pnode->nSendOffset == data.size()) { |
740 | pnode->nSendOffset = 0; | |
741 | pnode->nSendSize -= data.size(); | |
742 | it++; | |
743 | } else { | |
744 | // could not send full message; stop sending more | |
745 | break; | |
746 | } | |
747 | } else { | |
748 | if (nBytes < 0) { | |
749 | // error | |
750 | int nErr = WSAGetLastError(); | |
751 | if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | |
752 | { | |
881a85a2 | 753 | LogPrintf("socket send error %d\n", nErr); |
41b052ad PW |
754 | pnode->CloseSocketDisconnect(); |
755 | } | |
756 | } | |
757 | // couldn't send anything at all | |
758 | break; | |
bc2f5aa7 JG |
759 | } |
760 | } | |
41b052ad PW |
761 | |
762 | if (it == pnode->vSendMsg.end()) { | |
763 | assert(pnode->nSendOffset == 0); | |
764 | assert(pnode->nSendSize == 0); | |
765 | } | |
766 | pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it); | |
bc2f5aa7 | 767 | } |
0a61b0df | 768 | |
3427517d PW |
769 | static list<CNode*> vNodesDisconnected; |
770 | ||
21eb5ada | 771 | void ThreadSocketHandler() |
0a61b0df | 772 | { |
735a6069 | 773 | unsigned int nPrevNodeCount = 0; |
050d2e95 | 774 | while (true) |
0a61b0df | 775 | { |
776 | // | |
777 | // Disconnect nodes | |
778 | // | |
0a61b0df | 779 | { |
f8dcd5ca | 780 | LOCK(cs_vNodes); |
0a61b0df | 781 | // Disconnect unused nodes |
782 | vector<CNode*> vNodesCopy = vNodes; | |
223b6f1b | 783 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 784 | { |
785 | if (pnode->fDisconnect || | |
41b052ad | 786 | (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty())) |
0a61b0df | 787 | { |
788 | // remove from vNodes | |
789 | vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); | |
790 | ||
c59abe25 PW |
791 | // release outbound grant (if any) |
792 | pnode->grantOutbound.Release(); | |
092631f0 | 793 | |
0a61b0df | 794 | // close socket and cleanup |
795 | pnode->CloseSocketDisconnect(); | |
796 | pnode->Cleanup(); | |
797 | ||
798 | // hold in disconnected pool until all refs are released | |
0a61b0df | 799 | if (pnode->fNetworkNode || pnode->fInbound) |
800 | pnode->Release(); | |
801 | vNodesDisconnected.push_back(pnode); | |
802 | } | |
803 | } | |
49d754d9 PW |
804 | } |
805 | { | |
0a61b0df | 806 | // Delete disconnected nodes |
807 | list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected; | |
223b6f1b | 808 | BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy) |
0a61b0df | 809 | { |
810 | // wait until threads are done using it | |
811 | if (pnode->GetRefCount() <= 0) | |
812 | { | |
813 | bool fDelete = false; | |
f8dcd5ca PW |
814 | { |
815 | TRY_LOCK(pnode->cs_vSend, lockSend); | |
816 | if (lockSend) | |
817 | { | |
607dbfde | 818 | TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); |
f8dcd5ca PW |
819 | if (lockRecv) |
820 | { | |
529a4d48 WL |
821 | TRY_LOCK(pnode->cs_inventory, lockInv); |
822 | if (lockInv) | |
823 | fDelete = true; | |
f8dcd5ca PW |
824 | } |
825 | } | |
826 | } | |
0a61b0df | 827 | if (fDelete) |
828 | { | |
829 | vNodesDisconnected.remove(pnode); | |
830 | delete pnode; | |
831 | } | |
832 | } | |
833 | } | |
834 | } | |
ce14345a | 835 | if(vNodes.size() != nPrevNodeCount) { |
0a61b0df | 836 | nPrevNodeCount = vNodes.size(); |
ce14345a | 837 | uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount); |
0a61b0df | 838 | } |
839 | ||
840 | ||
841 | // | |
842 | // Find which sockets have data to receive | |
843 | // | |
844 | struct timeval timeout; | |
845 | timeout.tv_sec = 0; | |
846 | timeout.tv_usec = 50000; // frequency to poll pnode->vSend | |
847 | ||
848 | fd_set fdsetRecv; | |
849 | fd_set fdsetSend; | |
850 | fd_set fdsetError; | |
851 | FD_ZERO(&fdsetRecv); | |
852 | FD_ZERO(&fdsetSend); | |
853 | FD_ZERO(&fdsetError); | |
854 | SOCKET hSocketMax = 0; | |
23879447 | 855 | bool have_fds = false; |
5f88e888 | 856 | |
8f10a288 | 857 | BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) { |
5f88e888 | 858 | FD_SET(hListenSocket, &fdsetRecv); |
8f10a288 | 859 | hSocketMax = max(hSocketMax, hListenSocket); |
23879447 | 860 | have_fds = true; |
8f10a288 | 861 | } |
0a61b0df | 862 | { |
f8dcd5ca | 863 | LOCK(cs_vNodes); |
223b6f1b | 864 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 865 | { |
d7f1d200 | 866 | if (pnode->hSocket == INVALID_SOCKET) |
0a61b0df | 867 | continue; |
a9d9f0f5 PW |
868 | FD_SET(pnode->hSocket, &fdsetError); |
869 | hSocketMax = max(hSocketMax, pnode->hSocket); | |
870 | have_fds = true; | |
871 | ||
872 | // Implement the following logic: | |
873 | // * If there is data to send, select() for sending data. As this only | |
874 | // happens when optimistic write failed, we choose to first drain the | |
875 | // write buffer in this case before receiving more. This avoids | |
876 | // needlessly queueing received data, if the remote peer is not themselves | |
877 | // receiving data. This means properly utilizing TCP flow control signalling. | |
878 | // * Otherwise, if there is no (complete) message in the receive buffer, | |
879 | // or there is space left in the buffer, select() for receiving data. | |
880 | // * (if neither of the above applies, there is certainly one message | |
881 | // in the receiver buffer ready to be processed). | |
882 | // Together, that means that at least one of the following is always possible, | |
883 | // so we don't deadlock: | |
884 | // * We send some data. | |
885 | // * We wait for data to be received (and disconnect after timeout). | |
886 | // * We process a message in the buffer (message handler thread). | |
f8dcd5ca PW |
887 | { |
888 | TRY_LOCK(pnode->cs_vSend, lockSend); | |
a9d9f0f5 PW |
889 | if (lockSend && !pnode->vSendMsg.empty()) { |
890 | FD_SET(pnode->hSocket, &fdsetSend); | |
891 | continue; | |
b9ff2970 | 892 | } |
f8dcd5ca | 893 | } |
a9d9f0f5 PW |
894 | { |
895 | TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); | |
896 | if (lockRecv && ( | |
897 | pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() || | |
898 | pnode->GetTotalRecvSize() <= ReceiveFloodSize())) | |
899 | FD_SET(pnode->hSocket, &fdsetRecv); | |
900 | } | |
0a61b0df | 901 | } |
902 | } | |
903 | ||
23879447 JG |
904 | int nSelect = select(have_fds ? hSocketMax + 1 : 0, |
905 | &fdsetRecv, &fdsetSend, &fdsetError, &timeout); | |
21eb5ada GA |
906 | boost::this_thread::interruption_point(); |
907 | ||
0a61b0df | 908 | if (nSelect == SOCKET_ERROR) |
909 | { | |
23879447 | 910 | if (have_fds) |
c6710c7a | 911 | { |
23879447 | 912 | int nErr = WSAGetLastError(); |
881a85a2 | 913 | LogPrintf("socket select error %d\n", nErr); |
c376ac35 | 914 | for (unsigned int i = 0; i <= hSocketMax; i++) |
c6710c7a MC |
915 | FD_SET(i, &fdsetRecv); |
916 | } | |
0a61b0df | 917 | FD_ZERO(&fdsetSend); |
918 | FD_ZERO(&fdsetError); | |
1b43bf0d | 919 | MilliSleep(timeout.tv_usec/1000); |
0a61b0df | 920 | } |
921 | ||
922 | ||
923 | // | |
924 | // Accept new connections | |
925 | // | |
8f10a288 | 926 | BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) |
5f88e888 | 927 | if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv)) |
0a61b0df | 928 | { |
23aa78c4 | 929 | #ifdef USE_IPV6 |
8f10a288 | 930 | struct sockaddr_storage sockaddr; |
23aa78c4 | 931 | #else |
8f10a288 | 932 | struct sockaddr sockaddr; |
23aa78c4 | 933 | #endif |
0a61b0df | 934 | socklen_t len = sizeof(sockaddr); |
935 | SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); | |
25ab1758 | 936 | CAddress addr; |
4698dd9a CM |
937 | int nInbound = 0; |
938 | ||
25ab1758 | 939 | if (hSocket != INVALID_SOCKET) |
8f10a288 | 940 | if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) |
881a85a2 | 941 | LogPrintf("Warning: Unknown socket family\n"); |
25ab1758 | 942 | |
f8dcd5ca PW |
943 | { |
944 | LOCK(cs_vNodes); | |
223b6f1b | 945 | BOOST_FOREACH(CNode* pnode, vNodes) |
f8dcd5ca PW |
946 | if (pnode->fInbound) |
947 | nInbound++; | |
948 | } | |
25ab1758 | 949 | |
0a61b0df | 950 | if (hSocket == INVALID_SOCKET) |
951 | { | |
4bd34b49 PK |
952 | int nErr = WSAGetLastError(); |
953 | if (nErr != WSAEWOULDBLOCK) | |
881a85a2 | 954 | LogPrintf("socket error accept failed: %d\n", nErr); |
0a61b0df | 955 | } |
ba29a559 | 956 | else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) |
0a61b0df | 957 | { |
f8dcd5ca PW |
958 | { |
959 | LOCK(cs_setservAddNodeAddresses); | |
b24e6e4d MC |
960 | if (!setservAddNodeAddresses.count(addr)) |
961 | closesocket(hSocket); | |
f8dcd5ca | 962 | } |
0a61b0df | 963 | } |
67a42f92 | 964 | else if (CNode::IsBanned(addr)) |
15f3ad4d | 965 | { |
881a85a2 | 966 | LogPrintf("connection from %s dropped (banned)\n", addr.ToString().c_str()); |
15f3ad4d GA |
967 | closesocket(hSocket); |
968 | } | |
0a61b0df | 969 | else |
970 | { | |
881a85a2 | 971 | LogPrint("net", "accepted connection %s\n", addr.ToString().c_str()); |
9bab521d | 972 | CNode* pnode = new CNode(hSocket, addr, "", true); |
0a61b0df | 973 | pnode->AddRef(); |
f8dcd5ca PW |
974 | { |
975 | LOCK(cs_vNodes); | |
0a61b0df | 976 | vNodes.push_back(pnode); |
f8dcd5ca | 977 | } |
0a61b0df | 978 | } |
979 | } | |
980 | ||
981 | ||
982 | // | |
983 | // Service each socket | |
984 | // | |
985 | vector<CNode*> vNodesCopy; | |
0a61b0df | 986 | { |
f8dcd5ca | 987 | LOCK(cs_vNodes); |
0a61b0df | 988 | vNodesCopy = vNodes; |
223b6f1b | 989 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 990 | pnode->AddRef(); |
991 | } | |
223b6f1b | 992 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 993 | { |
21eb5ada | 994 | boost::this_thread::interruption_point(); |
0a61b0df | 995 | |
996 | // | |
997 | // Receive | |
998 | // | |
999 | if (pnode->hSocket == INVALID_SOCKET) | |
1000 | continue; | |
1001 | if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError)) | |
1002 | { | |
607dbfde | 1003 | TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); |
f8dcd5ca | 1004 | if (lockRecv) |
0a61b0df | 1005 | { |
a9d9f0f5 | 1006 | { |
9cbae55a GA |
1007 | // typical socket buffer is 8K-64K |
1008 | char pchBuf[0x10000]; | |
1009 | int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); | |
1010 | if (nBytes > 0) | |
0a61b0df | 1011 | { |
607dbfde JG |
1012 | if (!pnode->ReceiveMsgBytes(pchBuf, nBytes)) |
1013 | pnode->CloseSocketDisconnect(); | |
9cbae55a | 1014 | pnode->nLastRecv = GetTime(); |
86648a8d | 1015 | pnode->nRecvBytes += nBytes; |
ce14345a | 1016 | pnode->RecordBytesRecv(nBytes); |
9cbae55a GA |
1017 | } |
1018 | else if (nBytes == 0) | |
1019 | { | |
1020 | // socket closed gracefully | |
0a61b0df | 1021 | if (!pnode->fDisconnect) |
881a85a2 | 1022 | LogPrint("net", "socket closed\n"); |
0a61b0df | 1023 | pnode->CloseSocketDisconnect(); |
1024 | } | |
9cbae55a GA |
1025 | else if (nBytes < 0) |
1026 | { | |
1027 | // error | |
1028 | int nErr = WSAGetLastError(); | |
1029 | if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | |
1030 | { | |
1031 | if (!pnode->fDisconnect) | |
881a85a2 | 1032 | LogPrintf("socket recv error %d\n", nErr); |
9cbae55a GA |
1033 | pnode->CloseSocketDisconnect(); |
1034 | } | |
1035 | } | |
0a61b0df | 1036 | } |
1037 | } | |
1038 | } | |
1039 | ||
1040 | // | |
1041 | // Send | |
1042 | // | |
1043 | if (pnode->hSocket == INVALID_SOCKET) | |
1044 | continue; | |
1045 | if (FD_ISSET(pnode->hSocket, &fdsetSend)) | |
1046 | { | |
f8dcd5ca PW |
1047 | TRY_LOCK(pnode->cs_vSend, lockSend); |
1048 | if (lockSend) | |
bc2f5aa7 | 1049 | SocketSendData(pnode); |
0a61b0df | 1050 | } |
1051 | ||
1052 | // | |
1053 | // Inactivity checking | |
1054 | // | |
41b052ad | 1055 | if (pnode->vSendMsg.empty()) |
0a61b0df | 1056 | pnode->nLastSendEmpty = GetTime(); |
1057 | if (GetTime() - pnode->nTimeConnected > 60) | |
1058 | { | |
1059 | if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) | |
1060 | { | |
881a85a2 | 1061 | LogPrint("net", "socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0); |
0a61b0df | 1062 | pnode->fDisconnect = true; |
1063 | } | |
1064 | else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60) | |
1065 | { | |
881a85a2 | 1066 | LogPrintf("socket not sending\n"); |
0a61b0df | 1067 | pnode->fDisconnect = true; |
1068 | } | |
1069 | else if (GetTime() - pnode->nLastRecv > 90*60) | |
1070 | { | |
881a85a2 | 1071 | LogPrintf("socket inactivity timeout\n"); |
0a61b0df | 1072 | pnode->fDisconnect = true; |
1073 | } | |
1074 | } | |
1075 | } | |
0a61b0df | 1076 | { |
f8dcd5ca | 1077 | LOCK(cs_vNodes); |
223b6f1b | 1078 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 1079 | pnode->Release(); |
1080 | } | |
1081 | ||
1b43bf0d | 1082 | MilliSleep(10); |
0a61b0df | 1083 | } |
1084 | } | |
1085 | ||
1086 | ||
1087 | ||
1088 | ||
1089 | ||
1090 | ||
1091 | ||
1092 | ||
1093 | ||
8bb5edc1 | 1094 | #ifdef USE_UPNP |
21eb5ada | 1095 | void ThreadMapPort() |
8bb5edc1 | 1096 | { |
463a1cab | 1097 | std::string port = strprintf("%u", GetListenPort()); |
8bb5edc1 MC |
1098 | const char * multicastif = 0; |
1099 | const char * minissdpdpath = 0; | |
1100 | struct UPNPDev * devlist = 0; | |
1101 | char lanaddr[64]; | |
1102 | ||
94b97046 LD |
1103 | #ifndef UPNPDISCOVER_SUCCESS |
1104 | /* miniupnpc 1.5 */ | |
1105 | devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0); | |
1106 | #else | |
1107 | /* miniupnpc 1.6 */ | |
1108 | int error = 0; | |
b4ada906 | 1109 | devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); |
94b97046 | 1110 | #endif |
8bb5edc1 MC |
1111 | |
1112 | struct UPNPUrls urls; | |
1113 | struct IGDdatas data; | |
1114 | int r; | |
1115 | ||
f285d4f4 DH |
1116 | r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); |
1117 | if (r == 1) | |
8bb5edc1 | 1118 | { |
587f929c | 1119 | if (fDiscover) { |
baba6e7d MC |
1120 | char externalIPAddress[40]; |
1121 | r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); | |
1122 | if(r != UPNPCOMMAND_SUCCESS) | |
881a85a2 | 1123 | LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r); |
baba6e7d MC |
1124 | else |
1125 | { | |
1126 | if(externalIPAddress[0]) | |
1127 | { | |
881a85a2 | 1128 | LogPrintf("UPnP: ExternalIPAddress = %s\n", externalIPAddress); |
19b6958c | 1129 | AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP); |
baba6e7d MC |
1130 | } |
1131 | else | |
881a85a2 | 1132 | LogPrintf("UPnP: GetExternalIPAddress failed.\n"); |
baba6e7d MC |
1133 | } |
1134 | } | |
1135 | ||
15656981 | 1136 | string strDesc = "Bitcoin " + FormatFullVersion(); |
b4ada906 | 1137 | |
21eb5ada | 1138 | try { |
050d2e95 | 1139 | while (true) { |
177dbcaa MC |
1140 | #ifndef UPNPDISCOVER_SUCCESS |
1141 | /* miniupnpc 1.5 */ | |
1142 | r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, | |
9c809094 | 1143 | port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0); |
177dbcaa MC |
1144 | #else |
1145 | /* miniupnpc 1.6 */ | |
1146 | r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, | |
9c809094 | 1147 | port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); |
177dbcaa MC |
1148 | #endif |
1149 | ||
1150 | if(r!=UPNPCOMMAND_SUCCESS) | |
881a85a2 | 1151 | LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", |
9c809094 | 1152 | port.c_str(), port.c_str(), lanaddr, r, strupnperror(r)); |
177dbcaa | 1153 | else |
881a85a2 | 1154 | LogPrintf("UPnP Port Mapping successful.\n");; |
21eb5ada GA |
1155 | |
1156 | MilliSleep(20*60*1000); // Refresh every 20 minutes | |
177dbcaa | 1157 | } |
21eb5ada GA |
1158 | } |
1159 | catch (boost::thread_interrupted) | |
1160 | { | |
1161 | r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); | |
881a85a2 | 1162 | LogPrintf("UPNP_DeletePortMapping() returned : %d\n", r); |
21eb5ada GA |
1163 | freeUPNPDevlist(devlist); devlist = 0; |
1164 | FreeUPNPUrls(&urls); | |
1165 | throw; | |
8bb5edc1 MC |
1166 | } |
1167 | } else { | |
881a85a2 | 1168 | LogPrintf("No valid UPnP IGDs found\n"); |
8bb5edc1 | 1169 | freeUPNPDevlist(devlist); devlist = 0; |
f285d4f4 DH |
1170 | if (r != 0) |
1171 | FreeUPNPUrls(&urls); | |
8bb5edc1 MC |
1172 | } |
1173 | } | |
1174 | ||
21eb5ada | 1175 | void MapPort(bool fUseUPnP) |
8bb5edc1 | 1176 | { |
21eb5ada GA |
1177 | static boost::thread* upnp_thread = NULL; |
1178 | ||
1179 | if (fUseUPnP) | |
8bb5edc1 | 1180 | { |
21eb5ada GA |
1181 | if (upnp_thread) { |
1182 | upnp_thread->interrupt(); | |
1183 | upnp_thread->join(); | |
1184 | delete upnp_thread; | |
1185 | } | |
53e71135 | 1186 | upnp_thread = new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)); |
21eb5ada GA |
1187 | } |
1188 | else if (upnp_thread) { | |
1189 | upnp_thread->interrupt(); | |
1190 | upnp_thread->join(); | |
1191 | delete upnp_thread; | |
1192 | upnp_thread = NULL; | |
8bb5edc1 MC |
1193 | } |
1194 | } | |
21eb5ada | 1195 | |
9f0ac169 | 1196 | #else |
21eb5ada | 1197 | void MapPort(bool) |
9f0ac169 GA |
1198 | { |
1199 | // Intentionally left blank. | |
1200 | } | |
8bb5edc1 MC |
1201 | #endif |
1202 | ||
1203 | ||
1204 | ||
1205 | ||
1206 | ||
1207 | ||
21eb5ada | 1208 | void ThreadDNSAddressSeed() |
2bc6cece | 1209 | { |
0e4b3175 | 1210 | const vector<CDNSSeedData> &vSeeds = Params().DNSSeeds(); |
f684aec4 JG |
1211 | int found = 0; |
1212 | ||
881a85a2 | 1213 | LogPrintf("Loading addresses from DNS seeds (could take a while)\n"); |
af899882 | 1214 | |
0e4b3175 | 1215 | BOOST_FOREACH(const CDNSSeedData &seed, vSeeds) { |
af899882 | 1216 | if (HaveNameProxy()) { |
0e4b3175 | 1217 | AddOneShot(seed.host); |
af899882 | 1218 | } else { |
0e4b3175 | 1219 | vector<CNetAddr> vIPs; |
af899882 | 1220 | vector<CAddress> vAdd; |
0e4b3175 | 1221 | if (LookupHost(seed.host.c_str(), vIPs)) |
af899882 | 1222 | { |
0e4b3175 | 1223 | BOOST_FOREACH(CNetAddr& ip, vIPs) |
a6a5bb7c | 1224 | { |
af899882 | 1225 | int nOneDay = 24*3600; |
0e4b3175 | 1226 | CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); |
af899882 PT |
1227 | addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old |
1228 | vAdd.push_back(addr); | |
1229 | found++; | |
a6a5bb7c | 1230 | } |
f684aec4 | 1231 | } |
0e4b3175 | 1232 | addrman.Add(vAdd, CNetAddr(seed.name, true)); |
f684aec4 JG |
1233 | } |
1234 | } | |
1235 | ||
881a85a2 | 1236 | LogPrintf("%d addresses found from DNS seeds\n", found); |
f684aec4 | 1237 | } |
0a61b0df | 1238 | |
1239 | ||
1240 | ||
2bc6cece MC |
1241 | |
1242 | ||
1243 | ||
1244 | ||
1245 | ||
1246 | ||
1247 | ||
1248 | ||
1249 | ||
5fee401f PW |
1250 | void DumpAddresses() |
1251 | { | |
928d3a01 JG |
1252 | int64 nStart = GetTimeMillis(); |
1253 | ||
5fee401f | 1254 | CAddrDB adb; |
928d3a01 JG |
1255 | adb.Write(addrman); |
1256 | ||
881a85a2 | 1257 | LogPrint("net", "Flushed %d addresses to peers.dat %"PRI64d"ms\n", |
928d3a01 | 1258 | addrman.size(), GetTimeMillis() - nStart); |
5fee401f | 1259 | } |
0a61b0df | 1260 | |
478b01d9 PW |
1261 | void static ProcessOneShot() |
1262 | { | |
1263 | string strDest; | |
1264 | { | |
1265 | LOCK(cs_vOneShots); | |
1266 | if (vOneShots.empty()) | |
1267 | return; | |
1268 | strDest = vOneShots.front(); | |
1269 | vOneShots.pop_front(); | |
1270 | } | |
1271 | CAddress addr; | |
c59abe25 PW |
1272 | CSemaphoreGrant grant(*semOutbound, true); |
1273 | if (grant) { | |
1274 | if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true)) | |
1275 | AddOneShot(strDest); | |
1276 | } | |
478b01d9 PW |
1277 | } |
1278 | ||
21eb5ada | 1279 | void ThreadOpenConnections() |
0a61b0df | 1280 | { |
0a61b0df | 1281 | // Connect to specific addresses |
f161a2c2 | 1282 | if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) |
0a61b0df | 1283 | { |
bde280b9 | 1284 | for (int64 nLoop = 0;; nLoop++) |
0a61b0df | 1285 | { |
478b01d9 | 1286 | ProcessOneShot(); |
223b6f1b | 1287 | BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"]) |
0a61b0df | 1288 | { |
478b01d9 | 1289 | CAddress addr; |
c59abe25 | 1290 | OpenNetworkConnection(addr, NULL, strAddr.c_str()); |
0a61b0df | 1291 | for (int i = 0; i < 10 && i < nLoop; i++) |
1292 | { | |
1b43bf0d | 1293 | MilliSleep(500); |
0a61b0df | 1294 | } |
1295 | } | |
1b43bf0d | 1296 | MilliSleep(500); |
0a61b0df | 1297 | } |
1298 | } | |
1299 | ||
0a61b0df | 1300 | // Initiate network connections |
bde280b9 | 1301 | int64 nStart = GetTime(); |
050d2e95 | 1302 | while (true) |
0a61b0df | 1303 | { |
478b01d9 PW |
1304 | ProcessOneShot(); |
1305 | ||
1b43bf0d | 1306 | MilliSleep(500); |
cc201e01 | 1307 | |
c59abe25 | 1308 | CSemaphoreGrant grant(*semOutbound); |
21eb5ada | 1309 | boost::this_thread::interruption_point(); |
0a61b0df | 1310 | |
0e4b3175 MH |
1311 | // Add seed nodes if DNS seeds are all down (an infrastructure attack?). |
1312 | if (addrman.size() == 0 && (GetTime() - nStart > 60)) { | |
1313 | static bool done = false; | |
1314 | if (!done) { | |
881a85a2 | 1315 | LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n"); |
0e4b3175 MH |
1316 | addrman.Add(Params().FixedSeeds(), CNetAddr("127.0.0.1")); |
1317 | done = true; | |
0a61b0df | 1318 | } |
1319 | } | |
1320 | ||
0a61b0df | 1321 | // |
1322 | // Choose an address to connect to based on most recently seen | |
1323 | // | |
1324 | CAddress addrConnect; | |
0a61b0df | 1325 | |
19521acf | 1326 | // Only connect out to one peer per network group (/16 for IPv4). |
0a61b0df | 1327 | // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. |
c59abe25 | 1328 | int nOutbound = 0; |
67a42f92 | 1329 | set<vector<unsigned char> > setConnected; |
f8dcd5ca PW |
1330 | { |
1331 | LOCK(cs_vNodes); | |
c59abe25 | 1332 | BOOST_FOREACH(CNode* pnode, vNodes) { |
19521acf GM |
1333 | if (!pnode->fInbound) { |
1334 | setConnected.insert(pnode->addr.GetGroup()); | |
c59abe25 | 1335 | nOutbound++; |
19521acf | 1336 | } |
c59abe25 | 1337 | } |
f8dcd5ca | 1338 | } |
0a61b0df | 1339 | |
bde280b9 | 1340 | int64 nANow = GetAdjustedTime(); |
a4e6ae10 | 1341 | |
5fee401f | 1342 | int nTries = 0; |
050d2e95 | 1343 | while (true) |
0a61b0df | 1344 | { |
5fee401f PW |
1345 | // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections) |
1346 | CAddress addr = addrman.Select(10 + min(nOutbound,8)*10); | |
0a61b0df | 1347 | |
5fee401f | 1348 | // if we selected an invalid address, restart |
23aa78c4 | 1349 | if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) |
5fee401f | 1350 | break; |
0a61b0df | 1351 | |
f161a2c2 PW |
1352 | // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman, |
1353 | // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates | |
1354 | // already-connected network ranges, ...) before trying new addrman addresses. | |
5fee401f | 1355 | nTries++; |
f161a2c2 PW |
1356 | if (nTries > 100) |
1357 | break; | |
0a61b0df | 1358 | |
457754d2 PW |
1359 | if (IsLimited(addr)) |
1360 | continue; | |
1361 | ||
5fee401f PW |
1362 | // only consider very recently tried nodes after 30 failed attempts |
1363 | if (nANow - addr.nLastTry < 600 && nTries < 30) | |
1364 | continue; | |
1365 | ||
1366 | // do not allow non-default ports, unless after 50 invalid addresses selected already | |
0e4b3175 | 1367 | if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50) |
5fee401f PW |
1368 | continue; |
1369 | ||
1370 | addrConnect = addr; | |
1371 | break; | |
0a61b0df | 1372 | } |
1373 | ||
1374 | if (addrConnect.IsValid()) | |
c59abe25 | 1375 | OpenNetworkConnection(addrConnect, &grant); |
0a61b0df | 1376 | } |
1377 | } | |
1378 | ||
21eb5ada | 1379 | void ThreadOpenAddedConnections() |
b24e6e4d | 1380 | { |
74088e86 MC |
1381 | { |
1382 | LOCK(cs_vAddedNodes); | |
1383 | vAddedNodes = mapMultiArgs["-addnode"]; | |
1384 | } | |
b24e6e4d | 1385 | |
81bbef26 | 1386 | if (HaveNameProxy()) { |
21eb5ada | 1387 | while(true) { |
74088e86 MC |
1388 | list<string> lAddresses(0); |
1389 | { | |
1390 | LOCK(cs_vAddedNodes); | |
1391 | BOOST_FOREACH(string& strAddNode, vAddedNodes) | |
1392 | lAddresses.push_back(strAddNode); | |
1393 | } | |
1394 | BOOST_FOREACH(string& strAddNode, lAddresses) { | |
9bab521d | 1395 | CAddress addr; |
c59abe25 PW |
1396 | CSemaphoreGrant grant(*semOutbound); |
1397 | OpenNetworkConnection(addr, &grant, strAddNode.c_str()); | |
1b43bf0d | 1398 | MilliSleep(500); |
9bab521d | 1399 | } |
1b43bf0d | 1400 | MilliSleep(120000); // Retry every 2 minutes |
9bab521d | 1401 | } |
9bab521d PW |
1402 | } |
1403 | ||
f2bd6c28 | 1404 | for (unsigned int i = 0; true; i++) |
b24e6e4d | 1405 | { |
74088e86 MC |
1406 | list<string> lAddresses(0); |
1407 | { | |
1408 | LOCK(cs_vAddedNodes); | |
1409 | BOOST_FOREACH(string& strAddNode, vAddedNodes) | |
1410 | lAddresses.push_back(strAddNode); | |
1411 | } | |
1412 | ||
1413 | list<vector<CService> > lservAddressesToAdd(0); | |
1414 | BOOST_FOREACH(string& strAddNode, lAddresses) | |
b24e6e4d | 1415 | { |
74088e86 | 1416 | vector<CService> vservNode(0); |
0e4b3175 | 1417 | if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) |
f8dcd5ca | 1418 | { |
74088e86 MC |
1419 | lservAddressesToAdd.push_back(vservNode); |
1420 | { | |
1421 | LOCK(cs_setservAddNodeAddresses); | |
1422 | BOOST_FOREACH(CService& serv, vservNode) | |
1423 | setservAddNodeAddresses.insert(serv); | |
1424 | } | |
f8dcd5ca | 1425 | } |
b24e6e4d | 1426 | } |
b24e6e4d | 1427 | // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry |
9bab521d | 1428 | // (keeping in mind that addnode entries can have many IPs if fNameLookup) |
f8dcd5ca PW |
1429 | { |
1430 | LOCK(cs_vNodes); | |
b24e6e4d | 1431 | BOOST_FOREACH(CNode* pnode, vNodes) |
74088e86 | 1432 | for (list<vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) |
b24e6e4d MC |
1433 | BOOST_FOREACH(CService& addrNode, *(it)) |
1434 | if (pnode->addr == addrNode) | |
1435 | { | |
74088e86 | 1436 | it = lservAddressesToAdd.erase(it); |
b24e6e4d MC |
1437 | it--; |
1438 | break; | |
1439 | } | |
f8dcd5ca | 1440 | } |
74088e86 | 1441 | BOOST_FOREACH(vector<CService>& vserv, lservAddressesToAdd) |
b24e6e4d | 1442 | { |
c59abe25 | 1443 | CSemaphoreGrant grant(*semOutbound); |
f2bd6c28 | 1444 | OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); |
1b43bf0d | 1445 | MilliSleep(500); |
b24e6e4d | 1446 | } |
1b43bf0d | 1447 | MilliSleep(120000); // Retry every 2 minutes |
b24e6e4d MC |
1448 | } |
1449 | } | |
1450 | ||
814efd6f | 1451 | // if successful, this moves the passed grant to the constructed node |
c59abe25 | 1452 | bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot) |
0a61b0df | 1453 | { |
1454 | // | |
1455 | // Initiate outbound network connection | |
1456 | // | |
21eb5ada | 1457 | boost::this_thread::interruption_point(); |
9bab521d | 1458 | if (!strDest) |
39857190 PW |
1459 | if (IsLocal(addrConnect) || |
1460 | FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) || | |
9bab521d PW |
1461 | FindNode(addrConnect.ToStringIPPort().c_str())) |
1462 | return false; | |
1463 | if (strDest && FindNode(strDest)) | |
0a61b0df | 1464 | return false; |
1465 | ||
9bab521d | 1466 | CNode* pnode = ConnectNode(addrConnect, strDest); |
21eb5ada GA |
1467 | boost::this_thread::interruption_point(); |
1468 | ||
0a61b0df | 1469 | if (!pnode) |
1470 | return false; | |
c59abe25 PW |
1471 | if (grantOutbound) |
1472 | grantOutbound->MoveTo(pnode->grantOutbound); | |
0a61b0df | 1473 | pnode->fNetworkNode = true; |
478b01d9 PW |
1474 | if (fOneShot) |
1475 | pnode->fOneShot = true; | |
0a61b0df | 1476 | |
0a61b0df | 1477 | return true; |
1478 | } | |
1479 | ||
1480 | ||
6ed71b5e PW |
1481 | // for now, use a very simple selection metric: the node from which we received |
1482 | // most recently | |
1483 | double static NodeSyncScore(const CNode *pnode) { | |
1484 | return -pnode->nLastRecv; | |
1485 | } | |
0a61b0df | 1486 | |
6ed71b5e PW |
1487 | void static StartSync(const vector<CNode*> &vNodes) { |
1488 | CNode *pnodeNewSync = NULL; | |
1489 | double dBestScore = 0; | |
0a61b0df | 1490 | |
4c6d41b8 PW |
1491 | int nBestHeight = g_signals.GetHeight().get_value_or(0); |
1492 | ||
6ed71b5e PW |
1493 | // Iterate over all nodes |
1494 | BOOST_FOREACH(CNode* pnode, vNodes) { | |
1495 | // check preconditions for allowing a sync | |
1496 | if (!pnode->fClient && !pnode->fOneShot && | |
1497 | !pnode->fDisconnect && pnode->fSuccessfullyConnected && | |
1498 | (pnode->nStartingHeight > (nBestHeight - 144)) && | |
1499 | (pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) { | |
1500 | // if ok, compare node's score with the best so far | |
1501 | double dScore = NodeSyncScore(pnode); | |
1502 | if (pnodeNewSync == NULL || dScore > dBestScore) { | |
1503 | pnodeNewSync = pnode; | |
1504 | dBestScore = dScore; | |
1505 | } | |
1506 | } | |
1507 | } | |
1508 | // if a new sync candidate was found, start sync! | |
1509 | if (pnodeNewSync) { | |
1510 | pnodeNewSync->fStartSync = true; | |
1511 | pnodeSync = pnodeNewSync; | |
1512 | } | |
1513 | } | |
0a61b0df | 1514 | |
21eb5ada | 1515 | void ThreadMessageHandler() |
0a61b0df | 1516 | { |
0a61b0df | 1517 | SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); |
21eb5ada | 1518 | while (true) |
0a61b0df | 1519 | { |
6ed71b5e PW |
1520 | bool fHaveSyncNode = false; |
1521 | ||
0a61b0df | 1522 | vector<CNode*> vNodesCopy; |
0a61b0df | 1523 | { |
f8dcd5ca | 1524 | LOCK(cs_vNodes); |
0a61b0df | 1525 | vNodesCopy = vNodes; |
6ed71b5e | 1526 | BOOST_FOREACH(CNode* pnode, vNodesCopy) { |
0a61b0df | 1527 | pnode->AddRef(); |
6ed71b5e PW |
1528 | if (pnode == pnodeSync) |
1529 | fHaveSyncNode = true; | |
1530 | } | |
0a61b0df | 1531 | } |
1532 | ||
6ed71b5e PW |
1533 | if (!fHaveSyncNode) |
1534 | StartSync(vNodesCopy); | |
1535 | ||
0a61b0df | 1536 | // Poll the connected nodes for messages |
1537 | CNode* pnodeTrickle = NULL; | |
1538 | if (!vNodesCopy.empty()) | |
1539 | pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())]; | |
223b6f1b | 1540 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 1541 | { |
967f2459 PW |
1542 | if (pnode->fDisconnect) |
1543 | continue; | |
1544 | ||
0a61b0df | 1545 | // Receive messages |
f8dcd5ca | 1546 | { |
607dbfde | 1547 | TRY_LOCK(pnode->cs_vRecvMsg, lockRecv); |
f8dcd5ca | 1548 | if (lockRecv) |
501da250 | 1549 | if (!g_signals.ProcessMessages(pnode)) |
607dbfde | 1550 | pnode->CloseSocketDisconnect(); |
f8dcd5ca | 1551 | } |
21eb5ada | 1552 | boost::this_thread::interruption_point(); |
0a61b0df | 1553 | |
1554 | // Send messages | |
f8dcd5ca PW |
1555 | { |
1556 | TRY_LOCK(pnode->cs_vSend, lockSend); | |
501da250 EL |
1557 | if (lockSend) |
1558 | g_signals.SendMessages(pnode, pnode == pnodeTrickle); | |
f8dcd5ca | 1559 | } |
21eb5ada | 1560 | boost::this_thread::interruption_point(); |
0a61b0df | 1561 | } |
1562 | ||
0a61b0df | 1563 | { |
f8dcd5ca | 1564 | LOCK(cs_vNodes); |
223b6f1b | 1565 | BOOST_FOREACH(CNode* pnode, vNodesCopy) |
0a61b0df | 1566 | pnode->Release(); |
1567 | } | |
1568 | ||
1b43bf0d | 1569 | MilliSleep(100); |
0a61b0df | 1570 | } |
1571 | } | |
1572 | ||
1573 | ||
1574 | ||
1575 | ||
1576 | ||
1577 | ||
8f10a288 | 1578 | bool BindListenPort(const CService &addrBind, string& strError) |
0a61b0df | 1579 | { |
1580 | strError = ""; | |
1581 | int nOne = 1; | |
1582 | ||
0a61b0df | 1583 | // Create socket for listening for incoming connections |
23aa78c4 | 1584 | #ifdef USE_IPV6 |
8f10a288 | 1585 | struct sockaddr_storage sockaddr; |
23aa78c4 | 1586 | #else |
8f10a288 | 1587 | struct sockaddr sockaddr; |
23aa78c4 | 1588 | #endif |
8f10a288 PW |
1589 | socklen_t len = sizeof(sockaddr); |
1590 | if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len)) | |
1591 | { | |
1592 | strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str()); | |
881a85a2 | 1593 | LogPrintf("%s\n", strError.c_str()); |
8f10a288 PW |
1594 | return false; |
1595 | } | |
1596 | ||
1597 | SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP); | |
0a61b0df | 1598 | if (hListenSocket == INVALID_SOCKET) |
1599 | { | |
1600 | strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); | |
881a85a2 | 1601 | LogPrintf("%s\n", strError.c_str()); |
0a61b0df | 1602 | return false; |
1603 | } | |
1604 | ||
ec93a0e2 | 1605 | #ifdef SO_NOSIGPIPE |
0a61b0df | 1606 | // Different way of disabling SIGPIPE on BSD |
1607 | setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)); | |
1608 | #endif | |
1609 | ||
6853e627 | 1610 | #ifndef WIN32 |
0a61b0df | 1611 | // Allow binding if the port is still in TIME_WAIT state after |
1612 | // the program was closed and restarted. Not an issue on windows. | |
1613 | setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); | |
1614 | #endif | |
1615 | ||
8f10a288 | 1616 | |
6853e627 | 1617 | #ifdef WIN32 |
814efd6f | 1618 | // Set to non-blocking, incoming connections will also inherit this |
0a61b0df | 1619 | if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) |
1620 | #else | |
1621 | if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) | |
1622 | #endif | |
1623 | { | |
1624 | strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError()); | |
881a85a2 | 1625 | LogPrintf("%s\n", strError.c_str()); |
0a61b0df | 1626 | return false; |
1627 | } | |
1628 | ||
23aa78c4 | 1629 | #ifdef USE_IPV6 |
8f10a288 PW |
1630 | // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option |
1631 | // and enable it by default or not. Try to enable it, if possible. | |
1632 | if (addrBind.IsIPv6()) { | |
1633 | #ifdef IPV6_V6ONLY | |
b3e0aaf3 PK |
1634 | #ifdef WIN32 |
1635 | setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int)); | |
1636 | #else | |
8f10a288 | 1637 | setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)); |
23aa78c4 | 1638 | #endif |
b3e0aaf3 | 1639 | #endif |
8f10a288 PW |
1640 | #ifdef WIN32 |
1641 | int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */; | |
1642 | int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */; | |
1643 | // this call is allowed to fail | |
1644 | setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int)); | |
1645 | #endif | |
1646 | } | |
1647 | #endif | |
1648 | ||
1649 | if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) | |
0a61b0df | 1650 | { |
1651 | int nErr = WSAGetLastError(); | |
1652 | if (nErr == WSAEADDRINUSE) | |
8b4d6536 | 1653 | strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin is probably already running."), addrBind.ToString().c_str()); |
0a61b0df | 1654 | else |
8f10a288 | 1655 | strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr)); |
881a85a2 | 1656 | LogPrintf("%s\n", strError.c_str()); |
0a61b0df | 1657 | return false; |
1658 | } | |
881a85a2 | 1659 | LogPrintf("Bound to %s\n", addrBind.ToString().c_str()); |
0a61b0df | 1660 | |
1661 | // Listen for incoming connections | |
1662 | if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) | |
1663 | { | |
1664 | strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError()); | |
881a85a2 | 1665 | LogPrintf("%s\n", strError.c_str()); |
0a61b0df | 1666 | return false; |
1667 | } | |
1668 | ||
8f10a288 PW |
1669 | vhListenSocket.push_back(hListenSocket); |
1670 | ||
587f929c | 1671 | if (addrBind.IsRoutable() && fDiscover) |
8f10a288 PW |
1672 | AddLocal(addrBind, LOCAL_BIND); |
1673 | ||
0a61b0df | 1674 | return true; |
1675 | } | |
1676 | ||
19b6958c | 1677 | void static Discover() |
0a61b0df | 1678 | { |
587f929c | 1679 | if (!fDiscover) |
19b6958c | 1680 | return; |
0a61b0df | 1681 | |
6853e627 | 1682 | #ifdef WIN32 |
814efd6f | 1683 | // Get local host IP |
0a61b0df | 1684 | char pszHostName[1000] = ""; |
1685 | if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) | |
1686 | { | |
67a42f92 PW |
1687 | vector<CNetAddr> vaddr; |
1688 | if (LookupHost(pszHostName, vaddr)) | |
f8e4d43b | 1689 | { |
67a42f92 | 1690 | BOOST_FOREACH (const CNetAddr &addr, vaddr) |
f8e4d43b | 1691 | { |
39857190 | 1692 | AddLocal(addr, LOCAL_IF); |
f8e4d43b PK |
1693 | } |
1694 | } | |
0a61b0df | 1695 | } |
1696 | #else | |
1697 | // Get local host ip | |
1698 | struct ifaddrs* myaddrs; | |
1699 | if (getifaddrs(&myaddrs) == 0) | |
1700 | { | |
1701 | for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) | |
1702 | { | |
1703 | if (ifa->ifa_addr == NULL) continue; | |
1704 | if ((ifa->ifa_flags & IFF_UP) == 0) continue; | |
1705 | if (strcmp(ifa->ifa_name, "lo") == 0) continue; | |
1706 | if (strcmp(ifa->ifa_name, "lo0") == 0) continue; | |
0a61b0df | 1707 | if (ifa->ifa_addr->sa_family == AF_INET) |
1708 | { | |
1709 | struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr); | |
39857190 | 1710 | CNetAddr addr(s4->sin_addr); |
23aa78c4 | 1711 | if (AddLocal(addr, LOCAL_IF)) |
881a85a2 | 1712 | LogPrintf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); |
0a61b0df | 1713 | } |
23aa78c4 | 1714 | #ifdef USE_IPV6 |
0a61b0df | 1715 | else if (ifa->ifa_addr->sa_family == AF_INET6) |
1716 | { | |
1717 | struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr); | |
39857190 | 1718 | CNetAddr addr(s6->sin6_addr); |
23aa78c4 | 1719 | if (AddLocal(addr, LOCAL_IF)) |
881a85a2 | 1720 | LogPrintf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); |
0a61b0df | 1721 | } |
23aa78c4 | 1722 | #endif |
0a61b0df | 1723 | } |
1724 | freeifaddrs(myaddrs); | |
1725 | } | |
1726 | #endif | |
0a61b0df | 1727 | |
a76552ce PK |
1728 | // Don't use external IPv4 discovery, when -onlynet="IPv6" |
1729 | if (!IsLimited(NET_IPV4)) | |
53e71135 | 1730 | boost::thread(boost::bind(&TraceThread<void (*)()>, "ext-ip", &ThreadGetMyExternalIP)); |
19b6958c PW |
1731 | } |
1732 | ||
b31499ec | 1733 | void StartNode(boost::thread_group& threadGroup) |
19b6958c | 1734 | { |
c59abe25 PW |
1735 | if (semOutbound == NULL) { |
1736 | // initialize semaphore | |
ba29a559 | 1737 | int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); |
c59abe25 PW |
1738 | semOutbound = new CSemaphore(nMaxOutbound); |
1739 | } | |
1740 | ||
19b6958c PW |
1741 | if (pnodeLocalHost == NULL) |
1742 | pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); | |
1743 | ||
1744 | Discover(); | |
0a61b0df | 1745 | |
1746 | // | |
1747 | // Start threads | |
1748 | // | |
1749 | ||
9d952d17 | 1750 | if (!GetBoolArg("-dnsseed", true)) |
881a85a2 | 1751 | LogPrintf("DNS seeding disabled\n"); |
2bc6cece | 1752 | else |
53e71135 | 1753 | threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "dnsseed", &ThreadDNSAddressSeed)); |
2bc6cece | 1754 | |
b31499ec | 1755 | #ifdef USE_UPNP |
8bb5edc1 | 1756 | // Map ports with UPnP |
21eb5ada | 1757 | MapPort(GetBoolArg("-upnp", USE_UPNP)); |
b31499ec | 1758 | #endif |
8bb5edc1 | 1759 | |
0a61b0df | 1760 | // Send and receive from sockets, accept connections |
b31499ec | 1761 | threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "net", &ThreadSocketHandler)); |
0a61b0df | 1762 | |
b24e6e4d | 1763 | // Initiate outbound connections from -addnode |
b31499ec | 1764 | threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "addcon", &ThreadOpenAddedConnections)); |
b24e6e4d | 1765 | |
0a61b0df | 1766 | // Initiate outbound connections |
b31499ec | 1767 | threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "opencon", &ThreadOpenConnections)); |
0a61b0df | 1768 | |
1769 | // Process messages | |
b31499ec | 1770 | threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler)); |
0a61b0df | 1771 | |
5fee401f | 1772 | // Dump network addresses |
c43da3f1 | 1773 | threadGroup.create_thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, DUMP_ADDRESSES_INTERVAL * 1000)); |
0a61b0df | 1774 | } |
1775 | ||
1776 | bool StopNode() | |
1777 | { | |
881a85a2 | 1778 | LogPrintf("StopNode()\n"); |
21eb5ada | 1779 | MapPort(false); |
89b5616d PW |
1780 | if (semOutbound) |
1781 | for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++) | |
1782 | semOutbound->post(); | |
1b43bf0d | 1783 | MilliSleep(50); |
5fee401f | 1784 | DumpAddresses(); |
3427517d | 1785 | |
0a61b0df | 1786 | return true; |
1787 | } | |
1788 | ||
1789 | class CNetCleanup | |
1790 | { | |
1791 | public: | |
1792 | CNetCleanup() | |
1793 | { | |
1794 | } | |
1795 | ~CNetCleanup() | |
1796 | { | |
1797 | // Close sockets | |
223b6f1b | 1798 | BOOST_FOREACH(CNode* pnode, vNodes) |
0a61b0df | 1799 | if (pnode->hSocket != INVALID_SOCKET) |
1800 | closesocket(pnode->hSocket); | |
8f10a288 PW |
1801 | BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) |
1802 | if (hListenSocket != INVALID_SOCKET) | |
1803 | if (closesocket(hListenSocket) == SOCKET_ERROR) | |
881a85a2 | 1804 | LogPrintf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); |
0a61b0df | 1805 | |
3427517d PW |
1806 | // clean up some globals (to help leak detection) |
1807 | BOOST_FOREACH(CNode *pnode, vNodes) | |
1808 | delete pnode; | |
1809 | BOOST_FOREACH(CNode *pnode, vNodesDisconnected) | |
1810 | delete pnode; | |
1811 | vNodes.clear(); | |
1812 | vNodesDisconnected.clear(); | |
1813 | delete semOutbound; | |
1814 | semOutbound = NULL; | |
1815 | delete pnodeLocalHost; | |
1816 | pnodeLocalHost = NULL; | |
1817 | ||
6853e627 | 1818 | #ifdef WIN32 |
0a61b0df | 1819 | // Shutdown Windows Sockets |
1820 | WSACleanup(); | |
1821 | #endif | |
1822 | } | |
1823 | } | |
1824 | instance_of_cnetcleanup; | |
269d9c64 MC |
1825 | |
1826 | ||
1827 | ||
1828 | ||
1829 | ||
1830 | ||
1831 | ||
1832 | void RelayTransaction(const CTransaction& tx, const uint256& hash) | |
1833 | { | |
1834 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
1835 | ss.reserve(10000); | |
1836 | ss << tx; | |
1837 | RelayTransaction(tx, hash, ss); | |
1838 | } | |
1839 | ||
1840 | void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss) | |
1841 | { | |
1842 | CInv inv(MSG_TX, hash); | |
1843 | { | |
1844 | LOCK(cs_mapRelay); | |
1845 | // Expire old relay messages | |
1846 | while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) | |
1847 | { | |
1848 | mapRelay.erase(vRelayExpiration.front().second); | |
1849 | vRelayExpiration.pop_front(); | |
1850 | } | |
1851 | ||
1852 | // Save original serialized message so newer versions are preserved | |
1853 | mapRelay.insert(std::make_pair(inv, ss)); | |
1854 | vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); | |
1855 | } | |
1856 | LOCK(cs_vNodes); | |
1857 | BOOST_FOREACH(CNode* pnode, vNodes) | |
1858 | { | |
4c8fc1a5 MC |
1859 | if(!pnode->fRelayTxes) |
1860 | continue; | |
269d9c64 MC |
1861 | LOCK(pnode->cs_filter); |
1862 | if (pnode->pfilter) | |
1863 | { | |
d3b26f70 | 1864 | if (pnode->pfilter->IsRelevantAndUpdate(tx, hash)) |
269d9c64 MC |
1865 | pnode->PushInventory(inv); |
1866 | } else | |
1867 | pnode->PushInventory(inv); | |
1868 | } | |
1869 | } | |
ce14345a SE |
1870 | |
1871 | void CNode::RecordBytesRecv(uint64 bytes) | |
1872 | { | |
1873 | LOCK(cs_totalBytesRecv); | |
1874 | nTotalBytesRecv += bytes; | |
1875 | } | |
1876 | ||
1877 | void CNode::RecordBytesSent(uint64 bytes) | |
1878 | { | |
1879 | LOCK(cs_totalBytesSent); | |
1880 | nTotalBytesSent += bytes; | |
1881 | } | |
1882 | ||
1883 | uint64 CNode::GetTotalBytesRecv() | |
1884 | { | |
1885 | LOCK(cs_totalBytesRecv); | |
1886 | return nTotalBytesRecv; | |
1887 | } | |
1888 | ||
1889 | uint64 CNode::GetTotalBytesSent() | |
1890 | { | |
1891 | LOCK(cs_totalBytesSent); | |
1892 | return nTotalBytesSent; | |
1893 | } |