From 0da49d8b95a989a9211f734f5e9e4f053a6b7c6b Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Sat, 8 Aug 2020 23:27:23 +0000
Subject: [PATCH] socket_strerror() is now thread-safe.

---
 src/sbbs3/js_global.c |  3 ++-
 src/sbbs3/services.c  | 31 +++++++++++++++++--------------
 src/xpdev/ini_file.c  |  7 ++++---
 src/xpdev/multisock.c |  3 ++-
 src/xpdev/sockwrap.c  | 22 ++++++++++++----------
 src/xpdev/sockwrap.h  |  8 ++------
 6 files changed, 39 insertions(+), 35 deletions(-)

diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c
index 3eebd0585c..9cfe201114 100644
--- a/src/sbbs3/js_global.c
+++ b/src/sbbs3/js_global.c
@@ -75,6 +75,7 @@ BOOL DLLCALL js_argc(JSContext *cx, uintN argc, uintN min)
 static JSBool js_system_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
 	jsval idval;
+	char		err[128];
     jsint       tiny;
 	JSString*	js_str;
 
@@ -86,7 +87,7 @@ static JSBool js_system_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 			*vp=DOUBLE_TO_JSVAL(ERROR_VALUE);
 			break;
 		case GLOB_PROP_SOCKET_ERRNO_STR:
-			if((js_str=JS_NewStringCopyZ(cx, socket_strerror(socket_errno)))==NULL)
+			if((js_str=JS_NewStringCopyZ(cx, socket_strerror(socket_errno, err, sizeof(err))))==NULL)
 				return(JS_FALSE);
 	        *vp = STRING_TO_JSVAL(js_str);
 			break;
diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c
index 99b28f6c5f..64f676f0cc 100644
--- a/src/sbbs3/services.c
+++ b/src/sbbs3/services.c
@@ -254,6 +254,7 @@ static SOCKET open_socket(int family, int type, service_t* serv)
 
 static int close_socket(SOCKET sock)
 {
+	char	err[128];
 	int		result;
 
 	if(sock==INVALID_SOCKET)
@@ -264,7 +265,7 @@ static int close_socket(SOCKET sock)
 	if(startup!=NULL && startup->socket_open!=NULL) 
 		startup->socket_open(startup->cbdata,FALSE);
 	if(result!=0)
-		lprintf(LOG_WARNING,"%04d !ERROR %d (%s) closing socket",sock, ERROR_VALUE, socket_strerror(socket_errno));
+		lprintf(LOG_WARNING,"%04d !ERROR %d (%s) closing socket",sock, ERROR_VALUE, socket_strerror(socket_errno, err, sizeof(err)));
 
 	return(result);
 }
@@ -1649,8 +1650,9 @@ static void cleanup(int code)
 
 #ifdef _WINSOCKAPI_	
 	if(WSAInitialized) {
+		char err[128];
 		if(WSACleanup()!=0) 
-			lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d (%s)",ERROR_VALUE, socket_strerror(socket_errno));
+			lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d (%s)",ERROR_VALUE, socket_strerror(socket_errno, err, sizeof(err)));
 		WSAInitialized = FALSE;
 	}
 #endif
@@ -1689,7 +1691,8 @@ const char* DLLCALL services_ver(void)
 void service_udp_sock_cb(SOCKET sock, void *cbdata)
 {
 	service_t	*serv = (service_t *)cbdata;
-	int				optval;
+	int			optval;
+	char		err[128];
 
 	open_socket_cb(sock, cbdata);
 
@@ -1697,14 +1700,14 @@ void service_udp_sock_cb(SOCKET sock, void *cbdata)
 	optval=TRUE;
 	if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval,sizeof(optval))!=0) {
 		lprintf(LOG_ERR,"%04d !ERROR %d (%s) setting %s socket option"
-			,sock, ERROR_VALUE, socket_strerror(socket_errno), serv->protocol);
+			,sock, ERROR_VALUE, socket_strerror(socket_errno, err, sizeof(err)), serv->protocol);
 		close_socket(sock);
 		return;
 	}
    #ifdef BSD
 	if(setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&optval,sizeof(optval))!=0) {
 		lprintf(LOG_ERR,"%04d !ERROR %d (%s) setting %s socket option"
-			,sock, ERROR_VALUE, socket_strerror(socket_errno), serv->protocol);
+			,sock, ERROR_VALUE, socket_strerror(socket_errno, err, sizeof(err)), serv->protocol);
 		close_socket(sock);
 		return;
 	}
