Skip to content

Commit a60838d

Browse files
committed
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.
1 parent 8cd9007 commit a60838d

File tree

4 files changed

+53
-16
lines changed

4 files changed

+53
-16
lines changed

configure.ac

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ INCLUDES="$INCLUDES $PTHREAD_CFLAGS"
303303
# they also need to be passed down to any subprojects. Pull the results out of
304304
# the cache and add them to CPPFLAGS.
305305
AC_SYS_LARGEFILE
306+
# detect POSIX or GNU variant of strerror_r
307+
AC_FUNC_STRERROR_R
306308

307309
if test x$ac_cv_sys_file_offset_bits != x &&
308310
test x$ac_cv_sys_file_offset_bits != xno &&

src/net.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ bool RecvLine(SOCKET hSocket, string& strLine)
178178
{
179179
// socket error
180180
int nErr = WSAGetLastError();
181-
LogPrint("net", "recv failed: %d\n", nErr);
181+
LogPrint("net", "recv failed: %s\n", NetworkErrorString(nErr));
182182
return false;
183183
}
184184
}
@@ -489,10 +489,10 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
489489
#ifdef WIN32
490490
u_long nOne = 1;
491491
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
492-
LogPrintf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError());
492+
LogPrintf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %s\n", NetworkErrorString(WSAGetLastError()));
493493
#else
494494
if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
495-
LogPrintf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno);
495+
LogPrintf("ConnectSocket() : fcntl non-blocking setting failed, error %s\n", NetworkErrorString(errno));
496496
#endif
497497

498498
// Add node
@@ -736,7 +736,7 @@ void SocketSendData(CNode *pnode)
736736
int nErr = WSAGetLastError();
737737
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
738738
{
739-
LogPrintf("socket send error %d\n", nErr);
739+
LogPrintf("socket send error %s\n", NetworkErrorString(nErr));
740740
pnode->CloseSocketDisconnect();
741741
}
742742
}
@@ -896,7 +896,7 @@ void ThreadSocketHandler()
896896
if (have_fds)
897897
{
898898
int nErr = WSAGetLastError();
899-
LogPrintf("socket select error %d\n", nErr);
899+
LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
900900
for (unsigned int i = 0; i <= hSocketMax; i++)
901901
FD_SET(i, &fdsetRecv);
902902
}
@@ -933,7 +933,7 @@ void ThreadSocketHandler()
933933
{
934934
int nErr = WSAGetLastError();
935935
if (nErr != WSAEWOULDBLOCK)
936-
LogPrintf("socket error accept failed: %d\n", nErr);
936+
LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
937937
}
938938
else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
939939
{
@@ -1007,7 +1007,7 @@ void ThreadSocketHandler()
10071007
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
10081008
{
10091009
if (!pnode->fDisconnect)
1010-
LogPrintf("socket recv error %d\n", nErr);
1010+
LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
10111011
pnode->CloseSocketDisconnect();
10121012
}
10131013
}
@@ -1585,7 +1585,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
15851585
SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
15861586
if (hListenSocket == INVALID_SOCKET)
15871587
{
1588-
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
1588+
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %s)", NetworkErrorString(WSAGetLastError()));
15891589
LogPrintf("%s\n", strError);
15901590
return false;
15911591
}
@@ -1609,7 +1609,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
16091609
if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
16101610
#endif
16111611
{
1612-
strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
1612+
strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %s)", NetworkErrorString(WSAGetLastError()));
16131613
LogPrintf("%s\n", strError);
16141614
return false;
16151615
}
@@ -1638,7 +1638,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
16381638
if (nErr == WSAEADDRINUSE)
16391639
strError = strprintf(_("Unable to bind to %s on this computer. Bitcoin Core is probably already running."), addrBind.ToString());
16401640
else
1641-
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString(), nErr, strerror(nErr));
1641+
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
16421642
LogPrintf("%s\n", strError);
16431643
return false;
16441644
}
@@ -1647,7 +1647,7 @@ bool BindListenPort(const CService &addrBind, string& strError)
16471647
// Listen for incoming connections
16481648
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
16491649
{
1650-
strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %d)"), WSAGetLastError());
1650+
strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError()));
16511651
LogPrintf("%s\n", strError);
16521652
return false;
16531653
}
@@ -1785,7 +1785,7 @@ class CNetCleanup
17851785
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
17861786
if (hListenSocket != INVALID_SOCKET)
17871787
if (closesocket(hListenSocket) == SOCKET_ERROR)
1788-
LogPrintf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
1788+
LogPrintf("closesocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
17891789

17901790
// clean up some globals (to help leak detection)
17911791
BOOST_FOREACH(CNode *pnode, vNodes)

src/netbase.cpp

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
361361
}
362362
if (nRet == SOCKET_ERROR)
363363
{
364-
LogPrintf("select() for %s failed: %i\n", addrConnect.ToString(), WSAGetLastError());
364+
LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
365365
closesocket(hSocket);
366366
return false;
367367
}
@@ -372,13 +372,13 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
372372
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
373373
#endif
374374
{
375-
LogPrintf("getsockopt() for %s failed: %i\n", addrConnect.ToString(), WSAGetLastError());
375+
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
376376
closesocket(hSocket);
377377
return false;
378378
}
379379
if (nRet != 0)
380380
{
381-
LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), strerror(nRet));
381+
LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet));
382382
closesocket(hSocket);
383383
return false;
384384
}
@@ -389,7 +389,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
389389
else
390390
#endif
391391
{
392-
LogPrintf("connect() to %s failed: %i\n", addrConnect.ToString(), WSAGetLastError());
392+
LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
393393
closesocket(hSocket);
394394
return false;
395395
}
@@ -1237,3 +1237,36 @@ bool operator!=(const CSubNet& a, const CSubNet& b)
12371237
{
12381238
return !(a==b);
12391239
}
1240+
1241+
#ifdef WIN32
1242+
std::string NetworkErrorString(int err)
1243+
{
1244+
char buf[256];
1245+
buf[0] = 0;
1246+
if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
1247+
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1248+
buf, sizeof(buf), NULL))
1249+
{
1250+
return strprintf("%s (%d)", buf, err);
1251+
}
1252+
else
1253+
{
1254+
return strprintf("Unknown error (%d)", err);
1255+
}
1256+
}
1257+
#else
1258+
std::string NetworkErrorString(int err)
1259+
{
1260+
char buf[256];
1261+
const char *s = buf;
1262+
buf[0] = 0;
1263+
/* Too bad there are two incompatible implementations of the
1264+
* thread-safe strerror. */
1265+
#ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
1266+
s = strerror_r(err, buf, sizeof(buf));
1267+
#else /* POSIX variant always returns message in buffer */
1268+
(void) strerror_r(err, buf, sizeof(buf));
1269+
#endif
1270+
return strprintf("%s (%d)", s, err);
1271+
}
1272+
#endif

src/netbase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,5 +179,7 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault =
179179
bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
180180
bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout);
181181
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout);
182+
/** Return readable error string for a network error code */
183+
std::string NetworkErrorString(int err);
182184

183185
#endif

0 commit comments

Comments
 (0)