diff -uNr a/bitcoin/manifest b/bitcoin/manifest --- a/bitcoin/manifest c6493a2ebcfebf531a9ef2340355d5f6638b5436a77991c54a07c1ea80fac7c1c71a4525e07af9f36346c9f0a850a35be2389650a6172fb04d6b90d76eeb919c +++ b/bitcoin/manifest b6c64c0d831b862f4f9cc6bceb8634071dacfa3922bdbf33e61c5b76a94b0168e42ba181ce1de085a094be85f099f0d4d6cf6284722dd2a9be83fe657a6da5b1 @@ -48,3 +48,4 @@ 735324 bitcoin_pushmessage_cleanup_1 jfw Tame the PushMessage template explosion by pushing CDataStream serialization out to callers. Permanently disable undocumented -allowreceivebyip and otherwise dead code turned up when auditing PushMessage callers, namely generic network request tracking and publish/subscribe infrastructure. Simplify initialization of vSend/vRecv fields: type (since SER_NETWORK is the default) and version (since the indicated flag day is long past; it wasn't quite clear to remove the field altogether). Add unit test for assumption noted in one of the PushMessage calls. 735336 bitcoin_pushmessage_cleanup_2 jfw With PushMessage deduplicated, we can integrate BeginMessage, AbortMessage and EndMessage for major simplification. While we're here, fix those infernal torn send/receive debug messages with their redundant timestamps and no clue as to sender or recipient. 735393 bitcoin_enforce_buffer_limits jfw Finally we can move send and receive flood control logic to where the buffers get filled, so that the rest of the code can count on their not exceeding the size limits. Passing the error upstack is needed in the sending case to stop whatever was generating the output. While we're here, fix an erroneous fcntl flag bit inversion and kill a 64k stack buffer. +735393 bitcoin_posix_error_handling jfw Convert all error codes to readable strings in log and console output. Don't log numeric fork/setsid result in the error case as it's always -1 and only errno is interesting. Translate socket error handling from WinSock to better fit unix-like systems: in particular, EAGAIN may be distinct from EWOULDBLOCK; EWOULDBLOCK and EINVAL don't apply to connect; EINPROGRESS doesn't apply to send/recv; EMSGSIZE doesn't seem to apply to TCP and it's unclear that it could be handled if it did; and errno needs to be saved when there may be intervening libc calls (nAcceptErr). diff -uNr a/bitcoin/src/init.cpp b/bitcoin/src/init.cpp --- a/bitcoin/src/init.cpp 65d10b2fb7d554c0833d97931fde3429dad8a61d1c8e5a9c3d590d67340c43356a35a3ebcce1f4a96eee9e13b1b359a2173814cc97bccdfe6fd6a7d94ea0f74a +++ b/bitcoin/src/init.cpp 830f8ff84148b7cefa7b846e9e4fba03f60a1a68dc7066f1bb00b56dc4c4899056364dfd016869489d3567dfc6b2cc043e7581fb17b514dfd3ee08e10bb80db4 @@ -272,20 +272,21 @@ { // Daemonize pid_t pid = fork(); - if (pid < 0) + if (pid == -1) { - fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno); + fprintf(stderr, "Error: fork(): %s\n", StringError(errno).c_str()); return false; } - if (pid > 0) + if (pid) { + // parent CreatePidFile(GetPidFile(), pid); return true; } + // child - pid_t sid = setsid(); - if (sid < 0) - fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno); + if (setsid() == -1) + fprintf(stderr, "Error: setsid(): %s\n", StringError(errno).c_str()); } if (!fDebug && !pszSetDataDir[0]) diff -uNr a/bitcoin/src/net.cpp b/bitcoin/src/net.cpp --- a/bitcoin/src/net.cpp 73d3ab5906c00b2e7fc030b8664404d91ddea987ca9899dc30abda12e9e9e17966ad1abfbf5587753053231f8125e75a38f5f8d9d68c023dc92110ebfb1cd398 +++ b/bitcoin/src/net.cpp 15bb33eac15ff9e8d26a6a02ac68936bf748be6edd6f55a860edf8dc2b470ac9bc5e3cccd076164e82b6c9c282956820b2b3466b6c77dc77651d835e07732853 @@ -92,8 +92,7 @@ if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) { - // WSAEINVAL is here because some legacy version of winsock uses it - if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL) + if (errno == EINPROGRESS) { struct timeval timeout; timeout.tv_sec = nTimeout / 1000; @@ -111,27 +110,27 @@ } if (nRet == SOCKET_ERROR) { - printf("select() for connection failed: %i\n",WSAGetLastError()); + printf("select() for connection failed: %s\n", StringError(errno).c_str()); closesocket(hSocket); return false; } socklen_t nRetSize = sizeof(nRet); if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) { - printf("getsockopt() for connection failed: %i\n",WSAGetLastError()); + printf("getsockopt() for connection failed: %s\n", StringError(errno).c_str()); closesocket(hSocket); return false; } if (nRet != 0) { - printf("connect() failed after select(): %s\n",strerror(nRet)); + printf("connect() failed after select(): %s\n", StringError(nRet).c_str()); closesocket(hSocket); return false; } } else { - printf("connect() failed: %i\n",WSAGetLastError()); + printf("connect() failed: %s\n", StringError(errno).c_str()); closesocket(hSocket); return false; } @@ -375,7 +374,7 @@ // Set to nonblocking if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) - printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno); + printf("ConnectSocket() : fcntl nonblocking setting failed: %s\n", StringError(errno).c_str()); // Add node CNode* pnode = new CNode(hSocket, addrConnect, false); @@ -583,10 +582,9 @@ return; if (nSelect == SOCKET_ERROR) { - int nErr = WSAGetLastError(); if (hSocketMax > -1) { - printf("socket select error %d\n", nErr); + printf("socket select error: %s\n", StringError(errno).c_str()); for (int i = 0; i <= hSocketMax; i++) FD_SET(i, &fdsetRecv); } @@ -604,6 +602,7 @@ struct sockaddr_in sockaddr; socklen_t len = sizeof(sockaddr); SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); + int nAcceptErr = errno; CAddress addr; int nInbound = 0; @@ -617,8 +616,8 @@ if (hSocket == INVALID_SOCKET) { - if (WSAGetLastError() != WSAEWOULDBLOCK) - printf("socket error accept failed: %d\n", WSAGetLastError()); + if (nAcceptErr != EWOULDBLOCK && nAcceptErr != EAGAIN) + printf("socket error accept failed: %s\n", StringError(nAcceptErr).c_str()); } else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS) { @@ -696,11 +695,10 @@ else if (nBytes < 0) { // error - int nErr = WSAGetLastError(); - if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) { if (!pnode->fDisconnect) - printf("socket recv error %d\n", nErr); + printf("socket recv error: %s\n", StringError(errno).c_str()); pnode->CloseSocketDisconnect(); } } @@ -729,10 +727,9 @@ else if (nBytes < 0) { // error - int nErr = WSAGetLastError(); - if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) { - printf("socket send error %d\n", nErr); + printf("socket send error: %s\n", StringError(errno).c_str()); pnode->CloseSocketDisconnect(); } } @@ -1073,7 +1070,7 @@ hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (hListenSocket == INVALID_SOCKET) { - strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); + strError = string("Error: Couldn't open socket for incoming connections: ") + StringError(errno); printf("%s\n", strError.c_str()); return false; } @@ -1089,7 +1086,7 @@ if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) { - strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError()); + strError = string("Error: Couldn't set properties on socket for incoming connections: ") + StringError(errno); printf("%s\n", strError.c_str()); return false; } @@ -1103,11 +1100,7 @@ sockaddr.sin_port = htons(GetListenPort()); if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) { - int nErr = WSAGetLastError(); - if (nErr == WSAEADDRINUSE) - strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), ntohs(sockaddr.sin_port)); - else - strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr); + strError = strprintf("Error: Unable to bind to port %d on this computer: ", ntohs(sockaddr.sin_port)) + StringError(errno); printf("%s\n", strError.c_str()); return false; } @@ -1116,7 +1109,7 @@ // Listen for incoming connections if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) { - strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError()); + strError = string("Error: Listening for incoming connections failed: ") + StringError(errno); printf("%s\n", strError.c_str()); return false; } @@ -1241,7 +1234,7 @@ closesocket(pnode->hSocket); if (hListenSocket != INVALID_SOCKET) if (closesocket(hListenSocket) == SOCKET_ERROR) - printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); + printf("closesocket(hListenSocket) failed: %s\n", StringError(errno).c_str()); } } diff -uNr a/bitcoin/src/util.cpp b/bitcoin/src/util.cpp --- a/bitcoin/src/util.cpp d0d39dab1148e544ba93766ae80efcf004b715a0af89db3e98f0ea14b842c683f4f1bc6df6182347b36482aacc52c120d7e4beaf6128df44cbbfa4d9b583959d +++ b/bitcoin/src/util.cpp 15b46344c80e58143a11b215de7c883167142ff65136bb90df78ccdb01ca3a2a1fb1ebc61f78fea88c17c504b209f87eba7b42b2ae8d3a67652bfd133a97a850 @@ -907,6 +907,18 @@ return ss.str(); } +std::string StringError(int nErr) +{ + { + static CCriticalSection cs_strerror; + SCOPED_LOCK(cs_strerror); + // Locking makes this thread-safe, but not fully reentrant (async signal safe). strerror_r is a pain due to a POSIX vs GNU conflict. + char *s = strerror(nErr); + if (s) + return std::string(s); + } + return strprintf("Unknown error %d", nErr); +} #ifdef DEBUG_LOCKORDER diff -uNr a/bitcoin/src/util.h b/bitcoin/src/util.h --- a/bitcoin/src/util.h 25e0005b1ac501d4058966ec78823ff48427dc8dcb39f6414cba439782da31c5de505bf931ea41fee35bd3327caf0a90af74bb4a5a83617ab0d93caea61c5357 +++ b/bitcoin/src/util.h bab7740fd689486507200267b17cb0db5e4e082ccdbd6057915f723b778a8880443af98cd610e1d0094d944e6634c31431cb701ed87e16cb694938c7bd4f5020 @@ -65,18 +65,9 @@ return u.ptr; } -#define WSAGetLastError() errno -#define WSAEINVAL EINVAL -#define WSAEALREADY EALREADY -#define WSAEWOULDBLOCK EWOULDBLOCK -#define WSAEMSGSIZE EMSGSIZE -#define WSAEINTR EINTR -#define WSAEINPROGRESS EINPROGRESS -#define WSAEADDRINUSE EADDRINUSE -#define WSAENOTSOCK EBADF -#define INVALID_SOCKET (SOCKET)(~0) +#define INVALID_SOCKET -1 #define SOCKET_ERROR -1 -typedef u_int SOCKET; +typedef int SOCKET; #define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) #define strlwr(psz) to_lower(psz) #define _strlwr(psz) to_lower(psz) @@ -90,15 +81,12 @@ } -inline int myclosesocket(SOCKET& hSocket) +inline int closesocket(SOCKET& hSocket) { - if (hSocket == INVALID_SOCKET) - return WSAENOTSOCK; int ret = close(hSocket); hSocket = INVALID_SOCKET; return ret; } -#define closesocket(s) myclosesocket(s) inline const char* _(const char* psz) { return psz; @@ -167,6 +155,7 @@ void AddTimeData(unsigned int ip, int64 nTime); std::string FormatFullVersion(); std::string FormatSubVersion(const std::string& name, int nClientVersion); +std::string StringError(int nErr);