From e0036e9f0e0240541bf5a4ebcd8087be99739e71 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 8 May 2014 14:15:19 +0200 Subject: [PATCH] Replace non-threadsafe strerror Log the name of the error as well as the error code if a network problem happens. This makes network troubleshooting more convenient. Use thread-safe strerror_r and the WIN32 equivalent FormatMessage. Conflicts: src/netbase.cpp Rebased-By: Wladimir van der Laan Rebased-From: a60838d --- configure.ac | 2 ++ src/net.cpp | 24 ++++++++++++------------ src/netbase.cpp | 42 ++++++++++++++++++++++++++++++++++++++---- src/netbase.h | 2 ++ 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index eb45fdbfe1..e18f965eb6 100644 --- a/configure.ac +++ b/configure.ac @@ -303,6 +303,8 @@ INCLUDES="$INCLUDES $PTHREAD_CFLAGS" # they also need to be passed down to any subprojects. Pull the results out of # the cache and add them to CPPFLAGS. AC_SYS_LARGEFILE +# detect POSIX or GNU variant of strerror_r +AC_FUNC_STRERROR_R if test x$ac_cv_sys_file_offset_bits != x && test x$ac_cv_sys_file_offset_bits != xno && diff --git a/src/net.cpp b/src/net.cpp index 6bde1e7999..4cbd26a563 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -178,7 +178,7 @@ bool RecvLine(SOCKET hSocket, string& strLine) { // socket error int nErr = WSAGetLastError(); - LogPrint("net", "recv failed: %d\n", nErr); + LogPrint("net", "recv failed: %s\n", NetworkErrorString(nErr)); return false; } } @@ -489,10 +489,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) #ifdef WIN32 u_long nOne = 1; if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) - LogPrintf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError()); + LogPrintf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %s\n", NetworkErrorString(WSAGetLastError())); #else if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) - LogPrintf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno); + LogPrintf("ConnectSocket() : fcntl non-blocking setting failed, error %s\n", NetworkErrorString(errno)); #endif // Add node @@ -736,7 +736,7 @@ void SocketSendData(CNode *pnode) int nErr = WSAGetLastError(); if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) { - LogPrintf("socket send error %d\n", nErr); + LogPrintf("socket send error %s\n", NetworkErrorString(nErr)); pnode->CloseSocketDisconnect(); } } @@ -896,7 +896,7 @@ void ThreadSocketHandler() if (have_fds) { int nErr = WSAGetLastError(); - LogPrintf("socket select error %d\n", nErr); + LogPrintf("socket select error %s\n", NetworkErrorString(nErr)); for (unsigned int i = 0; i <= hSocketMax; i++) FD_SET(i, &fdsetRecv); } @@ -933,7 +933,7 @@ void ThreadSocketHandler() { int nErr = WSAGetLastError(); if (nErr != WSAEWOULDBLOCK) - LogPrintf("socket error accept failed: %d\n", nErr); + LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); } else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) { @@ -1007,7 +1007,7 @@ void ThreadSocketHandler() if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) { if (!pnode->fDisconnect) - LogPrintf("socket recv error %d\n", nErr); + LogPrintf("socket recv error %s\n", NetworkErrorString(nErr)); pnode->CloseSocketDisconnect(); } } @@ -1585,7 +1585,7 @@ bool BindListenPort(const CService &addrBind, string& strError) SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP); if (hListenSocket == INVALID_SOCKET) { - strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); + strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError())); LogPrintf("%s\n", strError); return false; } @@ -1609,7 +1609,7 @@ bool BindListenPort(const CService &addrBind, string& strError) if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) #endif { - strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError()); + strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %s)", NetworkErrorString(WSAGetLastError())); LogPrintf("%s\n", strError); return false; } @@ -1638,7 +1638,7 @@ bool BindListenPort(const CService &addrBind, string& strError) if (nErr == WSAEADDRINUSE) strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString()); else - strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString(), nErr, strerror(nErr)); + strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr)); LogPrintf("%s\n", strError); return false; } @@ -1647,7 +1647,7 @@ bool BindListenPort(const CService &addrBind, string& strError) // Listen for incoming connections if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) { - strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %d)"), WSAGetLastError()); + strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError())); LogPrintf("%s\n", strError); return false; } @@ -1785,7 +1785,7 @@ public: BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) if (hListenSocket != INVALID_SOCKET) if (closesocket(hListenSocket) == SOCKET_ERROR) - LogPrintf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); + LogPrintf("closesocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); // clean up some globals (to help leak detection) BOOST_FOREACH(CNode *pnode, vNodes) diff --git a/src/netbase.cpp b/src/netbase.cpp index ec275f738c..eb6859e28c 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -363,7 +363,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe } if (nRet == SOCKET_ERROR) { - LogPrintf("select() for %s failed: %i\n", addrConnect.ToString(), WSAGetLastError()); + LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); closesocket(hSocket); return false; } @@ -374,13 +374,13 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) #endif { - LogPrintf("getsockopt() for %s failed: %i\n", addrConnect.ToString(), WSAGetLastError()); + LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); closesocket(hSocket); return false; } if (nRet != 0) { - LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), strerror(nRet)); + LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet)); closesocket(hSocket); return false; } @@ -391,7 +391,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe else #endif { - LogPrintf("connect() to %s failed: %i\n", addrConnect.ToString(), WSAGetLastError()); + LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); closesocket(hSocket); return false; } @@ -1122,3 +1122,37 @@ void CService::SetPort(unsigned short portIn) { port = portIn; } + +#ifdef WIN32 +std::string NetworkErrorString(int err) +{ + char buf[256]; + buf[0] = 0; + if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buf, sizeof(buf), NULL)) + { + return strprintf("%s (%d)", buf, err); + } + else + { + return strprintf("Unknown error (%d)", err); + } +} +#else +std::string NetworkErrorString(int err) +{ + char buf[256]; + const char *s = buf; + buf[0] = 0; + /* Too bad there are two incompatible implementations of the + * thread-safe strerror. */ +#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */ + s = strerror_r(err, buf, sizeof(buf)); +#else /* POSIX variant always returns message in buffer */ + (void) strerror_r(err, buf, sizeof(buf)); +#endif + return strprintf("%s (%d)", s, err); +} +#endif + diff --git a/src/netbase.h b/src/netbase.h index 95b1795767..b3358dcf01 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -149,5 +149,7 @@ bool Lookup(const char *pszName, std::vector& vAddr, int portDefault = bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); +/** Return readable error string for a network error code */ +std::string NetworkErrorString(int err); #endif