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.
This commit is contained in:
Wladimir J. van der Laan 2014-05-08 14:15:19 +02:00
parent 8cd900711c
commit a60838d09a
4 changed files with 53 additions and 16 deletions

View File

@ -303,6 +303,8 @@ INCLUDES="$INCLUDES $PTHREAD_CFLAGS"
# they also need to be passed down to any subprojects. Pull the results out of # they also need to be passed down to any subprojects. Pull the results out of
# the cache and add them to CPPFLAGS. # the cache and add them to CPPFLAGS.
AC_SYS_LARGEFILE 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 && if test x$ac_cv_sys_file_offset_bits != x &&
test x$ac_cv_sys_file_offset_bits != xno && test x$ac_cv_sys_file_offset_bits != xno &&

View File

@ -178,7 +178,7 @@ bool RecvLine(SOCKET hSocket, string& strLine)
{ {
// socket error // socket error
int nErr = WSAGetLastError(); int nErr = WSAGetLastError();
LogPrint("net", "recv failed: %d\n", nErr); LogPrint("net", "recv failed: %s\n", NetworkErrorString(nErr));
return false; return false;
} }
} }
@ -489,10 +489,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
#ifdef WIN32 #ifdef WIN32
u_long nOne = 1; u_long nOne = 1;
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) 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 #else
if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) 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 #endif
// Add node // Add node
@ -736,7 +736,7 @@ void SocketSendData(CNode *pnode)
int nErr = WSAGetLastError(); int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) 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(); pnode->CloseSocketDisconnect();
} }
} }
@ -896,7 +896,7 @@ void ThreadSocketHandler()
if (have_fds) if (have_fds)
{ {
int nErr = WSAGetLastError(); 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++) for (unsigned int i = 0; i <= hSocketMax; i++)
FD_SET(i, &fdsetRecv); FD_SET(i, &fdsetRecv);
} }
@ -933,7 +933,7 @@ void ThreadSocketHandler()
{ {
int nErr = WSAGetLastError(); int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK) 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) else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
{ {
@ -1007,7 +1007,7 @@ void ThreadSocketHandler()
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{ {
if (!pnode->fDisconnect) if (!pnode->fDisconnect)
LogPrintf("socket recv error %d\n", nErr); LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
pnode->CloseSocketDisconnect(); 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); SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hListenSocket == INVALID_SOCKET) 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); LogPrintf("%s\n", strError);
return false; return false;
} }
@ -1609,7 +1609,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
#endif #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); LogPrintf("%s\n", strError);
return false; return false;
} }
@ -1638,7 +1638,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
if (nErr == WSAEADDRINUSE) if (nErr == WSAEADDRINUSE)
strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString()); strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString());
else 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); LogPrintf("%s\n", strError);
return false; return false;
} }
@ -1647,7 +1647,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
// Listen for incoming connections // Listen for incoming connections
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) 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); LogPrintf("%s\n", strError);
return false; return false;
} }
@ -1785,7 +1785,7 @@ public:
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
if (hListenSocket != INVALID_SOCKET) if (hListenSocket != INVALID_SOCKET)
if (closesocket(hListenSocket) == SOCKET_ERROR) 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) // clean up some globals (to help leak detection)
BOOST_FOREACH(CNode *pnode, vNodes) BOOST_FOREACH(CNode *pnode, vNodes)

View File

@ -361,7 +361,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
} }
if (nRet == SOCKET_ERROR) 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); closesocket(hSocket);
return false; return false;
} }
@ -372,13 +372,13 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
#endif #endif
{ {
LogPrintf("getsockopt() for %s failed: %i\n", addrConnect.ToString(), WSAGetLastError()); LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
closesocket(hSocket); closesocket(hSocket);
return false; return false;
} }
if (nRet != 0) 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); closesocket(hSocket);
return false; return false;
} }
@ -389,7 +389,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
else else
#endif #endif
{ {
LogPrintf("connect() to %s failed: %i\n", addrConnect.ToString(), WSAGetLastError()); LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
closesocket(hSocket); closesocket(hSocket);
return false; return false;
} }
@ -1237,3 +1237,36 @@ bool operator!=(const CSubNet& a, const CSubNet& b)
{ {
return !(a==b); return !(a==b);
} }
#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

View File

@ -179,5 +179,7 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault =
bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); 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); 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 #endif