@@ -2006,7 +2009,7 @@ void DLLCALL services_thread(void* arg)
 				else if(ERROR_VALUE == ENOTSOCK)
             		lprintf(LOG_NOTICE,"0000 Services sockets closed");
 				else
-					lprintf(LOG_WARNING,"0000 !ERROR %d (%s) selecting sockets",ERROR_VALUE, socket_strerror(socket_errno));
+					lprintf(LOG_WARNING,"0000 !ERROR %d (%s) selecting sockets",ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)));
 				continue;
 			}
 
@@ -2038,7 +2041,7 @@ void DLLCALL services_thread(void* arg)
 						if(udp_len<1) {
 							FREE_AND_NULL(udp_buf);
 							lprintf(LOG_WARNING,"%04d %s !ERROR %d (%s) recvfrom failed"
-								,service[i].set->socks[j].sock, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno));
+								,service[i].set->socks[j].sock, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)));
 							continue;
 						}
 
@@ -2046,7 +2049,7 @@ void DLLCALL services_thread(void* arg)
 							==INVALID_SOCKET) {
 							FREE_AND_NULL(udp_buf);
 							lprintf(LOG_ERR,"%04d %s !ERROR %d (%s) opening socket"
-								,service[i].set->socks[j].sock, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno));
+								,service[i].set->socks[j].sock, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)));
 							continue;
 						}
 
@@ -2059,7 +2062,7 @@ void DLLCALL services_thread(void* arg)
 							,(char*)&optval,sizeof(optval))!=0) {
 							FREE_AND_NULL(udp_buf);
 							lprintf(LOG_ERR,"%04d %s !ERROR %d (%s) setting socket option"
-								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno));
+								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)));
 							close_socket(client_socket);
 							continue;
 						}
@@ -2068,7 +2071,7 @@ void DLLCALL services_thread(void* arg)
 							,(char*)&optval,sizeof(optval))!=0) {
 							FREE_AND_NULL(udp_buf);
 							lprintf(LOG_ERR,"%04d %s !ERROR %d (%s) setting socket option"
-								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno));
+								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)));
 							close_socket(client_socket);
 							continue;
 						}
@@ -2081,14 +2084,14 @@ void DLLCALL services_thread(void* arg)
 							/* Failed to re-bind to same port number, use user port */
 							lprintf(LOG_NOTICE,"%04d %s ERROR %d (%s) re-binding socket to port %u failed, "
 								"using user port"
-								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno), service[i].port);
+								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)), service[i].port);
 							inet_setaddrport(&addr, 0);
 							result=bind(client_socket, (struct sockaddr *) &addr, addr_len);
 						}
 						if(result!=0) {
 							FREE_AND_NULL(udp_buf);
 							lprintf(LOG_ERR,"%04d %s !ERROR %d (%s) re-binding socket to port %u"
-								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno), service[i].port);
+								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)), service[i].port);
 							close_socket(client_socket);
 							continue;
 						}
@@ -2098,7 +2101,7 @@ void DLLCALL services_thread(void* arg)
 							,(struct sockaddr *)&client_addr, client_addr_len)!=0) {
 							FREE_AND_NULL(udp_buf);
 							lprintf(LOG_ERR,"%04d %s !ERROR %d (%s) connect failed"
-								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno));
+								,client_socket, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)));
 							close_socket(client_socket);
 							continue;
 						}
