Document assumptions that are being made to avoid NULL pointer dereferences
[bitcoinplatinum.git] / src / netbase.cpp
blob05f9f6961c45d884ac8469ec9e013aff91ab7bd4
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #ifdef HAVE_CONFIG_H
7 #include "config/bitcoin-config.h"
8 #endif
10 #include "netbase.h"
12 #include "hash.h"
13 #include "sync.h"
14 #include "uint256.h"
15 #include "random.h"
16 #include "util.h"
17 #include "utilstrencodings.h"
19 #include <atomic>
21 #ifndef WIN32
22 #include <fcntl.h>
23 #endif
25 #include <boost/algorithm/string/case_conv.hpp> // for to_lower()
26 #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
28 #if !defined(HAVE_MSG_NOSIGNAL)
29 #define MSG_NOSIGNAL 0
30 #endif
32 // Settings
33 static proxyType proxyInfo[NET_MAX];
34 static proxyType nameProxy;
35 static CCriticalSection cs_proxyInfos;
36 int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
37 bool fNameLookup = DEFAULT_NAME_LOOKUP;
39 // Need ample time for negotiation for very slow proxies such as Tor (milliseconds)
40 static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
41 static std::atomic<bool> interruptSocks5Recv(false);
43 enum Network ParseNetwork(std::string net) {
44 boost::to_lower(net);
45 if (net == "ipv4") return NET_IPV4;
46 if (net == "ipv6") return NET_IPV6;
47 if (net == "tor" || net == "onion") return NET_TOR;
48 return NET_UNROUTABLE;
51 std::string GetNetworkName(enum Network net) {
52 switch(net)
54 case NET_IPV4: return "ipv4";
55 case NET_IPV6: return "ipv6";
56 case NET_TOR: return "onion";
57 default: return "";
61 bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
63 vIP.clear();
66 CNetAddr addr;
67 if (addr.SetSpecial(std::string(pszName))) {
68 vIP.push_back(addr);
69 return true;
73 struct addrinfo aiHint;
74 memset(&aiHint, 0, sizeof(struct addrinfo));
76 aiHint.ai_socktype = SOCK_STREAM;
77 aiHint.ai_protocol = IPPROTO_TCP;
78 aiHint.ai_family = AF_UNSPEC;
79 #ifdef WIN32
80 aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
81 #else
82 aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
83 #endif
84 struct addrinfo *aiRes = nullptr;
85 int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes);
86 if (nErr)
87 return false;
89 struct addrinfo *aiTrav = aiRes;
90 while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
92 CNetAddr resolved;
93 if (aiTrav->ai_family == AF_INET)
95 assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
96 resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
99 if (aiTrav->ai_family == AF_INET6)
101 assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
102 struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
103 resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
105 /* Never allow resolving to an internal address. Consider any such result invalid */
106 if (!resolved.IsInternal()) {
107 vIP.push_back(resolved);
110 aiTrav = aiTrav->ai_next;
113 freeaddrinfo(aiRes);
115 return (vIP.size() > 0);
118 bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
120 std::string strHost(pszName);
121 if (strHost.empty())
122 return false;
123 if (boost::algorithm::starts_with(strHost, "[") && boost::algorithm::ends_with(strHost, "]"))
125 strHost = strHost.substr(1, strHost.size() - 2);
128 return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup);
131 bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup)
133 std::vector<CNetAddr> vIP;
134 LookupHost(pszName, vIP, 1, fAllowLookup);
135 if(vIP.empty())
136 return false;
137 addr = vIP.front();
138 return true;
141 bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
143 if (pszName[0] == 0)
144 return false;
145 int port = portDefault;
146 std::string hostname = "";
147 SplitHostPort(std::string(pszName), port, hostname);
149 std::vector<CNetAddr> vIP;
150 bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup);
151 if (!fRet)
152 return false;
153 vAddr.resize(vIP.size());
154 for (unsigned int i = 0; i < vIP.size(); i++)
155 vAddr[i] = CService(vIP[i], port);
156 return true;
159 bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup)
161 std::vector<CService> vService;
162 bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1);
163 if (!fRet)
164 return false;
165 addr = vService[0];
166 return true;
169 CService LookupNumeric(const char *pszName, int portDefault)
171 CService addr;
172 // "1.2:345" will fail to resolve the ip, but will still set the port.
173 // If the ip fails to resolve, re-init the result.
174 if(!Lookup(pszName, addr, portDefault, false))
175 addr = CService();
176 return addr;
179 struct timeval MillisToTimeval(int64_t nTimeout)
181 struct timeval timeout;
182 timeout.tv_sec = nTimeout / 1000;
183 timeout.tv_usec = (nTimeout % 1000) * 1000;
184 return timeout;
187 enum class IntrRecvError {
189 Timeout,
190 Disconnected,
191 NetworkError,
192 Interrupted
196 * Read bytes from socket. This will either read the full number of bytes requested
197 * or return False on error or timeout.
198 * This function can be interrupted by calling InterruptSocks5()
200 * @param data Buffer to receive into
201 * @param len Length of data to receive
202 * @param timeout Timeout in milliseconds for receive operation
204 * @note This function requires that hSocket is in non-blocking mode.
206 static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, const SOCKET& hSocket)
208 int64_t curTime = GetTimeMillis();
209 int64_t endTime = curTime + timeout;
210 // Maximum time to wait in one select call. It will take up until this time (in millis)
211 // to break off in case of an interruption.
212 const int64_t maxWait = 1000;
213 while (len > 0 && curTime < endTime) {
214 ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first
215 if (ret > 0) {
216 len -= ret;
217 data += ret;
218 } else if (ret == 0) { // Unexpected disconnection
219 return IntrRecvError::Disconnected;
220 } else { // Other error or blocking
221 int nErr = WSAGetLastError();
222 if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
223 if (!IsSelectableSocket(hSocket)) {
224 return IntrRecvError::NetworkError;
226 struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
227 fd_set fdset;
228 FD_ZERO(&fdset);
229 FD_SET(hSocket, &fdset);
230 int nRet = select(hSocket + 1, &fdset, nullptr, nullptr, &tval);
231 if (nRet == SOCKET_ERROR) {
232 return IntrRecvError::NetworkError;
234 } else {
235 return IntrRecvError::NetworkError;
238 if (interruptSocks5Recv)
239 return IntrRecvError::Interrupted;
240 curTime = GetTimeMillis();
242 return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
245 struct ProxyCredentials
247 std::string username;
248 std::string password;
251 std::string Socks5ErrorString(int err)
253 switch(err) {
254 case 0x01: return "general failure";
255 case 0x02: return "connection not allowed";
256 case 0x03: return "network unreachable";
257 case 0x04: return "host unreachable";
258 case 0x05: return "connection refused";
259 case 0x06: return "TTL expired";
260 case 0x07: return "protocol error";
261 case 0x08: return "address type not supported";
262 default: return "unknown";
266 /** Connect using SOCKS5 (as described in RFC1928) */
267 static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
269 IntrRecvError recvr;
270 LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
271 if (strDest.size() > 255) {
272 CloseSocket(hSocket);
273 return error("Hostname too long");
275 // Accepted authentication methods
276 std::vector<uint8_t> vSocks5Init;
277 vSocks5Init.push_back(0x05);
278 if (auth) {
279 vSocks5Init.push_back(0x02); // # METHODS
280 vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
281 vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929)
282 } else {
283 vSocks5Init.push_back(0x01); // # METHODS
284 vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
286 ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
287 if (ret != (ssize_t)vSocks5Init.size()) {
288 CloseSocket(hSocket);
289 return error("Error sending to proxy");
291 char pchRet1[2];
292 if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
293 CloseSocket(hSocket);
294 LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
295 return false;
297 if (pchRet1[0] != 0x05) {
298 CloseSocket(hSocket);
299 return error("Proxy failed to initialize");
301 if (pchRet1[1] == 0x02 && auth) {
302 // Perform username/password authentication (as described in RFC1929)
303 std::vector<uint8_t> vAuth;
304 vAuth.push_back(0x01);
305 if (auth->username.size() > 255 || auth->password.size() > 255)
306 return error("Proxy username or password too long");
307 vAuth.push_back(auth->username.size());
308 vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
309 vAuth.push_back(auth->password.size());
310 vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
311 ret = send(hSocket, (const char*)vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
312 if (ret != (ssize_t)vAuth.size()) {
313 CloseSocket(hSocket);
314 return error("Error sending authentication to proxy");
316 LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
317 char pchRetA[2];
318 if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
319 CloseSocket(hSocket);
320 return error("Error reading proxy authentication response");
322 if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
323 CloseSocket(hSocket);
324 return error("Proxy authentication unsuccessful");
326 } else if (pchRet1[1] == 0x00) {
327 // Perform no authentication
328 } else {
329 CloseSocket(hSocket);
330 return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
332 std::vector<uint8_t> vSocks5;
333 vSocks5.push_back(0x05); // VER protocol version
334 vSocks5.push_back(0x01); // CMD CONNECT
335 vSocks5.push_back(0x00); // RSV Reserved
336 vSocks5.push_back(0x03); // ATYP DOMAINNAME
337 vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
338 vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
339 vSocks5.push_back((port >> 8) & 0xFF);
340 vSocks5.push_back((port >> 0) & 0xFF);
341 ret = send(hSocket, (const char*)vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
342 if (ret != (ssize_t)vSocks5.size()) {
343 CloseSocket(hSocket);
344 return error("Error sending to proxy");
346 char pchRet2[4];
347 if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
348 CloseSocket(hSocket);
349 if (recvr == IntrRecvError::Timeout) {
350 /* If a timeout happens here, this effectively means we timed out while connecting
351 * to the remote node. This is very common for Tor, so do not print an
352 * error message. */
353 return false;
354 } else {
355 return error("Error while reading proxy response");
358 if (pchRet2[0] != 0x05) {
359 CloseSocket(hSocket);
360 return error("Proxy failed to accept request");
362 if (pchRet2[1] != 0x00) {
363 // Failures to connect to a peer that are not proxy errors
364 CloseSocket(hSocket);
365 LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
366 return false;
368 if (pchRet2[2] != 0x00) {
369 CloseSocket(hSocket);
370 return error("Error: malformed proxy response");
372 char pchRet3[256];
373 switch (pchRet2[3])
375 case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
376 case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
377 case 0x03:
379 recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
380 if (recvr != IntrRecvError::OK) {
381 CloseSocket(hSocket);
382 return error("Error reading from proxy");
384 int nRecv = pchRet3[0];
385 recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
386 break;
388 default: CloseSocket(hSocket); return error("Error: malformed proxy response");
390 if (recvr != IntrRecvError::OK) {
391 CloseSocket(hSocket);
392 return error("Error reading from proxy");
394 if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
395 CloseSocket(hSocket);
396 return error("Error reading from proxy");
398 LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
399 return true;
402 bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
404 hSocketRet = INVALID_SOCKET;
406 struct sockaddr_storage sockaddr;
407 socklen_t len = sizeof(sockaddr);
408 if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
409 LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
410 return false;
413 SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
414 if (hSocket == INVALID_SOCKET)
415 return false;
417 #ifdef SO_NOSIGPIPE
418 int set = 1;
419 // Different way of disabling SIGPIPE on BSD
420 setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
421 #endif
423 //Disable Nagle's algorithm
424 SetSocketNoDelay(hSocket);
426 // Set to non-blocking
427 if (!SetSocketNonBlocking(hSocket, true)) {
428 CloseSocket(hSocket);
429 return error("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
432 if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
434 int nErr = WSAGetLastError();
435 // WSAEINVAL is here because some legacy version of winsock uses it
436 if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
438 struct timeval timeout = MillisToTimeval(nTimeout);
439 fd_set fdset;
440 FD_ZERO(&fdset);
441 FD_SET(hSocket, &fdset);
442 int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
443 if (nRet == 0)
445 LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
446 CloseSocket(hSocket);
447 return false;
449 if (nRet == SOCKET_ERROR)
451 LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
452 CloseSocket(hSocket);
453 return false;
455 socklen_t nRetSize = sizeof(nRet);
456 #ifdef WIN32
457 if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
458 #else
459 if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
460 #endif
462 LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
463 CloseSocket(hSocket);
464 return false;
466 if (nRet != 0)
468 LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet));
469 CloseSocket(hSocket);
470 return false;
473 #ifdef WIN32
474 else if (WSAGetLastError() != WSAEISCONN)
475 #else
476 else
477 #endif
479 LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
480 CloseSocket(hSocket);
481 return false;
485 hSocketRet = hSocket;
486 return true;
489 bool SetProxy(enum Network net, const proxyType &addrProxy) {
490 assert(net >= 0 && net < NET_MAX);
491 if (!addrProxy.IsValid())
492 return false;
493 LOCK(cs_proxyInfos);
494 proxyInfo[net] = addrProxy;
495 return true;
498 bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
499 assert(net >= 0 && net < NET_MAX);
500 LOCK(cs_proxyInfos);
501 if (!proxyInfo[net].IsValid())
502 return false;
503 proxyInfoOut = proxyInfo[net];
504 return true;
507 bool SetNameProxy(const proxyType &addrProxy) {
508 if (!addrProxy.IsValid())
509 return false;
510 LOCK(cs_proxyInfos);
511 nameProxy = addrProxy;
512 return true;
515 bool GetNameProxy(proxyType &nameProxyOut) {
516 LOCK(cs_proxyInfos);
517 if(!nameProxy.IsValid())
518 return false;
519 nameProxyOut = nameProxy;
520 return true;
523 bool HaveNameProxy() {
524 LOCK(cs_proxyInfos);
525 return nameProxy.IsValid();
528 bool IsProxy(const CNetAddr &addr) {
529 LOCK(cs_proxyInfos);
530 for (int i = 0; i < NET_MAX; i++) {
531 if (addr == (CNetAddr)proxyInfo[i].proxy)
532 return true;
534 return false;
537 static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
539 SOCKET hSocket = INVALID_SOCKET;
540 // first connect to proxy server
541 if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) {
542 if (outProxyConnectionFailed)
543 *outProxyConnectionFailed = true;
544 return false;
546 // do socks negotiation
547 if (proxy.randomize_credentials) {
548 ProxyCredentials random_auth;
549 static std::atomic_int counter(0);
550 random_auth.username = random_auth.password = strprintf("%i", counter++);
551 if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
552 return false;
553 } else {
554 if (!Socks5(strDest, (unsigned short)port, 0, hSocket))
555 return false;
558 hSocketRet = hSocket;
559 return true;
562 bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
564 proxyType proxy;
565 if (outProxyConnectionFailed)
566 *outProxyConnectionFailed = false;
568 if (GetProxy(addrDest.GetNetwork(), proxy))
569 return ConnectThroughProxy(proxy, addrDest.ToStringIP(), addrDest.GetPort(), hSocketRet, nTimeout, outProxyConnectionFailed);
570 else // no proxy needed (none set for target network)
571 return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
574 bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)
576 std::string strDest;
577 int port = portDefault;
579 if (outProxyConnectionFailed)
580 *outProxyConnectionFailed = false;
582 SplitHostPort(std::string(pszDest), port, strDest);
584 proxyType proxy;
585 GetNameProxy(proxy);
587 std::vector<CService> addrResolved;
588 if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) {
589 if (addrResolved.size() > 0) {
590 addr = addrResolved[GetRand(addrResolved.size())];
591 return ConnectSocket(addr, hSocketRet, nTimeout);
595 addr = CService();
597 if (!HaveNameProxy())
598 return false;
599 return ConnectThroughProxy(proxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
602 bool LookupSubNet(const char* pszName, CSubNet& ret)
604 std::string strSubnet(pszName);
605 size_t slash = strSubnet.find_last_of('/');
606 std::vector<CNetAddr> vIP;
608 std::string strAddress = strSubnet.substr(0, slash);
609 if (LookupHost(strAddress.c_str(), vIP, 1, false))
611 CNetAddr network = vIP[0];
612 if (slash != strSubnet.npos)
614 std::string strNetmask = strSubnet.substr(slash + 1);
615 int32_t n;
616 // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
617 if (ParseInt32(strNetmask, &n)) { // If valid number, assume /24 syntax
618 ret = CSubNet(network, n);
619 return ret.IsValid();
621 else // If not a valid number, try full netmask syntax
623 // Never allow lookup for netmask
624 if (LookupHost(strNetmask.c_str(), vIP, 1, false)) {
625 ret = CSubNet(network, vIP[0]);
626 return ret.IsValid();
630 else
632 ret = CSubNet(network);
633 return ret.IsValid();
636 return false;
639 #ifdef WIN32
640 std::string NetworkErrorString(int err)
642 char buf[256];
643 buf[0] = 0;
644 if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
645 nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
646 buf, sizeof(buf), nullptr))
648 return strprintf("%s (%d)", buf, err);
650 else
652 return strprintf("Unknown error (%d)", err);
655 #else
656 std::string NetworkErrorString(int err)
658 char buf[256];
659 buf[0] = 0;
660 /* Too bad there are two incompatible implementations of the
661 * thread-safe strerror. */
662 const char *s;
663 #ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
664 s = strerror_r(err, buf, sizeof(buf));
665 #else /* POSIX variant always returns message in buffer */
666 s = buf;
667 if (strerror_r(err, buf, sizeof(buf)))
668 buf[0] = 0;
669 #endif
670 return strprintf("%s (%d)", s, err);
672 #endif
674 bool CloseSocket(SOCKET& hSocket)
676 if (hSocket == INVALID_SOCKET)
677 return false;
678 #ifdef WIN32
679 int ret = closesocket(hSocket);
680 #else
681 int ret = close(hSocket);
682 #endif
683 hSocket = INVALID_SOCKET;
684 return ret != SOCKET_ERROR;
687 bool SetSocketNonBlocking(const SOCKET& hSocket, bool fNonBlocking)
689 if (fNonBlocking) {
690 #ifdef WIN32
691 u_long nOne = 1;
692 if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
693 #else
694 int fFlags = fcntl(hSocket, F_GETFL, 0);
695 if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
696 #endif
697 return false;
699 } else {
700 #ifdef WIN32
701 u_long nZero = 0;
702 if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {
703 #else
704 int fFlags = fcntl(hSocket, F_GETFL, 0);
705 if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
706 #endif
707 return false;
711 return true;
714 bool SetSocketNoDelay(const SOCKET& hSocket)
716 int set = 1;
717 int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(int));
718 return rc == 0;
721 void InterruptSocks5(bool interrupt)
723 interruptSocks5Recv = interrupt;