From 5133dad7a2bbd8532e79a025617a1a57e95aacc1 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Sun, 3 Jun 2012 15:07:36 +0200 Subject: [PATCH] Add Windows network functions in network.c This file was taken from ioQuake2 and refactored to match Yamagi Quake II. It would be nice to have IPv6 support and to remove the old IPX cruft, but that happen now. --- Makefile | 1 + src/windows/network.c | 1016 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1017 insertions(+) create mode 100644 src/windows/network.c diff --git a/Makefile b/Makefile index 3447fd88..3c49cc1f 100644 --- a/Makefile +++ b/Makefile @@ -489,6 +489,7 @@ ifeq ($(OSTYPE), Windows) SERVER_OBJS_ += \ src/windows/conproc.o \ src/windows/mem.o \ + src/windows/network.o \ src/windows/system.o else SERVER_OBJS_ += \ diff --git a/src/windows/network.c b/src/windows/network.c new file mode 100644 index 00000000..c2caae5c --- /dev/null +++ b/src/windows/network.c @@ -0,0 +1,1016 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * Network connections over IPv4 and IPX via Winsocks. + * + * ======================================================================= + */ + +#include "winsock.h" +#include "wsipx.h" +#include "../common/header/common.h" + +#define MAX_LOOPBACK 4 + +typedef struct +{ + byte data[MAX_MSGLEN]; + int datalen; +} loopmsg_t; + +typedef struct +{ + loopmsg_t msgs[MAX_LOOPBACK]; + int get, send; +} loopback_t; + +cvar_t *net_shownet; +static cvar_t *noudp; +static cvar_t *noipx; + +loopback_t loopbacks[2]; +int ip_sockets[2]; +int ipx_sockets[2]; + +static WSADATA winsockdata; + +char *NET_ErrorString(void); + +/* ============================================================================= */ + +void +NetadrToSockadr(netadr_t *a, struct sockaddr *s) +{ + memset(s, 0, sizeof(*s)); + + if (a->type == NA_BROADCAST) + { + ((struct sockaddr_in *)s)->sin_family = AF_INET; + ((struct sockaddr_in *)s)->sin_port = a->port; + ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST; + } + else if (a->type == NA_IP) + { + ((struct sockaddr_in *)s)->sin_family = AF_INET; + ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip; + ((struct sockaddr_in *)s)->sin_port = a->port; + } + else if (a->type == NA_IPX) + { + ((struct sockaddr_ipx *)s)->sa_family = AF_IPX; + memcpy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4); + memcpy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6); + ((struct sockaddr_ipx *)s)->sa_socket = a->port; + } + else if (a->type == NA_BROADCAST_IPX) + { + ((struct sockaddr_ipx *)s)->sa_family = AF_IPX; + memset(((struct sockaddr_ipx *)s)->sa_netnum, 0, 4); + memset(((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6); + ((struct sockaddr_ipx *)s)->sa_socket = a->port; + } +} + +void +SockadrToNetadr(struct sockaddr *s, netadr_t *a) +{ + if (s->sa_family == AF_INET) + { + a->type = NA_IP; + *(int *) &a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr; + a->port = ((struct sockaddr_in *)s)->sin_port; + } + else if (s->sa_family == AF_IPX) + { + a->type = NA_IPX; + memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4); + memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6); + a->port = ((struct sockaddr_ipx *)s)->sa_socket; + } +} + +qboolean +NET_CompareAdr(netadr_t a, netadr_t b) +{ + if (a.type != b.type) + { + return false; + } + + if (a.type == NA_LOOPBACK) + { + return TRUE; + } + + if (a.type == NA_IP) + { + if ((a.ip[0] == b.ip[0]) && (a.ip[1] == b.ip[1]) && + (a.ip[2] == b.ip[2]) && (a.ip[3] == b.ip[3]) && + (a.port == b.port)) + { + return true; + } + + return false; + } + + if (a.type == NA_IPX) + { + if ((memcmp(a.ipx, b.ipx, 10) == 0) && (a.port == b.port)) + { + return true; + } + + return false; + } + + return false; +} + +qboolean +NET_CompareBaseAdr(netadr_t a, netadr_t b) +{ + if (a.type != b.type) + { + return false; + } + + if (a.type == NA_LOOPBACK) + { + return TRUE; + } + + if (a.type == NA_IP) + { + if ((a.ip[0] == b.ip[0]) && (a.ip[1] == b.ip[1]) && + (a.ip[2] == b.ip[2]) && (a.ip[3] == b.ip[3])) + { + return true; + } + + return false; + } + + if (a.type == NA_IPX) + { + if ((memcmp(a.ipx, b.ipx, 10) == 0)) + { + return true; + } + + return false; + } + + return false; +} + +char * +NET_AdrToString(netadr_t a) +{ + static char s[64]; + + if (a.type == NA_LOOPBACK) + { + Com_sprintf(s, sizeof(s), "loopback"); + } + else if (a.type == NA_IP) + { + Com_sprintf(s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], + a.ip[1], a.ip[2], a.ip[3], ntohs(a.port)); + } + else + { + Com_sprintf(s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", + a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], + a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port)); + } + + return s; +} + +#define DO(src, dest) \ + copy[0] = s[src]; \ + copy[1] = s[src + 1]; \ + sscanf(copy, "%x", &val); \ + ((struct sockaddr_ipx *)sadr)->dest = val + +/* + * localhost + * idnewt + * idnewt:28000 + * 192.246.40.70 + * 192.246.40.70:28000 + */ +qboolean +NET_StringToSockaddr(char *s, struct sockaddr *sadr) +{ + struct hostent *h; + char *colon; + int val; + char copy[128]; + + memset(sadr, 0, sizeof(*sadr)); + + if ((strlen(s) >= 23) && (s[8] == ':') && (s[21] == ':')) /* check for an IPX address */ + { + ((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX; + copy[2] = 0; + DO(0, sa_netnum[0]); + DO(2, sa_netnum[1]); + DO(4, sa_netnum[2]); + DO(6, sa_netnum[3]); + DO(9, sa_nodenum[0]); + DO(11, sa_nodenum[1]); + DO(13, sa_nodenum[2]); + DO(15, sa_nodenum[3]); + DO(17, sa_nodenum[4]); + DO(19, sa_nodenum[5]); + sscanf(&s[22], "%u", &val); + ((struct sockaddr_ipx *)sadr)->sa_socket = htons((unsigned short)val); + } + else + { + ((struct sockaddr_in *)sadr)->sin_family = AF_INET; + + ((struct sockaddr_in *)sadr)->sin_port = 0; + + strcpy(copy, s); + + /* strip off a trailing :port if present */ + for (colon = copy; *colon; colon++) + { + if (*colon == ':') + { + *colon = 0; + ((struct sockaddr_in *)sadr)->sin_port = + htons((short)atoi(colon + 1)); + } + } + + if ((copy[0] >= '0') && (copy[0] <= '9')) + { + *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy); + } + else + { + if (!(h = gethostbyname(copy))) + { + return 0; + } + + *(int *)&((struct sockaddr_in *)sadr)->sin_addr = + *(int *)h->h_addr_list[0]; + } + } + + return true; +} + +#undef DO + +/* + * localhost + * idnewt + * idnewt:28000 + * 192.246.40.70 + * 192.246.40.70:28000 + */ +qboolean +NET_StringToAdr(char *s, netadr_t *a) +{ + struct sockaddr sadr; + + if (!strcmp(s, "localhost")) + { + memset(a, 0, sizeof(*a)); + a->type = NA_LOOPBACK; + return true; + } + + if (!NET_StringToSockaddr(s, &sadr)) + { + return false; + } + + SockadrToNetadr(&sadr, a); + + return true; +} + +qboolean +NET_IsLocalAddress(netadr_t adr) +{ + return adr.type == NA_LOOPBACK; +} + +/* ============================================================================= */ + +qboolean +NET_GetLoopPacket(netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message) +{ + int i; + loopback_t *loop; + + loop = &loopbacks[sock]; + + if (loop->send - loop->get > MAX_LOOPBACK) + { + loop->get = loop->send - MAX_LOOPBACK; + } + + if (loop->get >= loop->send) + { + return false; + } + + i = loop->get & (MAX_LOOPBACK - 1); + loop->get++; + + memcpy(net_message->data, loop->msgs[i].data, loop->msgs[i].datalen); + net_message->cursize = loop->msgs[i].datalen; + memset(net_from, 0, sizeof(*net_from)); + net_from->type = NA_LOOPBACK; + return true; +} + +void +NET_SendLoopPacket(netsrc_t sock, int length, void *data, netadr_t to) +{ + int i; + loopback_t *loop; + + loop = &loopbacks[sock ^ 1]; + + i = loop->send & (MAX_LOOPBACK - 1); + loop->send++; + + memcpy(loop->msgs[i].data, data, length); + loop->msgs[i].datalen = length; +} + +/* ============================================================================= */ + +qboolean +NET_GetPacket(netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message) +{ + int ret; + struct sockaddr from; + int fromlen; + int net_socket; + int protocol; + int err; + + if (NET_GetLoopPacket(sock, net_from, net_message)) + { + return true; + } + + for (protocol = 0; protocol < 2; protocol++) + { + if (protocol == 0) + { + net_socket = ip_sockets[sock]; + } + else + { + net_socket = ipx_sockets[sock]; + } + + if (!net_socket) + { + continue; + } + + fromlen = sizeof(from); + ret = recvfrom(net_socket, (char *)net_message->data, net_message->maxsize, + 0, (struct sockaddr *)&from, &fromlen); + + SockadrToNetadr(&from, net_from); + + if (ret == -1) + { + err = WSAGetLastError(); + + if (err == WSAEWOULDBLOCK) + { + continue; + } + + if (err == WSAEMSGSIZE) + { + Com_Printf("Warning: Oversize packet from %s\n", + NET_AdrToString(*net_from)); + continue; + } + + if (dedicated->value) /* let dedicated servers continue after errors */ + { + Com_Printf("NET_GetPacket: %s from %s\n", NET_ErrorString(), + NET_AdrToString(*net_from)); + } + else + { + Com_Error(ERR_DROP, "NET_GetPacket: %s from %s", + NET_ErrorString(), NET_AdrToString(*net_from)); + } + + continue; + } + + if (ret == net_message->maxsize) + { + Com_Printf("Oversize packet from %s\n", NET_AdrToString(*net_from)); + continue; + } + + net_message->cursize = ret; + return true; + } + + return false; +} + +/* ============================================================================= */ + +void +NET_SendPacket(netsrc_t sock, int length, void *data, netadr_t to) +{ + int ret; + struct sockaddr addr; + int net_socket = 0; + + if (to.type == NA_LOOPBACK) + { + NET_SendLoopPacket(sock, length, data, to); + return; + } + + if (to.type == NA_BROADCAST) + { + net_socket = ip_sockets[sock]; + + if (!net_socket) + { + return; + } + } + else if (to.type == NA_IP) + { + net_socket = ip_sockets[sock]; + + if (!net_socket) + { + return; + } + } + else if (to.type == NA_IPX) + { + net_socket = ipx_sockets[sock]; + + if (!net_socket) + { + return; + } + } + else if (to.type == NA_BROADCAST_IPX) + { + net_socket = ipx_sockets[sock]; + + if (!net_socket) + { + return; + } + } + else + { + Com_Error(ERR_FATAL, "NET_SendPacket: bad address type"); + } + + NetadrToSockadr(&to, &addr); + + ret = sendto(net_socket, data, length, 0, &addr, sizeof(addr)); + + if (ret == -1) + { + int err = WSAGetLastError(); + + /* wouldblock is silent */ + if (err == WSAEWOULDBLOCK) + { + return; + } + + /* some PPP links dont allow broadcasts */ + if ((err == WSAEADDRNOTAVAIL) && + ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX))) + { + return; + } + + if (dedicated->value) /* let dedicated servers continue after errors */ + { + Com_Printf("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(), + NET_AdrToString(to)); + } + else + { + if (err == WSAEADDRNOTAVAIL) + { + Com_DPrintf("NET_SendPacket Warning: %s : %s\n", + NET_ErrorString(), NET_AdrToString(to)); + } + else + { + Com_Error(ERR_DROP, "NET_SendPacket ERROR: %s to %s\n", + NET_ErrorString(), NET_AdrToString(to)); + } + } + } +} + +/* ============================================================================= */ + +int +NET_IPSocket(char *net_interface, int port) +{ + int newsocket; + struct sockaddr_in address; + unsigned long t; + int i = 1; + int err; + + if ((newsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + err = WSAGetLastError(); + + if (err != WSAEAFNOSUPPORT) + { + Com_Printf("WARNING: UDP_OpenSocket: socket: %s", NET_ErrorString()); + } + + return 0; + } + + /* make it non-blocking */ + if (ioctlsocket(newsocket, FIONBIO, &t) == -1) + { + Com_Printf("WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", + NET_ErrorString()); + return 0; + } + + /* make it broadcast capable */ + if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, + sizeof(i)) == -1) + { + Com_Printf("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", + NET_ErrorString()); + return 0; + } + + if (!net_interface || !net_interface[0] || + !stricmp(net_interface, "localhost")) + { + address.sin_addr.s_addr = INADDR_ANY; + } + else + { + NET_StringToSockaddr(net_interface, (struct sockaddr *)&address); + } + + if (port == PORT_ANY) + { + address.sin_port = 0; + } + else + { + address.sin_port = htons((short)port); + } + + address.sin_family = AF_INET; + + if (bind(newsocket, (void *)&address, sizeof(address)) == -1) + { + Com_Printf("WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString()); + closesocket(newsocket); + return 0; + } + + return newsocket; +} + +void +NET_OpenIP(void) +{ + cvar_t *ip; + int port; + int dedicated; + + ip = Cvar_Get("ip", "localhost", CVAR_NOSET); + + dedicated = Cvar_VariableValue("dedicated"); + + if (!ip_sockets[NS_SERVER]) + { + port = Cvar_Get("ip_hostport", "0", CVAR_NOSET)->value; + + if (!port) + { + port = Cvar_Get("hostport", "0", CVAR_NOSET)->value; + + if (!port) + { + port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value; + } + } + + ip_sockets[NS_SERVER] = NET_IPSocket(ip->string, port); + + if (!ip_sockets[NS_SERVER] && dedicated) + { + Com_Error(ERR_FATAL, "Couldn't allocate dedicated server IP port"); + } + } + + /* dedicated servers don't need client ports */ + if (dedicated) + { + return; + } + + if (!ip_sockets[NS_CLIENT]) + { + port = Cvar_Get("ip_clientport", "0", CVAR_NOSET)->value; + + if (!port) + { + port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value; + + if (!port) + { + port = PORT_ANY; + } + } + + ip_sockets[NS_CLIENT] = NET_IPSocket(ip->string, port); + + if (!ip_sockets[NS_CLIENT]) + { + ip_sockets[NS_CLIENT] = NET_IPSocket(ip->string, PORT_ANY); + } + } +} + +int +NET_IPXSocket(int port) +{ + int newsocket; + struct sockaddr_ipx address; + unsigned long t = 1; + int err; + + if ((newsocket = socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1) + { + err = WSAGetLastError(); + + if (err != WSAEAFNOSUPPORT) + { + Com_Printf("WARNING: IPX_Socket: socket: %s\n", NET_ErrorString()); + } + + return 0; + } + + /* make it non-blocking */ + if (ioctlsocket(newsocket, FIONBIO, &t) == -1) + { + Com_Printf("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString()); + return 0; + } + + /* make it broadcast capable */ + if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&t, + sizeof(t)) == -1) + { + Com_Printf("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", + NET_ErrorString()); + return 0; + } + + address.sa_family = AF_IPX; + memset(address.sa_netnum, 0, 4); + memset(address.sa_nodenum, 0, 6); + + if (port == PORT_ANY) + { + address.sa_socket = 0; + } + else + { + address.sa_socket = htons((short)port); + } + + if (bind(newsocket, (void *)&address, sizeof(address)) == -1) + { + Com_Printf("WARNING: IPX_Socket: bind: %s\n", NET_ErrorString()); + closesocket(newsocket); + return 0; + } + + return newsocket; +} + +void +NET_OpenIPX(void) +{ + int port; + int dedicated; + + dedicated = Cvar_VariableValue("dedicated"); + + if (!ipx_sockets[NS_SERVER]) + { + port = Cvar_Get("ipx_hostport", "0", CVAR_NOSET)->value; + + if (!port) + { + port = Cvar_Get("hostport", "0", CVAR_NOSET)->value; + + if (!port) + { + port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value; + } + } + + ipx_sockets[NS_SERVER] = NET_IPXSocket(port); + } + + /* dedicated servers don't need client ports */ + if (dedicated) + { + return; + } + + if (!ipx_sockets[NS_CLIENT]) + { + port = Cvar_Get("ipx_clientport", "0", CVAR_NOSET)->value; + + if (!port) + { + port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value; + + if (!port) + { + port = PORT_ANY; + } + } + + ipx_sockets[NS_CLIENT] = NET_IPXSocket(port); + + if (!ipx_sockets[NS_CLIENT]) + { + ipx_sockets[NS_CLIENT] = NET_IPXSocket(PORT_ANY); + } + } +} + +/* + * A single player game will only use the loopback code + */ +void +NET_Config(qboolean multiplayer) +{ + int i; + static qboolean old_config; + + if (old_config == multiplayer) + { + return; + } + + old_config = multiplayer; + + if (!multiplayer) + { + /* shut down any existing sockets */ + for (i = 0; i < 2; i++) + { + if (ip_sockets[i]) + { + closesocket(ip_sockets[i]); + ip_sockets[i] = 0; + } + + if (ipx_sockets[i]) + { + closesocket(ipx_sockets[i]); + ipx_sockets[i] = 0; + } + } + } + else + { + /* open sockets */ + if (!noudp->value) + { + NET_OpenIP(); + } + + if (!noipx->value) + { + NET_OpenIPX(); + } + } +} + +/* + * sleeps msec or until + * net socket is ready + */ +void +NET_Sleep(int msec) +{ + struct timeval timeout; + fd_set fdset; + extern cvar_t *dedicated; + int i; + + if (!dedicated || !dedicated->value) + { + return; /* we're not a server, just run full speed */ + } + + FD_ZERO(&fdset); + i = 0; + + if (ip_sockets[NS_SERVER]) + { + FD_SET(ip_sockets[NS_SERVER], &fdset); /* network socket */ + i = ip_sockets[NS_SERVER]; + } + + if (ipx_sockets[NS_SERVER]) + { + FD_SET(ipx_sockets[NS_SERVER], &fdset); /* network socket */ + + if (ipx_sockets[NS_SERVER] > i) + { + i = ipx_sockets[NS_SERVER]; + } + } + + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + select(i + 1, &fdset, NULL, NULL, &timeout); +} + +/* =================================================================== */ + +void +NET_Init(void) +{ + int r; + + r = WSAStartup(MAKEWORD(1, 1), &winsockdata); + + if (r) + { + Com_Error(ERR_FATAL, "Winsock initialization failed."); + } + + Com_Printf("Winsock Initialized\n"); + + noudp = Cvar_Get("noudp", "0", CVAR_NOSET); + noipx = Cvar_Get("noipx", "0", CVAR_NOSET); + + net_shownet = Cvar_Get("net_shownet", "0", 0); +} + +void +NET_Shutdown(void) +{ + NET_Config(false); /* close sockets */ + + WSACleanup(); +} + +char * +NET_ErrorString(void) +{ + int code; + + code = WSAGetLastError(); + + switch (code) + { + case WSAEINTR: + return "WSAEINTR"; + case WSAEBADF: + return "WSAEBADF"; + case WSAEACCES: + return "WSAEACCES"; + case WSAEDISCON: + return "WSAEDISCON"; + case WSAEFAULT: + return "WSAEFAULT"; + case WSAEINVAL: + return "WSAEINVAL"; + case WSAEMFILE: + return "WSAEMFILE"; + case WSAEWOULDBLOCK: + return "WSAEWOULDBLOCK"; + case WSAEINPROGRESS: + return "WSAEINPROGRESS"; + case WSAEALREADY: + return "WSAEALREADY"; + case WSAENOTSOCK: + return "WSAENOTSOCK"; + case WSAEDESTADDRREQ: + return "WSAEDESTADDRREQ"; + case WSAEMSGSIZE: + return "WSAEMSGSIZE"; + case WSAEPROTOTYPE: + return "WSAEPROTOTYPE"; + case WSAENOPROTOOPT: + return "WSAENOPROTOOPT"; + case WSAEPROTONOSUPPORT: + return "WSAEPROTONOSUPPORT"; + case WSAESOCKTNOSUPPORT: + return "WSAESOCKTNOSUPPORT"; + case WSAEOPNOTSUPP: + return "WSAEOPNOTSUPP"; + case WSAEPFNOSUPPORT: + return "WSAEPFNOSUPPORT"; + case WSAEAFNOSUPPORT: + return "WSAEAFNOSUPPORT"; + case WSAEADDRINUSE: + return "WSAEADDRINUSE"; + case WSAEADDRNOTAVAIL: + return "WSAEADDRNOTAVAIL"; + case WSAENETDOWN: + return "WSAENETDOWN"; + case WSAENETUNREACH: + return "WSAENETUNREACH"; + case WSAENETRESET: + return "WSAENETRESET"; + case WSAECONNABORTED: + return "WSWSAECONNABORTEDAEINTR"; + case WSAECONNRESET: + return "WSAECONNRESET"; + case WSAENOBUFS: + return "WSAENOBUFS"; + case WSAEISCONN: + return "WSAEISCONN"; + case WSAENOTCONN: + return "WSAENOTCONN"; + case WSAESHUTDOWN: + return "WSAESHUTDOWN"; + case WSAETOOMANYREFS: + return "WSAETOOMANYREFS"; + case WSAETIMEDOUT: + return "WSAETIMEDOUT"; + case WSAECONNREFUSED: + return "WSAECONNREFUSED"; + case WSAELOOP: + return "WSAELOOP"; + case WSAENAMETOOLONG: + return "WSAENAMETOOLONG"; + case WSAEHOSTDOWN: + return "WSAEHOSTDOWN"; + case WSASYSNOTREADY: + return "WSASYSNOTREADY"; + case WSAVERNOTSUPPORTED: + return "WSAVERNOTSUPPORTED"; + case WSANOTINITIALISED: + return "WSANOTINITIALISED"; + case WSAHOST_NOT_FOUND: + return "WSAHOST_NOT_FOUND"; + case WSATRY_AGAIN: + return "WSATRY_AGAIN"; + case WSANO_RECOVERY: + return "WSANO_RECOVERY"; + case WSANO_DATA: + return "WSANO_DATA"; + default: + return "NO ERROR"; + } +} +