@@ -2112,7 +2115,7 @@ void DLLCALL services_thread(void* arg)
 									,service[i].set->socks[j].sock, service[i].protocol);
 							else
 								lprintf(LOG_WARNING,"%04d %s !ERROR %d (%s) accepting connection" 
-									,service[i].set->socks[j].sock, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno));
+									,service[i].set->socks[j].sock, service[i].protocol, ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error)));
 	#ifdef _WIN32
 							if(WSAGetLastError()==WSAENOBUFS)	/* recycle (re-init WinSock) on this error */
 								break;
diff --git a/src/xpdev/ini_file.c b/src/xpdev/ini_file.c
index 6aefefa3bc..827a3c55a8 100644
--- a/src/xpdev/ini_file.c
+++ b/src/xpdev/ini_file.c
@@ -1518,6 +1518,7 @@ int iniGetSocketOptions(str_list_t list, const char* section, SOCKET sock
 	int			i;
 	int			result;
 	char*		name;
+	char		err[128];
 	BYTE*		vp;
 	socklen_t	len;
 	int			option;
@@ -1532,13 +1533,13 @@ int iniGetSocketOptions(str_list_t list, const char* section, SOCKET sock
 
 	len=sizeof(type);
 	if((result=getsockopt(sock, SOL_SOCKET, SO_TYPE, (char*)&type, &len)) != 0) {
-		safe_snprintf(error,errlen,"%d (%s) getting socket type", ERROR_VALUE, socket_strerror(socket_errno));
+		safe_snprintf(error,errlen,"%d (%s) getting socket type", ERROR_VALUE, socket_strerror(socket_errno,err,sizeof(err)));
 		return(result);
 	}
 #ifdef IPPROTO_IPV6
 	len=sizeof(addr);
 	if((result=getsockname(sock, &addr.addr, &len)) != 0) {
-		safe_snprintf(error,errlen,"%d (%s) getting socket name", ERROR_VALUE, socket_strerror(socket_errno));
+		safe_snprintf(error,errlen,"%d (%s) getting socket name", ERROR_VALUE, socket_strerror(socket_errno,err,sizeof(err)));
 		return(result);
 	}
 #endif
@@ -1574,7 +1575,7 @@ int iniGetSocketOptions(str_list_t list, const char* section, SOCKET sock
 
 		if((result=setsockopt(sock,level,option,(const char *)vp,len)) != 0) {
 			safe_snprintf(error,errlen,"%d (%s) setting socket option (%s, %d) to %d"
-				,ERROR_VALUE, socket_strerror(socket_errno), name, option, value);
+				,ERROR_VALUE, socket_strerror(socket_errno,err,sizeof(err)), name, option, value);
 			return(result);
 		}
 	}
diff --git a/src/xpdev/multisock.c b/src/xpdev/multisock.c
index 59078799a4..ec549cb93e 100644
--- a/src/xpdev/multisock.c
+++ b/src/xpdev/multisock.c
@@ -58,6 +58,7 @@ BOOL DLLCALL xpms_add(struct xpms_set *xpms_set, int domain, int type,
     unsigned int		added = 0;
     int					ret;
     char				port_str[6];
+	char				err[128];
 
 #ifndef _WIN32
 	struct addrinfo		dummy;
@@ -154,7 +155,7 @@ BOOL DLLCALL xpms_add(struct xpms_set *xpms_set, int domain, int type,
 				if(xpms_set->lprintf)
 					xpms_set->lprintf(LOG_WARNING, "%04d !%s ERROR %d (%s) listening on port %d"
 						,xpms_set->socks[xpms_set->sock_count].sock, prot, ERROR_VALUE
-						,socket_strerror(socket_errno), port);
+						,socket_strerror(socket_errno,err,sizeof(err)), port);
 				closesocket(xpms_set->socks[xpms_set->sock_count].sock);
 				FREE_AND_NULL(xpms_set->socks[xpms_set->sock_count].address);
 				FREE_AND_NULL(xpms_set->socks[xpms_set->sock_count].prot);
diff --git a/src/xpdev/sockwrap.c b/src/xpdev/sockwrap.c
index 5cf7832c87..5cc64a2cf7 100644
--- a/src/xpdev/sockwrap.c
+++ b/src/xpdev/sockwrap.c
@@ -352,6 +352,7 @@ int retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen
 			   ,int (*lprintf)(int level, const char *fmt, ...))
 {
 	char	port_str[128];
+	char	err[128];
 	int		result=-1;
 	uint	i;
 
@@ -364,7 +365,7 @@ int retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen
 			break;
 		if(lprintf!=NULL)
 			lprintf(i<retries ? LOG_WARNING:LOG_CRIT
-				,"%04d !ERROR %d (%s) binding %s socket%s", s, ERROR_VALUE, socket_strerror(socket_errno), prot, port_str);
+				,"%04d !ERROR %d (%s) binding %s socket%s", s, ERROR_VALUE, socket_strerror(socket_errno, err, sizeof(err)), prot, port_str);
 		if(i<retries) {
 			if(lprintf!=NULL)
 				lprintf(LOG_WARNING,"%04d Will retry in %u seconds (%u of %u)"
@@ -500,20 +501,21 @@ BOOL inet_addrmatch(union xp_sockaddr* addr1, union xp_sockaddr* addr2)
 	return FALSE;
 }
 
-#if defined(_WINSOCKAPI_)
 /* Return the current socket error description (for Windows), like strerror() does for errno */
-DLLEXPORT const char* socket_strerror(int error_number)
+DLLEXPORT char* socket_strerror(int error_number, char* buf, size_t buflen)
 {
-	static char msg[256];
-
+#if defined(_WINSOCKAPI_)
+	strlcpy(buf, "Unknown error", buflen);
 	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,	// dwFlags
 		NULL,			// lpSource
 		error_number,	// dwMessageId
 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),    // dwLanguageId
-		msg,
-		sizeof(msg),
+		buf,
+		buflen,
 		NULL);
-	truncsp(msg);
-	return msg;
-}
+	truncsp(buf);
+	return buf;
+#else
+	return safe_strerror(error_number, buf, buflen);
 #endif
