From c7a74f3441ec34cdd0786a7f14eb82fa6b53ee0e Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 24 Sep 2023 00:45:22 -0400
Subject: [PATCH] Cleaned up error management to be Windows-friendly.
---
SDL_net.c | 122 +++++++++++++++++++++++++----------
examples/resolve-hostnames.c | 10 ++-
2 files changed, 96 insertions(+), 36 deletions(-)
diff --git a/SDL_net.c b/SDL_net.c
index b4d4cae..eda3038 100644
--- a/SDL_net.c
+++ b/SDL_net.c
@@ -8,21 +8,23 @@
typedef SOCKET Socket;
typedef int SockLen;
typedef SOCKADDR_STORAGE AddressStorage;
+
static int write(SOCKET s, const char *buf, size_t count) {
return send(s, buf, count, 0);
}
+
static int read(SOCKET s, char *buf, size_t count) {
WSABUF wsabuf;
wsabuf.buf = buf;
wsabuf.len = count;
DWORD count_received;
- int res = WSARecv(s, &wsabuf, 1, &count_received, 0, NULL, NULL);
+ const int res = WSARecv(s, &wsabuf, 1, &count_received, 0, NULL, NULL);
if (res != 0) {
- SDL_SetError("WSARecv(%d)", WSAGetLastError());
return -1;
}
return (int)count_received;
}
+
#define EAI_SYSTEM 0
#define poll WSAPoll
#else
@@ -97,8 +99,16 @@ static int RandomNumberBetween(const int lo, const int hi)
return (RandomNumber() % (hi + 1 - lo)) + lo;
}
-// !!! FIXME: replace strerror.
-// !!! FIXME: replace errno.
+
+static int CloseSocketHandle(Socket handle)
+{
+#ifdef __WINDOWS__
+ return closesocket(handle);
+#else
+ return close(handle);
+#endif
+}
+
static int LastSocketError(void)
{
#ifdef __WINDOWS__
@@ -108,15 +118,59 @@ static int LastSocketError(void)
#endif
}
-static int CloseSocketHandle(Socket handle)
+static char *CreateSocketErrorString(int rc)
{
#ifdef __WINDOWS__
- return closesocket(handle);
+ WCHAR msgbuf[256];
+ const DWORD bw = FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ msgbuf,
+ SDL_arraysize(msgbuf),
+ NULL
+ );
+ if (bw == 0) {
+ return SDL_strdup("Unknown error");
+ }
+ return SDL_iconv_string("UTF-8", "UTF-16LE", (const char *)msgbuf, (bw+1) * sizeof (WCHAR));
#else
- return close(handle);
+ return SDL_strdup(strerror(rc));
#endif
}
+static char *CreateGetAddrInfoErrorString(int rc)
+{
+#ifdef __WINDOWS__
+ return CreateSocketErrorString(rc); // same error codes.
+#else
+ return SDL_strdup((rc == EAI_SYSTEM) ? strerror(errno) : gai_strerror(rc));
+#endif
+}
+
+static int SetSocketError(const char *msg, int err)
+{
+ char *errmsg = CreateSocketErrorString(err);
+ SDL_SetError("%s: %s", msg, errmsg);
+ SDL_free(errmsg);
+ return -1;
+}
+
+static int SetLastSocketError(const char *msg)
+{
+ return SetSocketError(msg, LastSocketError());
+}
+
+static int SetGetAddrInfoError(const char *msg, int err)
+{
+ char *errmsg = CreateGetAddrInfoErrorString(err);
+ SDL_SetError("%s: %s", msg, errmsg);
+ SDL_free(errmsg);
+ return -1;
+}
+
// this blocks!
static int ResolveAddress(SDLNet_Address *addr)
{
@@ -124,11 +178,11 @@ static int ResolveAddress(SDLNet_Address *addr)
struct addrinfo *ainfo = NULL;
int rc;
-//SDL_Log("getaddrinfo '%s'", addr->hostname);
+ //SDL_Log("getaddrinfo '%s'", addr->hostname);
rc = getaddrinfo(addr->hostname, NULL, NULL, &ainfo);
-//SDL_Log("rc=%d", rc);
+ //SDL_Log("rc=%d", rc);
if (rc != 0) {
- addr->errstr = SDL_strdup((rc == EAI_SYSTEM) ? strerror(errno) : gai_strerror(rc));
+ addr->errstr = CreateGetAddrInfoErrorString(rc);
return -1; // error
} else if (ainfo == NULL) {
addr->errstr = SDL_strdup("Unknown error (query succeeded but result was NULL!)");
@@ -138,7 +192,7 @@ static int ResolveAddress(SDLNet_Address *addr)
char buf[128];
rc = getnameinfo(ainfo->ai_addr, ainfo->ai_addrlen, buf, sizeof (buf), NULL, 0, NI_NUMERICHOST);
if (rc != 0) {
- addr->errstr = SDL_strdup((rc == EAI_SYSTEM) ? strerror(errno) : gai_strerror(rc));
+ addr->errstr = CreateGetAddrInfoErrorString(rc);
freeaddrinfo(ainfo);
return -1; // error
}
@@ -241,7 +295,7 @@ int SDLNet_Init(void)
#ifdef __WINDOWS__
WSADATA data;
if (WSAStartup(MAKEWORD(1, 1), &data) != 0) {
- return SDL_SetError("WSAStartup() failed");
+ return SetSocketError("WSAStartup() failed", LastSocketError());
}
#else
signal(SIGPIPE, SIG_IGN);
@@ -508,7 +562,9 @@ static struct addrinfo *MakeAddrInfoWithPort(const SDLNet_Address *addr, const i
struct addrinfo *addrwithport = NULL;
int rc = getaddrinfo(addr ? addr->human_readable : NULL, service, &hints, &addrwithport);
if (rc != 0) {
- SDL_SetError("Failed to prepare address with port: %s", (rc == EAI_SYSTEM) ? strerror(errno) : gai_strerror(rc));
+ char *errstr = CreateGetAddrInfoErrorString(rc);
+ SDL_SetError("Failed to prepare address with port: %s", errstr);
+ SDL_free(errstr);
return NULL;
}
@@ -579,7 +635,7 @@ SDLNet_StreamSocket *SDLNet_CreateClient(SDLNet_Address *addr, Uint16 port)
sock->handle = socket(addrwithport->ai_family, addrwithport->ai_socktype, addrwithport->ai_protocol);
if (sock->handle == INVALID_SOCKET) {
- SDL_SetError("Failed to create socket: %s", strerror(errno));
+ SetLastSocketError("Failed to create socket");
freeaddrinfo(addrwithport);
SDL_free(sock);
return NULL;
@@ -600,7 +656,7 @@ SDLNet_StreamSocket *SDLNet_CreateClient(SDLNet_Address *addr, Uint16 port)
if (rc == SOCKET_ERROR) {
const int err = LastSocketError();
if (!WouldBlock(err)) {
- SDL_SetError("Connection failed at startup: %s", strerror(err));
+ SetSocketError("Connection failed at startup", err);
CloseSocketHandle(sock->handle);
SDL_free(sock);
return NULL;
@@ -672,7 +728,7 @@ SDLNet_Server *SDLNet_CreateServer(SDLNet_Address *addr, Uint16 port)
server->handle = socket(addrwithport->ai_family, addrwithport->ai_socktype, addrwithport->ai_protocol);
if (server->handle == INVALID_SOCKET) {
- SDL_SetError("Failed to create listen socket: %s", strerror(errno));
+ SetLastSocketError("Failed to create listen socket");
freeaddrinfo(addrwithport);
SDL_free(server);
return NULL;
@@ -692,7 +748,7 @@ SDLNet_Server *SDLNet_CreateServer(SDLNet_Address *addr, Uint16 port)
if (rc == SOCKET_ERROR) {
const int err = LastSocketError();
SDL_assert(!WouldBlock(err)); // binding shouldn't be a blocking operation.
- SDL_SetError("Failed to bind listen socket: %s", strerror(err));
+ SetSocketError("Failed to bind listen socket", err);
CloseSocketHandle(server->handle);
SDL_free(server);
return NULL;
@@ -702,7 +758,7 @@ SDLNet_Server *SDLNet_CreateServer(SDLNet_Address *addr, Uint16 port)
if (rc == SOCKET_ERROR) {
const int err = LastSocketError();
SDL_assert(!WouldBlock(err)); // listen shouldn't be a blocking operation.
- SDL_SetError("Failed to listen on socket: %s", strerror(err));
+ SetSocketError("Failed to listen on socket", err);
CloseSocketHandle(server->handle);
SDL_free(server);
return NULL;
@@ -729,7 +785,7 @@ int SDLNet_AcceptClient(SDLNet_Server *server, SDLNet_StreamSocket **client_stre
const Socket handle = accept(server->handle, (struct sockaddr *) &from, &fromlen);
if (handle == INVALID_SOCKET) {
const int err = LastSocketError();
- return WouldBlock(err) ? 0 : SDL_SetError("Failed to accept new connection: %s", strerror(err));
+ return WouldBlock(err) ? 0 : SetSocketError("Failed to accept new connection", err);
}
if (MakeSocketNonblocking(handle) < 0) {
@@ -743,7 +799,7 @@ int SDLNet_AcceptClient(SDLNet_Server *server, SDLNet_StreamSocket **client_stre
const int rc = getnameinfo((struct sockaddr *) &from, fromlen, hostbuf, sizeof (hostbuf), portbuf, sizeof (portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (rc != 0) {
CloseSocketHandle(handle);
- return SDL_SetError("Failed to determine incoming connection's address: %s", (rc == EAI_SYSTEM) ? strerror(errno) : gai_strerror(rc));
+ return SetGetAddrInfoError("Failed to determine incoming connection's address", rc);
}
SDLNet_Address *fromaddr = (SDLNet_Address *) SDL_calloc(1, sizeof (SDLNet_Address));
@@ -764,7 +820,7 @@ int SDLNet_AcceptClient(SDLNet_Server *server, SDLNet_StreamSocket **client_stre
if (gairc != 0) {
SDL_free(fromaddr);
CloseSocketHandle(handle);
- return SDL_SetError("Failed to determine incoming connection's address: %s", (rc == EAI_SYSTEM) ? strerror(errno) : gai_strerror(rc));
+ return SetGetAddrInfoError("Failed to determine incoming connection's address: %s", rc);
}
fromaddr->human_readable = SDL_strdup(hostbuf);
@@ -839,7 +895,7 @@ static int PumpStreamSocket(SDLNet_StreamSocket *sock)
const int bw = (int) write(sock->handle, sock->pending_output_buffer, sock->pending_output_len);
if (bw < 0) {
const int err = LastSocketError();
- return WouldBlock(err) ? 0 : SDL_SetError("Failed to write to socket: %s", strerror(err));
+ return WouldBlock(err) ? 0 : SetSocketError("Failed to write to socket", err);
} else if (bw < sock->pending_output_len) {
SDL_memmove(sock->pending_output_buffer, sock->pending_output_buffer + bw, sock->pending_output_len - bw);
}
@@ -870,7 +926,7 @@ int SDLNet_WriteToStreamSocket(SDLNet_StreamSocket *sock, const void *buf, int b
if (bw < 0) {
const int err = LastSocketError();
if (!WouldBlock(err)) {
- return SDL_SetError("Failed to write to socket: %s", strerror(err));
+ return SetSocketError("Failed to write to socket", err);
}
} else if (bw == buflen) { // sent the whole thing? We're good to go here.
return 0;
@@ -925,7 +981,7 @@ int SDLNet_WaitUntilStreamSocketDrained(SDLNet_StreamSocket *sock, int timeoutms
pfd.events = POLLOUT;
const int rc = poll(&pfd, 1, timeoutms);
if (rc == SOCKET_ERROR) {
- return SDL_SetError("Socket poll failed: %s", strerror(errno));
+ return SetLastSocketError("Socket poll failed");
} else if (rc == 0) {
break; // timed out
}
@@ -965,7 +1021,7 @@ int SDLNet_ReadStreamSocket(SDLNet_StreamSocket *sock, void *buf, int buflen)
return SDL_SetError("End of stream");
} else if (br < 0) {
const int err = LastSocketError();
- return WouldBlock(err) ? 0 : SDL_SetError("Failed to read from socket: %s", strerror(err));
+ return WouldBlock(err) ? 0 : SetSocketError("Failed to read from socket", err);
}
UpdateStreamSocketSimulatedFailure(sock);
@@ -1046,7 +1102,7 @@ SDLNet_DatagramSocket *SDLNet_CreateDatagramSocket(SDLNet_Address *addr, Uint16
sock->handle = socket(addrwithport->ai_family, addrwithport->ai_socktype, addrwithport->ai_protocol);
if (sock->handle == INVALID_SOCKET) {
- SDL_SetError("Failed to create socket: %s", strerror(errno));
+ SetLastSocketError("Failed to create socket");
freeaddrinfo(addrwithport);
SDL_free(sock);
return NULL;
@@ -1066,7 +1122,7 @@ SDLNet_DatagramSocket *SDLNet_CreateDatagramSocket(SDLNet_Address *addr, Uint16
if (rc == SOCKET_ERROR) {
const int err = LastSocketError();
SDL_assert(!WouldBlock(err)); // binding shouldn't be a blocking operation.
- SDL_SetError("Failed to bind socket: %s", strerror(err));
+ SetSocketError("Failed to bind socket", err);
CloseSocketHandle(sock->handle);
SDL_free(sock);
return NULL;
@@ -1087,7 +1143,7 @@ static int SendOneDatagram(SDLNet_DatagramSocket *sock, SDLNet_Address *addr, Ui
if (rc == SOCKET_ERROR) {
const int err = LastSocketError();
- return WouldBlock(err) ? 0 : SDL_SetError("Failed to send from socket: %s", strerror(err));
+ return WouldBlock(err) ? 0 : SetSocketError("Failed to send from socket", err);
}
SDL_assert(rc == buflen);
@@ -1199,7 +1255,7 @@ int SDLNet_ReceiveDatagram(SDLNet_DatagramSocket *sock, SDLNet_Datagram **dgram)
const int br = recvfrom(sock->handle, sock->recv_buffer, sizeof (sock->recv_buffer), 0, (struct sockaddr *) &from, &fromlen);
if (br == SOCKET_ERROR) {
const int err = LastSocketError();
- return WouldBlock(err) ? 0 : SDL_SetError("Failed to receive datagrams: %s", strerror(err));
+ return WouldBlock(err) ? 0 : SetSocketError("Failed to receive datagrams", err);
} else if (sock->percent_loss && (RandomNumberBetween(0, 100) > sock->percent_loss)) {
// you won the percent_loss lottery. Drop this packet as if it never arrived.
return 0;
@@ -1210,7 +1266,7 @@ int SDLNet_ReceiveDatagram(SDLNet_DatagramSocket *sock, SDLNet_Datagram **dgram)
char portbuf[16];
const int rc = getnameinfo((struct sockaddr *) &from, fromlen, hostbuf, sizeof (hostbuf), portbuf, sizeof (portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (rc != 0) {
- return SDL_SetError("Failed to determine incoming packet's address: %s", (rc == EAI_SYSTEM) ? strerror(errno) : gai_strerror(rc));
+ return SetGetAddrInfoError("Failed to determine incoming packet's address", rc);
}
// Cache the last X addresses we saw; if we see it again, refcount it and reuse it.
@@ -1256,7 +1312,7 @@ int SDLNet_ReceiveDatagram(SDLNet_DatagramSocket *sock, SDLNet_Datagram **dgram)
const int gairc = getaddrinfo(hostbuf, NULL, &hints, &fromaddr->ainfo);
if (gairc != 0) {
SDL_free(fromaddr);
- return SDL_SetError("Failed to determine incoming packet's address: %s", (rc == EAI_SYSTEM) ? strerror(errno) : gai_strerror(rc));
+ return SetGetAddrInfoError("Failed to determine incoming packet's address", gairc);
}
fromaddr->human_readable = SDL_strdup(hostbuf);
@@ -1407,7 +1463,7 @@ int SDLNet_WaitUntilInputAvailable(void **vsockets, int numsockets, int timeoutm
if (rc == SOCKET_ERROR) {
SDL_free(malloced_pfds);
- return SDL_SetError("Socket poll failed: %s", strerror(errno));
+ return SetLastSocketError("Socket poll failed");
}
for (int i = 0; i < numsockets; i++) {
@@ -1428,7 +1484,7 @@ int SDLNet_WaitUntilInputAvailable(void **vsockets, int numsockets, int timeoutm
int err = 0;
SockLen errsize = sizeof (err);
getsockopt(pfd->fd, SOL_SOCKET, SO_ERROR, (char*)&err, &errsize);
- sock->stream.status = SDL_SetError("Socket failed to connect: %s", strerror(err));
+ sock->stream.status = SetSocketError("Socket failed to connect", err);
} else if (writable) {
sock->stream.status = 1;
}
diff --git a/examples/resolve-hostnames.c b/examples/resolve-hostnames.c
index f12b708..e028d25 100644
--- a/examples/resolve-hostnames.c
+++ b/examples/resolve-hostnames.c
@@ -25,10 +25,14 @@ int main(int argc, char **argv)
}
for (int i = 1; i < argc; i++) {
- const char *str;
SDLNet_WaitUntilResolved(addrs[i], -1);
- str = SDLNet_GetAddressString(addrs[i]);
- SDL_Log("%s: %s", argv[i], str ? str : "[FAILED TO RESOLVE]");
+
+ if (SDLNet_GetAddressStatus(addrs[i]) == -1) {
+ SDL_Log("%s: [FAILED TO RESOLVE: %s]", argv[i], SDL_GetError());
+ } else {
+ SDL_Log("%s: %s", argv[i], SDLNet_GetAddressString(addrs[i]));
+ }
+
SDLNet_UnrefAddress(addrs[i]);
}