+}
diff --git a/src/xpdev/sockwrap.h b/src/xpdev/sockwrap.h
index c9ad42fff6..b4afb35e7e 100644
--- a/src/xpdev/sockwrap.h
+++ b/src/xpdev/sockwrap.h
@@ -186,7 +186,7 @@ typedef uint32_t                in_addr_t;
 
 static  int wsa_error;
 #define ERROR_VALUE			((wsa_error=WSAGetLastError())>0 ? wsa_error-WSABASEERR : wsa_error)
-#define socket_errno			WSAGetLastError()
+#define socket_errno		WSAGetLastError()
 #define sendsocket(s,b,l)	send(s,b,l,0)
 
 /* For getaddrinfo() */
@@ -212,7 +212,6 @@ static  int wsa_error;
 #define ioctlsocket		ioctl
 #define ERROR_VALUE		errno
 #define socket_errno	errno
-#define socket_strerror	strerror
 #define sendsocket		write		/* FreeBSD send() is broken */
 
 #ifdef __WATCOMC__
@@ -240,10 +239,7 @@ DLLEXPORT const char* inet_addrtop(union xp_sockaddr *addr, char *dest, size_t s
 DLLEXPORT uint16_t inet_addrport(union xp_sockaddr *addr);
 DLLEXPORT void inet_setaddrport(union xp_sockaddr *addr, uint16_t port);
 DLLEXPORT BOOL inet_addrmatch(union xp_sockaddr* addr1, union xp_sockaddr* addr2);
-
-#if defined(_WINSOCKAPI_)
-DLLEXPORT const char* socket_strerror(int);
-#endif
+DLLEXPORT char* socket_strerror(int, char*, size_t);
 
 #ifdef __cplusplus
 }
-- 
GitLab