summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/common.mk1
-rw-r--r--src/cl_local.h1
-rw-r--r--src/cl_main.c6
-rw-r--r--src/cl_public.h3
-rw-r--r--src/common.c5
-rw-r--r--src/in_evdev.c12
-rw-r--r--src/in_lirc.c13
-rw-r--r--src/io_sleep.c334
-rw-r--r--src/io_sleep.h45
-rw-r--r--src/mvd_client.c4
-rw-r--r--src/net_chan.c14
-rw-r--r--src/net_chan.h4
-rw-r--r--src/net_common.c1318
-rw-r--r--src/net_sock.h62
-rw-r--r--src/net_stream.h4
-rw-r--r--src/net_unix.h409
-rw-r--r--src/net_win.h401
-rw-r--r--src/sv_ac.c10
-rw-r--r--src/sv_local.h1
-rw-r--r--src/sv_main.c85
-rw-r--r--src/sv_mvd.c6
-rw-r--r--src/sv_public.h2
-rw-r--r--src/sv_send.c13
-rw-r--r--src/sys_unix.c6
-rw-r--r--src/wsaerr.h86
25 files changed, 1530 insertions, 1315 deletions
diff --git a/build/common.mk b/build/common.mk
index e11417a..101ea13 100644
--- a/build/common.mk
+++ b/build/common.mk
@@ -29,7 +29,6 @@ SRCFILES+=cmd.c \
q_msg.c \
q_shared.c \
q_field.c \
- io_sleep.c \
error.c \
fpu.c
diff --git a/src/cl_local.h b/src/cl_local.h
index cbd5e97..f0fc535 100644
--- a/src/cl_local.h
+++ b/src/cl_local.h
@@ -37,7 +37,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "cl_public.h"
#include "ui_public.h"
#include "sv_public.h"
-#include "io_sleep.h"
#include "vid_public.h"
#if USE_ZLIB
#include <zlib.h>
diff --git a/src/cl_main.c b/src/cl_main.c
index ccc627e..b5f3b79 100644
--- a/src/cl_main.c
+++ b/src/cl_main.c
@@ -1583,7 +1583,7 @@ static void CL_PacketEvent(void)
}
#if USE_ICMP
-void CL_ErrorEvent(void)
+void CL_ErrorEvent(netadr_t *from)
{
//
// error packet from server
@@ -1594,10 +1594,10 @@ void CL_ErrorEvent(void)
if (!cls.netchan) {
return; // dump it if not connected
}
- if (!NET_IsEqualBaseAdr(&net_from, &cls.netchan->remote_address)) {
+ if (!NET_IsEqualBaseAdr(from, &cls.netchan->remote_address)) {
return;
}
- if (net_from.port && net_from.port != cls.netchan->remote_address.port) {
+ if (from->port && from->port != cls.netchan->remote_address.port) {
return;
}
diff --git a/src/cl_public.h b/src/cl_public.h
index 77cee04..12c9628 100644
--- a/src/cl_public.h
+++ b/src/cl_public.h
@@ -49,7 +49,8 @@ typedef enum {
qboolean CL_ProcessEvents(void);
#if USE_ICMP
-void CL_ErrorEvent(void);
+struct netadr_s;
+void CL_ErrorEvent(struct netadr_s *from);
#endif
void CL_Init(void);
void CL_Disconnect(error_type_t type);
diff --git a/src/common.c b/src/common.c
index dd64000..a530fce 100644
--- a/src/common.c
+++ b/src/common.c
@@ -37,7 +37,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "cmodel.h"
#include "q_field.h"
#include "prompt.h"
-#include "io_sleep.h"
#include "fpu.h"
#include <setjmp.h>
@@ -2203,7 +2202,7 @@ void Qcommon_Frame(void)
// sleep on network sockets when running a dedicated server
// still do a select(), but don't sleep when running a client!
- IO_Sleep(remaining);
+ NET_Sleep(remaining);
// calculate time spent running last frame and sleeping
oldtime = com_eventTime;
@@ -2255,6 +2254,8 @@ void Qcommon_Frame(void)
Sys_RunConsole();
#endif
+ NET_UpdateStats();
+
remaining = SV_Frame(msec);
#if USE_CLIENT
diff --git a/src/in_evdev.c b/src/in_evdev.c
index 8013f1b..cfdc936 100644
--- a/src/in_evdev.c
+++ b/src/in_evdev.c
@@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "key_public.h"
#include "in_public.h"
#include "cl_public.h"
-#include "io_sleep.h"
#include "q_list.h"
#include <sys/types.h>
@@ -48,7 +47,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
typedef struct {
list_t entry;
int fd;
- ioentry_t *io;
} evdev_t;
static struct {
@@ -63,7 +61,6 @@ static struct {
static void evdev_remove(evdev_t *dev)
{
- IO_Remove(dev->fd);
close(dev->fd);
List_Remove(&dev->entry);
Z_Free(dev);
@@ -76,12 +73,6 @@ static void evdev_read(evdev_t *dev)
size_t i, count;
unsigned button, time;
-#if 0
- if (!dev->io->canread) {
- return;
- }
-#endif
-
bytes = read(dev->fd, ev, EVENT_SIZE * MAX_EVENTS);
if (bytes == -1) {
if (errno == EAGAIN || errno == EINTR) {
@@ -206,7 +197,6 @@ static evdev_t *evdev_add(const char *path)
dev = Z_Malloc(sizeof(*dev));
dev->fd = fd;
- dev->io = IO_Add(fd);
List_Append(&evdev.devices, &dev->entry);
return dev;
@@ -328,12 +318,10 @@ static void GrabMouse(grab_t grab)
FOR_EACH_EVDEV(dev) {
if (!grab) {
- dev->io->wantread = qfalse;
continue;
}
// pump pending events
- dev->io->wantread = qtrue;
while (read(dev->fd, &ev, EVENT_SIZE) == EVENT_SIZE)
;
}
diff --git a/src/in_lirc.c b/src/in_lirc.c
index 287d4d2..bc46c53 100644
--- a/src/in_lirc.c
+++ b/src/in_lirc.c
@@ -23,7 +23,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "in_public.h"
#include "cl_public.h"
#include "sys_public.h"
-#include "io_sleep.h"
#include "in_lirc.h"
#include <sys/types.h>
@@ -88,7 +87,7 @@ void Lirc_Shutdown(void)
return;
}
lirc_freeconfig(lirc.config);
- IO_Remove(lirc.fd);
+ NET_RemoveFd(lirc.fd);
lirc_deinit();
memset(&lirc, 0, sizeof(lirc));
}
@@ -101,6 +100,8 @@ static void lirc_param_changed(cvar_t *self)
qboolean Lirc_Init(void)
{
+ int ret;
+
lirc_enable = Cvar_Get("lirc_enable", "0", 0);
lirc_enable->changed = lirc_param_changed;
lirc_config = Cvar_Get("lirc_config", "", CVAR_NOSET);
@@ -125,8 +126,12 @@ qboolean Lirc_Init(void)
return qfalse;
}
- fcntl(lirc.fd, F_SETFL, fcntl(lirc.fd, F_GETFL, 0) | FNDELAY);
- lirc.io = IO_Add(lirc.fd);
+ // change it to non-blocking
+ ret = fcntl(lirc.fd, F_GETFL, 0);
+ if (!(ret & O_NONBLOCK))
+ fcntl(lirc.fd, F_SETFL, ret | O_NONBLOCK);
+
+ lirc.io = NET_AddFd(lirc.fd);
lirc.io->wantread = qtrue;
Com_Printf("LIRC interface initialized.\n");
diff --git a/src/io_sleep.c b/src/io_sleep.c
deleted file mode 100644
index 3116e44..0000000
--- a/src/io_sleep.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
-Copyright (C) 2009 Andrey Nazarov
-
-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.
-
-*/
-
-#include "common.h"
-#include "sys_public.h"
-#include "io_sleep.h"
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <winsock2.h>
-#else
-#include <sys/select.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-static ioentry_t entries[FD_SETSIZE];
-static int numfds;
-
-ioentry_t *IO_Add(int fd)
-{
- ioentry_t *e;
-#ifdef _WIN32
- int i;
-
- for (i = 0, e = entries; i < numfds; i++, e++) {
- if (!e->inuse) {
- break;
- }
- }
-
- if (i == numfds) {
- if (++numfds > FD_SETSIZE) {
- Com_Error(ERR_FATAL, "%s: no more space for fd: %d", __func__, fd);
- }
- }
-
- e->fd = fd;
-#else
-
-#define CHECK_FD \
- if( fd < 0 || fd >= FD_SETSIZE ) { \
- Com_Error( ERR_FATAL, "%s: fd out of range: %d", __func__, fd ); \
- }
-
- CHECK_FD
-
- if (fd >= numfds) {
- numfds = fd + 1;
- }
-
- e = &entries[fd];
-#endif
- e->inuse = qtrue;
- return e;
-}
-
-void IO_Remove(int fd)
-{
- ioentry_t *e;
- int i;
-
- e = IO_Get(fd);
- memset(e, 0, sizeof(*e));
-
- for (i = numfds - 1; i >= 0; i--) {
- e = &entries[i];
- if (e->inuse) {
- break;
- }
- }
-
- numfds = i + 1;
-}
-
-ioentry_t *IO_Get(int fd)
-{
- ioentry_t *e;
-#ifdef _WIN32
- int i;
-
- for (i = 0, e = entries; i < numfds; i++, e++) {
- if (!e->inuse) {
- continue;
- }
- if (e->fd == fd) {
- return e;
- }
- }
-
- Com_Error(ERR_FATAL, "%s: fd not found: %d", __func__, fd);
-#else
- CHECK_FD
-
- e = &entries[fd];
- return e;
-#endif
-}
-
-//void IO_Mask( int fd ) {
-//}
-
-/*
-====================
-IO_Sleep
-
-Sleeps msec or until some file descriptor is ready
-====================
-*/
-int IO_Sleep(int msec)
-{
- struct timeval timeout;
- fd_set rfd, wfd;
-#ifdef _WIN32
- fd_set efd;
-#endif
- ioentry_t *e;
- int i, ret;
-
- if (!numfds) {
- // don't bother with select()
- Sys_Sleep(msec);
- return 0;
- }
-
- FD_ZERO(&rfd);
- FD_ZERO(&wfd);
-#ifdef _WIN32
- FD_ZERO(&efd);
-#endif
-
-#ifdef _WIN32
-#define FD e->fd
-#else
-#define FD i
-#endif
-
- for (i = 0, e = entries; i < numfds; i++, e++) {
- if (!e->inuse) {
- continue;
- }
- e->canread = qfalse;
- if (e->wantread) {
- FD_SET(FD, &rfd);
- }
- e->canwrite = qfalse;
- if (e->wantwrite) {
- FD_SET(FD, &wfd);
- }
-#ifdef _WIN32
- e->canexcept = qfalse;
- if (e->wantexcept) {
- FD_SET(FD, &efd);
- }
-#endif
- }
-
- timeout.tv_sec = msec / 1000;
- timeout.tv_usec = (msec % 1000) * 1000;
-
- ret = select(numfds, &rfd, &wfd,
-#ifdef _WIN32
- & efd,
-#else
- NULL,
-#endif
- & timeout);
- if (ret == -1) {
-#ifdef _WIN32
- // TODO: report WSA error
-#else
- if (errno != EINTR) {
- Com_EPrintf("%s: %s\n", __func__, strerror(errno));
- }
-#endif
- return ret;
- }
-
- if (!ret) {
- return ret;
- }
-
- for (i = 0; i < numfds; i++) {
- e = &entries[i];
- if (!e->inuse) {
- continue;
- }
- if (e->wantread && FD_ISSET(FD, &rfd)) {
- e->canread = qtrue;
- }
- if (e->wantwrite && FD_ISSET(FD, &wfd)) {
- e->canwrite = qtrue;
- }
-#ifdef _WIN32
- if (e->wantexcept && FD_ISSET(FD, &efd)) {
- e->canexcept = qtrue;
- }
-#endif
- }
-
- return ret;
-}
-
-#if USE_AC_SERVER
-
-/*
-====================
-IO_Sleep
-
-Sleeps msec or until some file descriptor from a given subset is ready
-====================
-*/
-int IO_Sleepv(int msec, ...)
-{
- va_list argptr;
- struct timeval timeout;
- fd_set rfd, wfd;
-#ifdef _WIN32
- fd_set efd;
-#endif
- ioentry_t *e;
- int i, ret;
-
- if (!numfds) {
- // don't bother with select()
- Sys_Sleep(msec);
- return 0;
- }
-
- FD_ZERO(&rfd);
- FD_ZERO(&wfd);
-#ifdef _WIN32
- FD_ZERO(&efd);
-#endif
-
- va_start(argptr, msec);
- while (1) {
- i = va_arg(argptr, int);
- if (i == -1) {
- break;
- }
- e = &entries[i];
- if (!e->inuse) {
- continue;
- }
- e->canread = qfalse;
- if (e->wantread) {
- FD_SET(FD, &rfd);
- }
- e->canwrite = qfalse;
- if (e->wantwrite) {
- FD_SET(FD, &wfd);
- }
-#ifdef _WIN32
- e->canexcept = qfalse;
- if (e->wantexcept) {
- FD_SET(FD, &efd);
- }
-#endif
- }
- va_end(argptr);
-
- timeout.tv_sec = msec / 1000;
- timeout.tv_usec = (msec % 1000) * 1000;
-
- ret = select(numfds, &rfd, &wfd,
-#ifdef _WIN32
- & efd,
-#else
- NULL,
-#endif
- & timeout);
- if (ret == -1) {
-#ifdef _WIN32
- // TODO: report WSA error
-#else
- if (errno != EINTR) {
- Com_EPrintf("%s: %s\n", __func__, strerror(errno));
- }
-#endif
- return ret;
- }
-
- if (!ret) {
- return ret;
- }
-
- va_start(argptr, msec);
- while (1) {
- i = va_arg(argptr, int);
- if (i == -1) {
- break;
- }
- e = &entries[i];
- if (!e->inuse) {
- continue;
- }
- if (e->wantread && FD_ISSET(FD, &rfd)) {
- e->canread = qtrue;
- }
- if (e->wantwrite && FD_ISSET(FD, &wfd)) {
- e->canwrite = qtrue;
- }
-#ifdef _WIN32
- if (e->wantexcept && FD_ISSET(FD, &efd)) {
- e->canexcept = qtrue;
- }
-#endif
- }
- va_end(argptr);
-
- return ret;
-}
-
-#endif // USE_AC_SERVER
-
diff --git a/src/io_sleep.h b/src/io_sleep.h
deleted file mode 100644
index fa80418..0000000
--- a/src/io_sleep.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-Copyright (C) 2009 Andrey Nazarov
-
-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.
-
-*/
-
-typedef struct {
-#ifdef _WIN32
- int fd;
-#endif
- qboolean inuse: 1;
- qboolean canread: 1;
- qboolean canwrite: 1;
-#ifdef _WIN32
- qboolean canexcept: 1;
-#endif
- qboolean wantread: 1;
- qboolean wantwrite: 1;
-#ifdef _WIN32
- qboolean wantexcept: 1;
-#endif
-} ioentry_t;
-
-ioentry_t *IO_Add(int fd);
-void IO_Remove(int fd);
-ioentry_t *IO_Get(int fd);
-int IO_Sleep(int msec);
-#if USE_AC_SERVER
-int IO_Sleepv(int msec, ...);
-#endif
-
diff --git a/src/mvd_client.c b/src/mvd_client.c
index 22c9da7..3c098d9 100644
--- a/src/mvd_client.c
+++ b/src/mvd_client.c
@@ -1579,7 +1579,7 @@ static void gtv_destroy(gtv_t *gtv)
}
// make sure network connection is closed
- NET_Close(&gtv->stream);
+ NET_CloseStream(&gtv->stream);
// unlink from the list of connections
List_Remove(&gtv->entry);
@@ -1624,7 +1624,7 @@ static void gtv_drop(gtv_t *gtv)
Com_FormatTimeLong(buffer, sizeof(buffer), sec);
Com_Printf("[%s] -=- Reconnecting in %s.\n", gtv->name, buffer);
- NET_Close(&gtv->stream);
+ NET_CloseStream(&gtv->stream);
#if USE_ZLIB
inflateReset(&gtv->z_str);
FIFO_Clear(&gtv->z_buf);
diff --git a/src/net_chan.c b/src/net_chan.c
index f4acd89..88fa0a8 100644
--- a/src/net_chan.c
+++ b/src/net_chan.c
@@ -158,7 +158,7 @@ void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address,
}
// send the datagram
- NET_SendPacket(sock, address, len + 4, &packet);
+ NET_SendPacket(sock, &packet, len + 4, address);
}
// ============================================================================
@@ -261,8 +261,8 @@ static size_t NetchanOld_Transmit(netchan_t *netchan, size_t length, const void
// send the datagram
for (i = 0; i < numpackets; i++) {
- NET_SendPacket(netchan->sock, &netchan->remote_address,
- send.cursize, send.data);
+ NET_SendPacket(netchan->sock, send.data, send.cursize,
+ &netchan->remote_address);
}
netchan->outgoing_sequence++;
@@ -506,8 +506,8 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *netchan)
}
// send the datagram
- NET_SendPacket(netchan->sock, &netchan->remote_address,
- send.cursize, send.data);
+ NET_SendPacket(netchan->sock, send.data, send.cursize,
+ &netchan->remote_address);
return send.cursize;
}
@@ -610,8 +610,8 @@ static size_t NetchanNew_Transmit(netchan_t *netchan, size_t length, const void
// send the datagram
for (i = 0; i < numpackets; i++) {
- NET_SendPacket(netchan->sock, &netchan->remote_address,
- send.cursize, send.data);
+ NET_SendPacket(netchan->sock, send.data, send.cursize,
+ &netchan->remote_address);
}
netchan->outgoing_sequence++;
diff --git a/src/net_chan.h b/src/net_chan.h
index ec56838..e7cf612 100644
--- a/src/net_chan.h
+++ b/src/net_chan.h
@@ -72,8 +72,8 @@ netchan_t *Netchan_Setup(netsrc_t sock, netchan_type_t type,
const netadr_t *adr, int qport, size_t maxpacketlen, int protocol);
void Netchan_Close(netchan_t *netchan);
-#define OOB_PRINT(sock, addr, string) \
- NET_SendPacket(sock, addr, sizeof("\xff\xff\xff\xff" string) - 1, "\xff\xff\xff\xff" string)
+#define OOB_PRINT(sock, addr, data) \
+ NET_SendPacket(sock, CONST_STR_LEN("\xff\xff\xff\xff" data), addr)
//============================================================================
diff --git a/src/net_common.c b/src/net_common.c
index 84bce5a..5b86120 100644
--- a/src/net_common.c
+++ b/src/net_common.c
@@ -34,30 +34,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sys_public.h"
#include "sv_public.h"
#include "cl_public.h"
-#include "io_sleep.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
-#define socklen_t int
-#define IOCTLSOCKET_PARAM u_long
-#define SETSOCKOPT_PARAM BOOL
-#ifdef _WIN32_WCE
-#define NET_GET_ERROR() (net_error = GetLastError())
-#else
-#define NET_GET_ERROR() (net_error = WSAGetLastError())
-#define NET_WOULD_BLOCK() (NET_GET_ERROR() == WSAEWOULDBLOCK)
-#endif
#else // _WIN32
#include <unistd.h>
+#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/ioctl.h>
-#include <sys/uio.h>
#include <arpa/inet.h>
#ifdef __linux__
#include <linux/types.h>
@@ -65,19 +54,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <linux/errqueue.h>
#endif
#endif // __linux__
-#define SOCKET int
-#define INVALID_SOCKET -1
-#define closesocket close
-#define ioctlsocket ioctl
-#define IOCTLSOCKET_PARAM int
-#define SETSOCKOPT_PARAM int
-#define NET_GET_ERROR() (net_error = errno)
-#define NET_WOULD_BLOCK() (NET_GET_ERROR() == EWOULDBLOCK)
#endif // !_WIN32
+// prevents infinite retry loops caused by broken TCP/IP stacks
+#define MAX_ERROR_RETRIES 64
+
#if USE_CLIENT
-#define MAX_LOOPBACK 4
+#define MAX_LOOPBACK 4
typedef struct {
byte data[MAX_PACKETLEN];
@@ -85,14 +69,14 @@ typedef struct {
} loopmsg_t;
typedef struct {
- loopmsg_t msgs[MAX_LOOPBACK];
- unsigned get;
- unsigned send;
+ loopmsg_t msgs[MAX_LOOPBACK];
+ unsigned long get;
+ unsigned long send;
} loopback_t;
static loopback_t loopbacks[NS_COUNT];
-#endif
+#endif // USE_CLIENT
cvar_t *net_ip;
cvar_t *net_port;
@@ -121,13 +105,16 @@ static cvar_t *net_ignore_icmp;
static netflag_t net_active;
static int net_error;
-static const char socketNames[NS_COUNT][8] = { "Client", "Server" };
-static SOCKET udp_sockets[NS_COUNT] = { INVALID_SOCKET, INVALID_SOCKET };
-static SOCKET tcp_socket = INVALID_SOCKET;
+static qsocket_t udp_sockets[NS_COUNT] = { -1, -1 };
+static qsocket_t tcp_socket = -1;
+
#ifdef _DEBUG
static qhandle_t net_logFile;
#endif
+static ioentry_t io_entries[FD_SETSIZE];
+static int io_numfds;
+
// current rate measurement
static unsigned net_rate_time;
static size_t net_rate_rcvd;
@@ -148,11 +135,6 @@ static uint64_t net_packets_sent;
//=============================================================================
-/*
-===================
-NET_NetadrToSockadr
-===================
-*/
static void NET_NetadrToSockadr(const netadr_t *a, struct sockaddr_in *s)
{
memset(s, 0, sizeof(*s));
@@ -174,11 +156,6 @@ static void NET_NetadrToSockadr(const netadr_t *a, struct sockaddr_in *s)
}
}
-/*
-===================
-NET_SockadrToNetadr
-===================
-*/
static void NET_SockadrToNetadr(const struct sockaddr_in *s, netadr_t *a)
{
memset(a, 0, sizeof(*a));
@@ -188,36 +165,17 @@ static void NET_SockadrToNetadr(const struct sockaddr_in *s, netadr_t *a)
a->port = s->sin_port;
}
-/*
-=============
-NET_StringToSockaddr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
static qboolean NET_StringToSockaddr(const char *s, struct sockaddr_in *sadr)
{
+ uint32_t addr;
struct hostent *h;
- char copy[MAX_QPATH], *p;
+ const char *p;
int dots;
memset(sadr, 0, sizeof(*sadr));
-
sadr->sin_family = AF_INET;
- sadr->sin_port = 0;
- Q_strlcpy(copy, s, sizeof(copy));
- // strip off a trailing :port if present
- p = strchr(copy, ':');
- if (p) {
- *p = 0;
- sadr->sin_port = htons((u_short)atoi(p + 1));
- }
- for (p = copy, dots = 0; *p; p++) {
+ for (p = s, dots = 0; *p; p++) {
if (*p == '.') {
dots++;
} else if (!Q_isdigit(*p)) {
@@ -225,14 +183,11 @@ static qboolean NET_StringToSockaddr(const char *s, struct sockaddr_in *sadr)
}
}
if (*p == 0 && dots <= 3) {
- uint32_t addr = inet_addr(copy);
-
- if (addr == INADDR_NONE) {
+ if ((addr = inet_addr(s)) == INADDR_NONE)
return qfalse;
- }
sadr->sin_addr.s_addr = addr;
} else {
- if (!(h = gethostbyname(copy)))
+ if (!(h = gethostbyname(s)))
return qfalse;
sadr->sin_addr.s_addr = *(uint32_t *)h->h_addr_list[0];
}
@@ -240,6 +195,23 @@ static qboolean NET_StringToSockaddr(const char *s, struct sockaddr_in *sadr)
return qtrue;
}
+static qboolean NET_StringToSockaddr2(const char *s, int port, struct sockaddr_in *sadr)
+{
+ if (*s) {
+ if (!NET_StringToSockaddr(s, sadr))
+ return qfalse;
+ } else {
+ // empty string binds to all interfaces
+ memset(sadr, 0, sizeof(*sadr));
+ sadr->sin_family = AF_INET;
+ sadr->sin_addr.s_addr = INADDR_ANY;
+ }
+
+ if (port != PORT_ANY)
+ sadr->sin_port = htons((u_short)port);
+
+ return qtrue;
+}
/*
===================
@@ -249,7 +221,6 @@ NET_AdrToString
char *NET_AdrToString(const netadr_t *a)
{
static char s[MAX_QPATH];
- const uint8_t *ip;
switch (a->type) {
case NA_LOOPBACK:
@@ -257,9 +228,10 @@ char *NET_AdrToString(const netadr_t *a)
return s;
case NA_IP:
case NA_BROADCAST:
- ip = a->ip.u8;
Q_snprintf(s, sizeof(s), "%u.%u.%u.%u:%u",
- ip[0], ip[1], ip[2], ip[3], ntohs(a->port));
+ a->ip.u8[0], a->ip.u8[1],
+ a->ip.u8[2], a->ip.u8[3],
+ BigShort(a->port));
return s;
default:
Com_Error(ERR_FATAL, "%s: bad address type", __func__);
@@ -283,16 +255,27 @@ idnewt:28000
qboolean NET_StringToAdr(const char *s, netadr_t *a, int port)
{
struct sockaddr_in sadr;
+ char copy[MAX_STRING_CHARS], *p;
+ size_t len;
- if (!NET_StringToSockaddr(s, &sadr)) {
+ len = Q_strlcpy(copy, s, sizeof(copy));
+ if (len >= sizeof(copy))
+ return qfalse;
+
+ // strip off a trailing :port if present
+ p = strchr(copy, ':');
+ if (p)
+ *p = 0;
+
+ if (!NET_StringToSockaddr(copy, &sadr))
return qfalse;
- }
NET_SockadrToNetadr(&sadr, a);
- if (!a->port) {
+ if (p)
+ a->port = BigShort(atoi(p + 1));
+ if (!a->port)
a->port = BigShort(port);
- }
return qtrue;
}
@@ -370,7 +353,8 @@ static void NET_LogPacket(const netadr_t *address, const char *prefix,
return;
}
- FS_FPrintf(net_logFile, "%s : %s\n", prefix, NET_AdrToString(address));
+ FS_FPrintf(net_logFile, "%u : %s : %s : %"PRIz" bytes\n",
+ com_localTime, prefix, NET_AdrToString(address), length);
numRows = (length + 15) / 16;
for (i = 0; i < numRows; i++) {
@@ -386,7 +370,7 @@ static void NET_LogPacket(const netadr_t *address, const char *prefix,
for (j = 0; j < 16; j++) {
if (i * 16 + j < length) {
c = data[i * 16 + j];
- FS_FPrintf(net_logFile, "%c", (c < 32 || c > 127) ? '.' : c);
+ FS_FPrintf(net_logFile, "%c", Q_isprint(c) ? c : '.');
} else {
FS_FPrintf(net_logFile, " ");
}
@@ -399,9 +383,11 @@ static void NET_LogPacket(const netadr_t *address, const char *prefix,
#endif
+//=============================================================================
+
#define RATE_SECS 3
-static void NET_UpdateStats(void)
+void NET_UpdateStats(void)
{
unsigned diff;
@@ -420,6 +406,56 @@ static void NET_UpdateStats(void)
net_rate_rcvd = 0;
}
+/*
+====================
+NET_Stats_f
+====================
+*/
+static void NET_Stats_f(void)
+{
+ time_t diff, now = time(NULL);
+ char buffer[MAX_QPATH];
+
+ if (com_startTime > now) {
+ com_startTime = now;
+ }
+ diff = now - com_startTime;
+ if (diff < 1) {
+ diff = 1;
+ }
+
+ Com_FormatTime(buffer, sizeof(buffer), diff);
+ Com_Printf("Network uptime: %s\n", buffer);
+ Com_Printf("Bytes sent: %"PRIu64" (%"PRIu64" bytes/sec)\n",
+ net_bytes_sent, net_bytes_sent / diff);
+ Com_Printf("Bytes rcvd: %"PRIu64" (%"PRIu64" bytes/sec)\n",
+ net_bytes_rcvd, net_bytes_rcvd / diff);
+ Com_Printf("Packets sent: %"PRIu64" (%"PRIu64" packets/sec)\n",
+ net_packets_sent, net_packets_sent / diff);
+ Com_Printf("Packets rcvd: %"PRIu64" (%"PRIu64" packets/sec)\n",
+ net_packets_rcvd, net_packets_rcvd / diff);
+#if USE_ICMP
+ Com_Printf("Total errors: %"PRIu64"/%"PRIu64"/%"PRIu64" (send/recv/icmp)\n",
+ net_send_errors, net_recv_errors, net_icmp_errors);
+#else
+ Com_Printf("Total errors: %"PRIu64"/%"PRIu64" (send/recv)\n",
+ net_send_errors, net_recv_errors);
+#endif
+ Com_Printf("Current upload rate: %"PRIz" bytes/sec\n", net_rate_up);
+ Com_Printf("Current download rate: %"PRIz" bytes/sec\n", net_rate_dn);
+}
+
+static size_t NET_UpRate_m(char *buffer, size_t size)
+{
+ return Q_scnprintf(buffer, size, "%"PRIz, net_rate_up);
+}
+
+static size_t NET_DnRate_m(char *buffer, size_t size)
+{
+ return Q_scnprintf(buffer, size, "%"PRIz, net_rate_dn);
+}
+
+//=============================================================================
#if USE_CLIENT
@@ -433,8 +469,6 @@ qboolean NET_GetLoopPacket(netsrc_t sock)
loopback_t *loop;
loopmsg_t *loopmsg;
- NET_UpdateStats();
-
loop = &loopbacks[sock];
if (loop->send - loop->get > MAX_LOOPBACK - 1) {
@@ -451,7 +485,7 @@ qboolean NET_GetLoopPacket(netsrc_t sock)
memcpy(msg_read_buffer, loopmsg->data, loopmsg->datalen);
#ifdef _DEBUG
- if (net_log_enable->integer) {
+ if (net_log_enable->integer > 1) {
NET_LogPacket(&net_from, "LP recv", loopmsg->data, loopmsg->datalen);
}
#endif
@@ -465,30 +499,62 @@ qboolean NET_GetLoopPacket(netsrc_t sock)
return qtrue;
}
+static qboolean NET_SendLoopPacket(netsrc_t sock, const void *data,
+ size_t len, const netadr_t *to)
+{
+ loopback_t *loop;
+ loopmsg_t *msg;
+
+ if (net_dropsim->integer > 0 && (rand() % 100) < net_dropsim->integer) {
+ return qfalse;
+ }
+
+ loop = &loopbacks[sock ^ 1];
+
+ msg = &loop->msgs[loop->send & (MAX_LOOPBACK - 1)];
+ loop->send++;
+
+ memcpy(msg->data, data, len);
+ msg->datalen = len;
+
+#ifdef _DEBUG
+ if (net_log_enable->integer > 1) {
+ NET_LogPacket(to, "LP send", data, len);
+ }
#endif
+ if (sock == NS_CLIENT) {
+ net_rate_sent += len;
+ }
+
+ return qtrue;
+}
+
+#endif // USE_CLIENT
+
+//=============================================================================
#if USE_ICMP
-// prevents infinite retry loops caused by broken TCP/IP stacks
-#define MAX_ERROR_RETRIES 64
+static const char *os_error_string(int err);
-static void icmp_error_event(netsrc_t sock, int info)
+static void NET_ErrorEvent(netsrc_t sock, netadr_t *from,
+ int ee_errno, int ee_info)
{
if (net_ignore_icmp->integer > 0) {
return;
}
Com_DPrintf("%s: %s from %s\n", __func__,
- NET_ErrorString(), NET_AdrToString(&net_from));
+ os_error_string(ee_errno), NET_AdrToString(from));
net_icmp_errors++;
switch (sock) {
case NS_SERVER:
- SV_ErrorEvent(info);
+ SV_ErrorEvent(from, ee_errno, ee_info);
break;
#if USE_CLIENT
case NS_CLIENT:
- CL_ErrorEvent();
+ CL_ErrorEvent(from);
break;
#endif
default:
@@ -496,103 +562,207 @@ static void icmp_error_event(netsrc_t sock, int info)
}
}
-#ifdef __linux__
+#endif // USE_ICMP
-// Linux at least supports receiving ICMP errors on unconnected UDP sockets
-// via IP_RECVERR cruft below... What about BSD?
-//
-// Returns true if failed socket operation should be retried, extremely hacky :/
-static qboolean process_error_queue(netsrc_t sock, struct sockaddr_in *to)
+//=============================================================================
+
+// include our wrappers to hide platfrom-specific details
+#ifdef _WIN32
+#include "net_win.h"
+#else
+#include "net_unix.h"
+#endif
+
+/*
+=============
+NET_ErrorString
+=============
+*/
+const char *NET_ErrorString(void)
{
- byte buffer[1024];
- struct sockaddr_in from;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct sock_extended_err *ee;
- int info;
- int tries;
- qboolean found;
-
- tries = 0;
- found = qfalse;
-
-retry:
- memset(&from, 0, sizeof(from));
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = &from;
- msg.msg_namelen = sizeof(from);
- msg.msg_control = buffer;
- msg.msg_controllen = sizeof(buffer);
-
- if (recvmsg(udp_sockets[sock], &msg, MSG_ERRQUEUE) == -1) {
- if (NET_WOULD_BLOCK()) {
- // wouldblock is silent
- goto finish;
+ return os_error_string(net_error);
+}
+
+/*
+=============
+NET_AddFd
+
+Adds file descriptor to the list of monitored descriptors
+=============
+*/
+ioentry_t *NET_AddFd(qsocket_t fd)
+{
+ ioentry_t *e = os_add_io(fd);
+
+ e->inuse = qtrue;
+ return e;
+}
+
+/*
+=============
+NET_RemoveFd
+
+Removes file descriptor from the list of monitored descriptors
+=============
+*/
+void NET_RemoveFd(qsocket_t fd)
+{
+ ioentry_t *e = os_get_io(fd);
+ int i;
+
+ memset(e, 0, sizeof(*e));
+
+ for (i = io_numfds - 1; i >= 0; i--) {
+ e = &io_entries[i];
+ if (e->inuse) {
+ break;
}
- Com_EPrintf("%s: %s\n", __func__, NET_ErrorString());
- goto finish;
}
- if (!(msg.msg_flags & MSG_ERRQUEUE)) {
- Com_DPrintf("%s: no extended error received\n", __func__);
- goto finish;
+ io_numfds = i + 1;
+}
+
+/*
+=============
+NET_Sleep
+
+Sleeps msec or until some file descriptor is ready. Implementation is not
+terribly efficient, but that's fine for a small number of descriptors we
+typically have.
+=============
+*/
+int NET_Sleep(int msec)
+{
+ struct timeval tv;
+ fd_set rfds, wfds, efds;
+ ioentry_t *e;
+ qsocket_t fd;
+ int i, ret;
+
+ if (!io_numfds) {
+ // don't bother with select()
+ Sys_Sleep(msec);
+ return 0;
}
- // find an ICMP error message
- for (cmsg = CMSG_FIRSTHDR(&msg);
- cmsg != NULL;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level != IPPROTO_IP) {
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+
+ for (i = 0, e = io_entries; i < io_numfds; i++, e++) {
+ if (!e->inuse) {
continue;
}
- if (cmsg->cmsg_type != IP_RECVERR) {
+ fd = os_get_fd(e);
+ e->canread = qfalse;
+ e->canwrite = qfalse;
+ e->canexcept = qfalse;
+ if (e->wantread) FD_SET(fd, &rfds);
+ if (e->wantwrite) FD_SET(fd, &wfds);
+ if (e->wantexcept) FD_SET(fd, &efds);
+ }
+
+ tv.tv_sec = msec / 1000;
+ tv.tv_usec = (msec % 1000) * 1000;
+
+ ret = os_select(io_numfds, &rfds, &wfds, &efds, &tv);
+ if (ret == -1) {
+ Com_EPrintf("%s: %s\n", __func__, NET_ErrorString());
+ return ret;
+ }
+
+ if (ret == 0)
+ return ret;
+
+ for (i = 0; i < io_numfds; i++) {
+ e = &io_entries[i];
+ if (!e->inuse) {
continue;
}
- ee = (struct sock_extended_err *)CMSG_DATA(cmsg);
- if (ee->ee_origin == SO_EE_ORIGIN_ICMP) {
- break;
- }
+ fd = os_get_fd(e);
+ if (FD_ISSET(fd, &rfds)) e->canread = qtrue;
+ if (FD_ISSET(fd, &wfds)) e->canwrite = qtrue;
+ if (FD_ISSET(fd, &efds)) e->canexcept = qtrue;
}
- if (!cmsg) {
- Com_DPrintf("%s: no ICMP error found\n", __func__);
- goto finish;
- }
+ return ret;
+}
+
+#if USE_AC_SERVER
+
+/*
+=============
+NET_Sleepv
- NET_SockadrToNetadr(&from, &net_from);
+Sleeps msec or until some file descriptor from a given subset is ready
+=============
+*/
+int NET_Sleepv(int msec, ...)
+{
+ va_list argptr;
+ struct timeval tv;
+ fd_set rfds, wfds, efds;
+ ioentry_t *e;
+ qsocket_t fd;
+ int ret;
- // check if this error was caused by a packet sent to the given address
- // if so, do not retry send operation to prevent infinite loop
- if (to != NULL && from.sin_addr.s_addr == to->sin_addr.s_addr &&
- (!from.sin_port || from.sin_port == to->sin_port)) {
- Com_DPrintf("%s: found offending address %s:%d\n",
- __func__, inet_ntoa(from.sin_addr), BigShort(from.sin_port));
- found = qtrue;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+
+ va_start(argptr, msec);
+ while (1) {
+ fd = va_arg(argptr, qsocket_t);
+ if (fd == -1) {
+ break;
+ }
+ e = os_get_io(fd);
+ if (!e->inuse) {
+ continue;
+ }
+ e->canread = qfalse;
+ e->canwrite = qfalse;
+ e->canexcept = qfalse;
+ if (e->wantread) FD_SET(fd, &rfds);
+ if (e->wantwrite) FD_SET(fd, &wfds);
+ if (e->wantexcept) FD_SET(fd, &efds);
}
+ va_end(argptr);
- // handle ICMP errors
- net_error = ee->ee_errno;
- info = 0;
-#if USE_PMTUDISC
- // for EMSGSIZE ee_info should hold discovered MTU
- if (net_error == EMSGSIZE && ee->ee_info >= 576 && ee->ee_info < 4096) {
- info = ee->ee_info;
+ tv.tv_sec = msec / 1000;
+ tv.tv_usec = (msec % 1000) * 1000;
+
+ ret = os_select(io_numfds, &rfds, &wfds, &efds, &tv);
+ if (ret == -1) {
+ Com_EPrintf("%s: %s\n", __func__, NET_ErrorString());
+ return ret;
}
-#endif
- icmp_error_event(sock, info);
- if (++tries < MAX_ERROR_RETRIES) {
- goto retry;
+ if (ret == 0)
+ return ret;
+
+ va_start(argptr, msec);
+ while (1) {
+ fd = va_arg(argptr, qsocket_t);
+ if (fd == -1) {
+ break;
+ }
+ e = os_get_io(fd);
+ if (!e->inuse) {
+ continue;
+ }
+ if (FD_ISSET(fd, &rfds)) e->canread = qtrue;
+ if (FD_ISSET(fd, &wfds)) e->canwrite = qtrue;
+ if (FD_ISSET(fd, &efds)) e->canexcept = qtrue;
}
+ va_end(argptr);
-finish:
- return !!tries && !found;
+ return ret;
}
-#endif // __linux__
+#endif // USE_AC_SERVER
-#endif // USE_ICMP
+//=============================================================================
/*
=============
@@ -604,112 +774,37 @@ net_from variable receives source address.
*/
qboolean NET_GetPacket(netsrc_t sock)
{
- struct sockaddr_in from;
- socklen_t fromlen;
- int ret;
-#if USE_ICMP
- int tries;
-#ifndef _WIN32
- int saved_error;
-#endif
-#endif
ioentry_t *e;
+ ssize_t ret;
- if (udp_sockets[sock] == INVALID_SOCKET) {
+ if (udp_sockets[sock] == -1)
return qfalse;
- }
-
- NET_UpdateStats();
-
- e = IO_Get(udp_sockets[sock]);
- if (!e->canread) {
- return qfalse;
- }
-#if USE_ICMP
- tries = 0;
-
-retry:
-#endif
- memset(&from, 0, sizeof(from));
-
- fromlen = sizeof(from);
- ret = recvfrom(udp_sockets[sock], (void *)msg_read_buffer,
- MAX_PACKETLEN, 0, (struct sockaddr *)&from, &fromlen);
-
- if (!ret) {
+ e = os_get_io(udp_sockets[sock]);
+ if (!e->canread)
return qfalse;
- }
-
- NET_SockadrToNetadr(&from, &net_from);
-
- if (ret == -1) {
- NET_GET_ERROR();
-#ifdef _WIN32
- switch (net_error) {
- case WSAEWOULDBLOCK:
- // wouldblock is silent
- e->canread = qfalse;
- break;
-#if USE_ICMP
- case WSAECONNRESET:
- case WSAENETRESET:
- // winsock has already provided us with
- // a valid address from ICMP error packet
- icmp_error_event(sock, 0);
- if (++tries < MAX_ERROR_RETRIES) {
- goto retry;
- }
- // intentional fallthrough
-#endif // USE_ICMP
- default:
- Com_DPrintf("%s: %s from %s\n", __func__,
- NET_ErrorString(), NET_AdrToString(&net_from));
- net_recv_errors++;
- break;
- }
-#else // _WIN32
- switch (net_error) {
- case EWOULDBLOCK:
- // wouldblock is silent
- e->canread = qfalse;
- break;
- default:
-#if USE_ICMP
- saved_error = net_error;
- // recvfrom() fails on Linux if there's an ICMP originated
- // pending error on socket. suck up error queue and retry...
- if (process_error_queue(sock, NULL)) {
- if (++tries < MAX_ERROR_RETRIES) {
- goto retry;
- }
- }
- net_error = saved_error;
-#endif
- Com_DPrintf("%s: %s from %s\n", __func__,
- NET_ErrorString(), NET_AdrToString(&net_from));
- net_recv_errors++;
- break;
- }
-#endif // !_WIN32
+ ret = os_udp_recv(sock, msg_read_buffer, MAX_PACKETLEN, &net_from);
+ if (ret == NET_AGAIN) {
+ e->canread = qfalse;
return qfalse;
}
- if (ret > MAX_PACKETLEN) {
- Com_EPrintf("%s: oversize packet from %s\n", __func__,
- NET_AdrToString(&net_from));
+ if (ret == NET_ERROR) {
+ Com_DPrintf("%s: %s from %s\n", __func__,
+ NET_ErrorString(), NET_AdrToString(&net_from));
+ net_recv_errors++;
return qfalse;
}
#ifdef _DEBUG
- if (net_log_enable->integer) {
+ if (net_log_enable->integer)
NET_LogPacket(&net_from, "UDP recv", msg_read_buffer, ret);
- }
#endif
SZ_Init(&msg_read, msg_read_buffer, sizeof(msg_read_buffer));
msg_read.cursize = ret;
+
net_rate_rcvd += ret;
net_bytes_rcvd += ret;
net_packets_rcvd++;
@@ -717,155 +812,54 @@ retry:
return qtrue;
}
-//=============================================================================
-
/*
=============
NET_SendPacket
=============
*/
-qboolean NET_SendPacket(netsrc_t sock, const netadr_t *to, size_t length, const void *data)
+qboolean NET_SendPacket(netsrc_t sock, const void *data,
+ size_t len, const netadr_t *to)
{
- struct sockaddr_in addr;
- int ret;
-#if USE_ICMP && (defined __linux__)
- int tries;
- int saved_error;
-#endif
+ ssize_t ret;
- if (!length) {
+ if (len == 0)
return qfalse;
- }
- if (length > MAX_PACKETLEN) {
+ if (len > MAX_PACKETLEN) {
Com_EPrintf("%s: oversize packet to %s\n", __func__,
NET_AdrToString(to));
return qfalse;
}
- switch (to->type) {
#if USE_CLIENT
- case NA_LOOPBACK: {
- loopback_t *loop;
- loopmsg_t *msg;
-
- if (net_dropsim->integer > 0 &&
- (rand() % 100) < net_dropsim->integer) {
- return NET_AGAIN;
- }
-
- loop = &loopbacks[sock ^ 1];
-
- msg = &loop->msgs[loop->send & (MAX_LOOPBACK - 1)];
- loop->send++;
-
- memcpy(msg->data, data, length);
- msg->datalen = length;
-
-#ifdef _DEBUG
- if (net_log_enable->integer) {
- NET_LogPacket(to, "LB send", data, length);
- }
-#endif
- if (sock == NS_CLIENT) {
- net_rate_sent += length;
- }
- }
- return qtrue;
+ if (to->type == NA_LOOPBACK)
+ return NET_SendLoopPacket(sock, data, len, to);
#endif
- case NA_IP:
- case NA_BROADCAST:
- break;
- default:
- Com_Error(ERR_FATAL, "%s: bad address type", __func__);
- break;
- }
- if (udp_sockets[sock] == INVALID_SOCKET) {
+ if (udp_sockets[sock] == -1)
return qfalse;
- }
-
- NET_NetadrToSockadr(to, &addr);
-#if USE_ICMP && (defined __linux__)
- tries = 0;
-
-retry:
-#endif
- ret = sendto(udp_sockets[sock], data, length, 0,
- (struct sockaddr *)&addr, sizeof(addr));
- if (ret == -1) {
- NET_GET_ERROR();
+ ret = os_udp_send(sock, data, len, to);
+ if (ret == NET_AGAIN)
+ return qfalse;
-#ifdef _WIN32
- switch (net_error) {
- case WSAEWOULDBLOCK:
- case WSAEINTR:
- // wouldblock is silent
- break;
- case WSAEADDRNOTAVAIL:
- // some PPP links do not allow broadcasts
- if (to->type == NA_BROADCAST) {
- break;
- }
- // intentional fallthrough
- default:
- Com_DPrintf("%s: %s to %s\n", __func__,
- NET_ErrorString(), NET_AdrToString(to));
- net_send_errors++;
- break;
- }
-#else // _WIN32
- switch (net_error) {
- case EWOULDBLOCK:
- // wouldblock is silent
- break;
- default:
-#if USE_ICMP
- saved_error = net_error;
- // sendto() fails on Linux if there's an ICMP originated
- // pending error on socket. suck up error queue and retry...
- //
- // this one is especially lame - how do I distingiush between
- // a failure caused by completely unrelated ICMP error sitting
- // in the queue and an error explicit to this sendto() call?
- //
- // on one hand, I don't want to drop packets to legitimate
- // clients because of this, and have to retry sendto() after
- // processing error queue, on another hand, infinite loop should be
- // avoided if this sendto() regenerates a message in error queue
- //
- // this mess is worked around by passing destination address
- // to process_error_queue() and checking if this address/port
- // pair is found in the queue. if it is found, or the queue
- // is empty, do not retry
- if (process_error_queue(sock, &addr)) {
- if (++tries < MAX_ERROR_RETRIES) {
- goto retry;
- }
- }
- net_error = saved_error;
-#endif
- Com_DPrintf("%s: %s to %s\n", __func__,
- NET_ErrorString(), NET_AdrToString(to));
- net_send_errors++;
- break;
- }
-#endif // !_WIN32
+ if (ret == NET_ERROR) {
+ Com_DPrintf("%s: %s to %s\n", __func__,
+ NET_ErrorString(), NET_AdrToString(to));
+ net_send_errors++;
return qfalse;
}
- if (ret != length) {
+ if (ret < len)
Com_WPrintf("%s: short send to %s\n", __func__,
NET_AdrToString(to));
- }
#ifdef _DEBUG
- if (net_log_enable->integer) {
+ if (net_log_enable->integer)
NET_LogPacket(to, "UDP send", data, ret);
- }
#endif
+
net_rate_sent += ret;
net_bytes_sent += ret;
net_packets_sent++;
@@ -873,116 +867,55 @@ retry:
return qtrue;
}
-
//=============================================================================
-const char *NET_ErrorString(void)
+static qsocket_t UDP_OpenSocket(const char *iface, int port)
{
-#ifdef _WIN32
- switch (net_error) {
- case S_OK:
- return "NO ERROR";
- default:
- return "UNKNOWN ERROR";
-#include "wsaerr.h"
- }
-#else
- return strerror(net_error);
-#endif
-}
-
-static qboolean get_bind_addr(const char *iface, int port, struct sockaddr_in *sadr)
-{
- if (*iface) {
- if (!NET_StringToSockaddr(iface, sadr)) {
- return qfalse;
- }
- } else {
- // empty string binds to all interfaces
- memset(sadr, 0, sizeof(*sadr));
- sadr->sin_family = AF_INET;
- sadr->sin_addr.s_addr = INADDR_ANY;
- }
- if (port != PORT_ANY) {
- sadr->sin_port = htons((u_short)port);
- }
-
- return qtrue;
-}
-
-static SOCKET create_socket(int type, int proto)
-{
- SOCKET ret = socket(PF_INET, type, proto);
-
- NET_GET_ERROR();
- return ret;
-}
-
-static int set_option(SOCKET s, int level, int optname, int value)
-{
- SETSOCKOPT_PARAM _value = value;
- int ret = setsockopt(s, level, optname, (char *)&_value, sizeof(_value));
-
- NET_GET_ERROR();
- return ret;
-}
-
-#define enable_option(s,level,optname) set_option(s,level,optname,1)
-
-static int make_nonblock(SOCKET s)
-{
- IOCTLSOCKET_PARAM _true = 1;
- int ret = ioctlsocket(s, FIONBIO, &_true);
-
- NET_GET_ERROR();
- return ret;
-}
-
-static int bind_socket(SOCKET s, struct sockaddr_in *sadr)
-{
- int ret = bind(s, (struct sockaddr *)sadr, sizeof(*sadr));
-
- NET_GET_ERROR();
- return ret;
-}
-
-static SOCKET UDP_OpenSocket(const char *iface, int port)
-{
- SOCKET s;
struct sockaddr_in sadr;
-#ifdef __linux__
- int pmtudisc;
-#endif
+ int s;
+
+ Com_DPrintf("Opening UDP socket: %s:%d\n", iface, port);
- Com_DPrintf("Opening UDP socket: %s:%i\n", iface, port);
+ // resolve iface addr
+ if (!NET_StringToSockaddr2(iface, port, &sadr)) {
+ Com_EPrintf("%s: %s:%d: bad interface address\n",
+ __func__, iface, port);
+ return -1;
+ }
- s = create_socket(SOCK_DGRAM, IPPROTO_UDP);
- if (s == INVALID_SOCKET) {
+ s = os_socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1) {
Com_EPrintf("%s: %s:%d: can't create socket: %s\n",
__func__, iface, port, NET_ErrorString());
- return INVALID_SOCKET;
+ return -1;
}
// make it non-blocking
- if (make_nonblock(s) == -1) {
+ if (os_make_nonblock(s, 1)) {
Com_EPrintf("%s: %s:%d: can't make socket non-blocking: %s\n",
__func__, iface, port, NET_ErrorString());
goto fail;
}
// make it broadcast capable
- if (enable_option(s, SOL_SOCKET, SO_BROADCAST) == -1) {
+ if (os_setsockopt(s, SOL_SOCKET, SO_BROADCAST, 1)) {
Com_WPrintf("%s: %s:%d: can't make socket broadcast capable: %s\n",
__func__, iface, port, NET_ErrorString());
}
#ifdef __linux__
- pmtudisc = IP_PMTUDISC_DONT;
+ // udp(7) says: "By default, Linux UDP does path MTU discovery". This means
+ // kernel will set "don't fragment" bit on outgoing packets. This is not
+ // what most Quake 2 server operators expect. Firewalled ICMP traffic may
+ // result in clients getting stuck on connect. Thus we enable IP
+ // fragmentation by default.
+
+ int disc = IP_PMTUDISC_DONT;
#if USE_ICMP
// enable ICMP error queue
if (net_ignore_icmp->integer <= 0) {
- if (enable_option(s, IPPROTO_IP, IP_RECVERR) == -1) {
+ if (os_setsockopt(s, IPPROTO_IP, IP_RECVERR, 1)) {
Com_WPrintf("%s: %s:%d: can't enable ICMP error queue: %s\n",
__func__, iface, port, NET_ErrorString());
Cvar_Set("net_ignore_icmp", "1");
@@ -991,33 +924,26 @@ static SOCKET UDP_OpenSocket(const char *iface, int port)
#if USE_PMTUDISC
// overload negative values to enable path MTU discovery
switch (net_ignore_icmp->integer) {
- case -1: pmtudisc = IP_PMTUDISC_WANT; break;
- case -2: pmtudisc = IP_PMTUDISC_DO; break;
+ case -1: disc = IP_PMTUDISC_WANT; break;
+ case -2: disc = IP_PMTUDISC_DO; break;
#ifdef IP_PMTUDISC_PROBE
- case -3: pmtudisc = IP_PMTUDISC_PROBE; break;
+ case -3: disc = IP_PMTUDISC_PROBE; break;
#endif
}
#endif // USE_PMTUDISC
}
#endif // USE_ICMP
- // disable or enable path MTU discovery
- if (set_option(s, IPPROTO_IP, IP_MTU_DISCOVER, pmtudisc) == -1) {
+ // set path MTU discovery option
+ if (os_setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, disc)) {
Com_WPrintf("%s: %s:%d: can't %sable path MTU discovery: %s\n",
- __func__, iface, port, pmtudisc == IP_PMTUDISC_DONT ? "dis" : "en",
+ __func__, iface, port,
+ disc == IP_PMTUDISC_DONT ? "dis" : "en",
NET_ErrorString());
}
-
#endif // __linux__
- // resolve iface sadr
- if (!get_bind_addr(iface, port, &sadr)) {
- Com_EPrintf("%s: %s:%d: bad interface address\n",
- __func__, iface, port);
- goto fail;
- }
-
- if (bind_socket(s, &sadr) == -1) {
+ if (os_bind(s, (struct sockaddr *)&sadr, sizeof(sadr))) {
Com_EPrintf("%s: %s:%d: can't bind socket: %s\n",
__func__, iface, port, NET_ErrorString());
goto fail;
@@ -1026,46 +952,47 @@ static SOCKET UDP_OpenSocket(const char *iface, int port)
return s;
fail:
- closesocket(s);
- return INVALID_SOCKET;
+ os_closesocket(s);
+ return -1;
}
-static SOCKET TCP_OpenSocket(const char *iface, int port, netsrc_t who)
+static qsocket_t TCP_OpenSocket(const char *iface, int port, netsrc_t who)
{
- SOCKET s;
struct sockaddr_in sadr;
+ int s;
- Com_DPrintf("Opening TCP socket: %s:%i\n", iface, port);
+ Com_DPrintf("Opening TCP socket: %s:%d\n", iface, port);
- s = create_socket(SOCK_STREAM, IPPROTO_TCP);
- if (s == INVALID_SOCKET) {
+ // resolve iface addr
+ if (!NET_StringToSockaddr2(iface, port, &sadr)) {
+ Com_EPrintf("%s: %s:%d: bad interface address\n",
+ __func__, iface, port);
+ return -1;
+ }
+
+ s = os_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (s == -1) {
Com_EPrintf("%s: %s:%d: can't create socket: %s\n",
__func__, iface, port, NET_ErrorString());
- return INVALID_SOCKET;
+ return -1;
}
// make it non-blocking
- if (make_nonblock(s) == -1) {
+ if (os_make_nonblock(s, 1)) {
Com_EPrintf("%s: %s:%d: can't make socket non-blocking: %s\n",
__func__, iface, port, NET_ErrorString());
goto fail;
}
- // give it a chance to reuse previous port
if (who == NS_SERVER) {
- if (enable_option(s, SOL_SOCKET, SO_REUSEADDR) == -1) {
+ // give it a chance to reuse previous port
+ if (os_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 1)) {
Com_WPrintf("%s: %s:%d: can't force socket to reuse address: %s\n",
__func__, iface, port, NET_ErrorString());
}
}
- if (!get_bind_addr(iface, port, &sadr)) {
- Com_EPrintf("%s: %s:%d: bad interface address\n",
- __func__, iface, port);
- goto fail;
- }
-
- if (bind_socket(s, &sadr) == -1) {
+ if (os_bind(s, (struct sockaddr *)&sadr, sizeof(sadr))) {
Com_EPrintf("%s: %s:%d: can't bind socket: %s\n",
__func__, iface, port, NET_ErrorString());
goto fail;
@@ -1074,21 +1001,21 @@ static SOCKET TCP_OpenSocket(const char *iface, int port, netsrc_t who)
return s;
fail:
- closesocket(s);
- return INVALID_SOCKET;
+ os_closesocket(s);
+ return -1;
}
static void NET_OpenServer(void)
{
static int saved_port;
ioentry_t *e;
- SOCKET s;
+ qsocket_t s;
s = UDP_OpenSocket(net_ip->string, net_port->integer);
- if (s != INVALID_SOCKET) {
+ if (s != -1) {
saved_port = net_port->integer;
udp_sockets[NS_SERVER] = s;
- e = IO_Add(s);
+ e = NET_AddFd(s);
e->wantread = qtrue;
return;
}
@@ -1114,77 +1041,140 @@ static void NET_OpenServer(void)
static void NET_OpenClient(void)
{
ioentry_t *e;
- SOCKET s;
- struct sockaddr_in sadr;
- socklen_t len;
+ qsocket_t s;
+ netadr_t adr;
s = UDP_OpenSocket(net_ip->string, net_clientport->integer);
- if (s == INVALID_SOCKET) {
+ if (s == -1) {
// now try with random port
- if (net_clientport->integer != PORT_ANY) {
+ if (net_clientport->integer != PORT_ANY)
s = UDP_OpenSocket(net_ip->string, PORT_ANY);
- }
- if (s == INVALID_SOCKET) {
+
+ if (s == -1) {
Com_WPrintf("Couldn't open client UDP port.\n");
return;
}
- len = sizeof(sadr);
- getsockname(s, (struct sockaddr *)&sadr, &len);
- Com_WPrintf("Client bound to UDP port %d.\n", ntohs(sadr.sin_port));
+
+ if (os_getsockname(s, &adr)) {
+ Com_EPrintf("Couldn't get client UDP socket name: %s\n", NET_ErrorString());
+ os_closesocket(s);
+ return;
+ }
+
+ Com_WPrintf("Client UDP socket bound to %s.\n", NET_AdrToString(&adr));
Cvar_SetByVar(net_clientport, va("%d", PORT_ANY), FROM_CODE);
}
udp_sockets[NS_CLIENT] = s;
- e = IO_Add(s);
+ e = NET_AddFd(s);
e->wantread = qtrue;
}
#endif
+/*
+====================
+NET_Config
+====================
+*/
+void NET_Config(netflag_t flag)
+{
+ netsrc_t sock;
+
+ if (flag == net_active) {
+ return;
+ }
+
+ if (flag == NET_NONE) {
+ // shut down any existing sockets
+ for (sock = 0; sock < NS_COUNT; sock++) {
+ if (udp_sockets[sock] != -1) {
+ NET_RemoveFd(udp_sockets[sock]);
+ os_closesocket(udp_sockets[sock]);
+ udp_sockets[sock] = -1;
+ }
+ }
+ net_active = NET_NONE;
+ return;
+ }
+
+#if USE_CLIENT
+ if ((flag & NET_CLIENT) && udp_sockets[NS_CLIENT] == -1) {
+ NET_OpenClient();
+ }
+#endif
+
+ if ((flag & NET_SERVER) && udp_sockets[NS_SERVER] == -1) {
+ NET_OpenServer();
+ }
+
+ net_active |= flag;
+}
+
+/*
+====================
+NET_GetAddress
+====================
+*/
+qboolean NET_GetAddress(netsrc_t sock, netadr_t *adr)
+{
+ if (udp_sockets[sock] == -1)
+ return qfalse;
+
+ if (os_getsockname(udp_sockets[sock], adr))
+ return qfalse;
+
+ return qtrue;
+}
+
//=============================================================================
-void NET_Close(netstream_t *s)
+void NET_CloseStream(netstream_t *s)
{
if (!s->state) {
return;
}
- IO_Remove(s->socket);
- closesocket(s->socket);
- s->socket = INVALID_SOCKET;
+ NET_RemoveFd(s->socket);
+ os_closesocket(s->socket);
+ s->socket = -1;
s->state = NS_DISCONNECTED;
}
neterr_t NET_Listen(qboolean arg)
{
- SOCKET s;
+ qsocket_t s;
ioentry_t *e;
+ neterr_t ret;
if (!arg) {
- if (tcp_socket != INVALID_SOCKET) {
- IO_Remove(tcp_socket);
- closesocket(tcp_socket);
- tcp_socket = INVALID_SOCKET;
+ if (tcp_socket != -1) {
+ NET_RemoveFd(tcp_socket);
+ os_closesocket(tcp_socket);
+ tcp_socket = -1;
}
return NET_OK;
}
- if (tcp_socket != INVALID_SOCKET) {
+ if (tcp_socket != -1) {
return NET_OK;
}
s = TCP_OpenSocket(net_tcp_ip->string,
net_tcp_port->integer, NS_SERVER);
- if (s == INVALID_SOCKET) {
+ if (s == -1) {
return NET_ERROR;
}
- if (listen(s, net_tcp_backlog->integer) == -1) {
- NET_GET_ERROR();
- closesocket(s);
- return NET_ERROR;
+
+ ret = os_listen(s, net_tcp_backlog->integer);
+ if (ret) {
+ os_closesocket(s);
+ return ret;
}
tcp_socket = s;
- e = IO_Add(s);
+
+ // initialize io entry
+ e = NET_AddFd(s);
e->wantread = qtrue;
return NET_OK;
@@ -1193,39 +1183,30 @@ neterr_t NET_Listen(qboolean arg)
// net_from variable receives source address
neterr_t NET_Accept(netstream_t *s)
{
- struct sockaddr_in from;
- socklen_t fromlen;
- SOCKET newsocket;
ioentry_t *e;
+ qsocket_t newsocket;
+ neterr_t ret;
- if (tcp_socket == INVALID_SOCKET) {
+ if (tcp_socket == -1) {
return NET_AGAIN;
}
- e = IO_Get(tcp_socket);
+ e = os_get_io(tcp_socket);
if (!e->canread) {
return NET_AGAIN;
}
- memset(&from, 0, sizeof(from));
- fromlen = sizeof(from);
- newsocket = accept(tcp_socket, (struct sockaddr *)&from, &fromlen);
-
- NET_SockadrToNetadr(&from, &net_from);
-
- if (newsocket == -1) {
- if (NET_WOULD_BLOCK()) {
- // wouldblock is silent
- e->canread = qfalse;
- return NET_AGAIN;
- }
- return NET_ERROR;
+ ret = os_accept(tcp_socket, &newsocket, &net_from);
+ if (ret) {
+ e->canread = qfalse;
+ return ret;
}
// make it non-blocking
- if (make_nonblock(newsocket) == -1) {
- closesocket(newsocket);
- return NET_ERROR;
+ ret = os_make_nonblock(newsocket, 1);
+ if (ret) {
+ os_closesocket(newsocket);
+ return ret;
}
// initialize stream
@@ -1235,7 +1216,7 @@ neterr_t NET_Accept(netstream_t *s)
s->state = NS_CONNECTED;
// initialize io entry
- e = IO_Add(newsocket);
+ e = NET_AddFd(newsocket);
//e->wantwrite = qtrue;
e->wantread = qtrue;
@@ -1244,31 +1225,21 @@ neterr_t NET_Accept(netstream_t *s)
neterr_t NET_Connect(const netadr_t *peer, netstream_t *s)
{
- SOCKET socket;
+ qsocket_t socket;
ioentry_t *e;
- struct sockaddr_in sadr;
- int ret;
+ neterr_t ret;
// always bind to `net_ip' for outgoing TCP connections
// to avoid problems with AC or MVD/GTV auth on a multi IP system
socket = TCP_OpenSocket(net_ip->string, PORT_ANY, NS_CLIENT);
- if (socket == INVALID_SOCKET) {
+ if (socket == -1) {
return NET_ERROR;
}
- NET_NetadrToSockadr(peer, &sadr);
-
- ret = connect(socket, (struct sockaddr *)&sadr, sizeof(sadr));
- if (ret == -1) {
-#ifdef _WIN32
- if (NET_GET_ERROR() != WSAEWOULDBLOCK) {
-#else
- if (NET_GET_ERROR() != EINPROGRESS) {
-#endif
- // wouldblock is silent
- closesocket(socket);
- return NET_ERROR;
- }
+ ret = os_connect(socket, peer);
+ if (ret) {
+ os_closesocket(socket);
+ return NET_ERROR;
}
// initialize stream
@@ -1278,7 +1249,7 @@ neterr_t NET_Connect(const netadr_t *peer, netstream_t *s)
s->socket = socket;
// initialize io entry
- e = IO_Add(socket);
+ e = NET_AddFd(socket);
e->wantwrite = qtrue;
#ifdef _WIN32
e->wantexcept = qtrue;
@@ -1289,15 +1260,15 @@ neterr_t NET_Connect(const netadr_t *peer, netstream_t *s)
neterr_t NET_RunConnect(netstream_t *s)
{
- socklen_t len;
- int ret, err;
ioentry_t *e;
+ neterr_t ret;
+ int err;
if (s->state != NS_CONNECTING) {
return NET_AGAIN;
}
- e = IO_Get(s->socket);
+ e = os_get_io(s->socket);
if (!e->canwrite
#ifdef _WIN32
&& !e->canexcept
@@ -1306,27 +1277,24 @@ neterr_t NET_RunConnect(netstream_t *s)
return NET_AGAIN;
}
- len = sizeof(err);
- ret = getsockopt(s->socket, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
- if (ret == -1) {
- goto error1;
+ ret = os_getsockopt(s->socket, SOL_SOCKET, SO_ERROR, &err);
+ if (ret) {
+ goto fail;
}
if (err) {
net_error = err;
- goto error2;
+ goto fail;
}
+ s->state = NS_CONNECTED;
e->wantwrite = qfalse;
e->wantread = qtrue;
#ifdef _WIN32
e->wantexcept = qfalse;
#endif
- s->state = NS_CONNECTED;
return NET_OK;
-error1:
- NET_GET_ERROR();
-error2:
+fail:
s->state = NS_BROKEN;
e->wantwrite = qfalse;
e->wantread = qfalse;
@@ -1346,7 +1314,7 @@ void NET_UpdateStream(netstream_t *s)
return;
}
- e = IO_Get(s->socket);
+ e = os_get_io(s->socket);
FIFO_Reserve(&s->recv, &len);
e->wantread = len ? qtrue : qfalse;
@@ -1358,7 +1326,7 @@ void NET_UpdateStream(netstream_t *s)
// returns NET_OK only when there was some data read
neterr_t NET_RunStream(netstream_t *s)
{
- int ret;
+ ssize_t ret;
size_t len;
void *data;
neterr_t result = NET_AGAIN;
@@ -1368,22 +1336,21 @@ neterr_t NET_RunStream(netstream_t *s)
return result;
}
- e = IO_Get(s->socket);
+ e = os_get_io(s->socket);
if (e->wantread && e->canread) {
// read as much as we can
data = FIFO_Reserve(&s->recv, &len);
if (len) {
- ret = recv(s->socket, data, len, 0);
+ ret = os_recv(s->socket, data, len, 0);
if (!ret) {
goto closed;
}
- if (ret == -1) {
- if (NET_WOULD_BLOCK()) {
- // wouldblock is silent
- e->canread = qfalse;
- } else {
- goto error;
- }
+ if (ret == NET_ERROR) {
+ goto error;
+ }
+ if (ret == NET_AGAIN) {
+ // wouldblock is silent
+ e->canread = qfalse;
} else {
FIFO_Commit(&s->recv, ret);
#if _DEBUG
@@ -1409,17 +1376,16 @@ neterr_t NET_RunStream(netstream_t *s)
// write as much as we can
data = FIFO_Peek(&s->send, &len);
if (len) {
- ret = send(s->socket, data, len, 0);
+ ret = os_send(s->socket, data, len, 0);
if (!ret) {
goto closed;
}
- if (ret == -1) {
- if (NET_WOULD_BLOCK()) {
- // wouldblock is silent
- e->canwrite = qfalse;
- } else {
- goto error;
- }
+ if (ret == NET_ERROR) {
+ goto error;
+ }
+ if (ret == NET_AGAIN) {
+ // wouldblock is silent
+ e->canwrite = qfalse;
} else {
FIFO_Decommit(&s->send, ret);
#if _DEBUG
@@ -1458,51 +1424,7 @@ error:
//===================================================================
-/*
-====================
-NET_Stats_f
-====================
-*/
-static void NET_Stats_f(void)
-{
- time_t diff, now = time(NULL);
- char buffer[MAX_QPATH];
-
- if (com_startTime > now) {
- com_startTime = now;
- }
- diff = now - com_startTime;
- if (diff < 1) {
- diff = 1;
- }
-
- Com_FormatTime(buffer, sizeof(buffer), diff);
- Com_Printf("Network uptime: %s\n", buffer);
- Com_Printf("Bytes sent: %"PRIu64" (%"PRIu64" bytes/sec)\n",
- net_bytes_sent, net_bytes_sent / diff);
- Com_Printf("Bytes rcvd: %"PRIu64" (%"PRIu64" bytes/sec)\n",
- net_bytes_rcvd, net_bytes_rcvd / diff);
- Com_Printf("Packets sent: %"PRIu64" (%"PRIu64" packets/sec)\n",
- net_packets_sent, net_packets_sent / diff);
- Com_Printf("Packets rcvd: %"PRIu64" (%"PRIu64" packets/sec)\n",
- net_packets_rcvd, net_packets_rcvd / diff);
-#if USE_ICMP
- Com_Printf("Total errors: %"PRIu64"/%"PRIu64"/%"PRIu64" (send/recv/icmp)\n",
- net_send_errors, net_recv_errors, net_icmp_errors);
-#else
- Com_Printf("Total errors: %"PRIu64"/%"PRIu64" (send/recv)\n",
- net_send_errors, net_recv_errors);
-#endif
- Com_Printf("Current upload rate: %"PRIz" bytes/sec\n", net_rate_up);
- Com_Printf("Current download rate: %"PRIz" bytes/sec\n", net_rate_dn);
-}
-
-/*
-====================
-NET_DumpHostInfo
-====================
-*/
-static void NET_DumpHostInfo(struct hostent *h)
+static void dump_hostent(struct hostent *h)
{
byte **list;
int i;
@@ -1521,20 +1443,21 @@ static void NET_DumpHostInfo(struct hostent *h)
}
}
-static void dump_socket(SOCKET s, const char *s1, const char *s2)
+static void dump_socket(qsocket_t s, const char *s1, const char *s2)
{
- struct sockaddr_in sadr;
- socklen_t len;
netadr_t adr;
- len = sizeof(sadr);
- if (getsockname(s, (struct sockaddr *)&sadr, &len) == -1) {
- NET_GET_ERROR();
- Com_EPrintf("%s: getsockname: %s\n", __func__, NET_ErrorString());
+ if (s == -1)
+ return;
+
+ if (os_getsockname(s, &adr)) {
+ Com_EPrintf("Couldn't get %s %s socket name: %s\n",
+ s1, s2, NET_ErrorString());
return;
}
- NET_SockadrToNetadr(&sadr, &adr);
- Com_Printf("%s %s socket bound to %s\n", s1, s2, NET_AdrToString(&adr));
+
+ Com_Printf("%s %s socket bound to %s\n",
+ s1, s2, NET_AdrToString(&adr));
}
/*
@@ -1546,30 +1469,23 @@ static void NET_ShowIP_f(void)
{
char buffer[256];
struct hostent *h;
- netsrc_t sock;
if (gethostname(buffer, sizeof(buffer)) == -1) {
- NET_GET_ERROR();
- Com_EPrintf("%s: gethostname: %s\n", __func__, NET_ErrorString());
+ Com_EPrintf("Couldn't get system host name\n");
return;
}
if (!(h = gethostbyname(buffer))) {
- NET_GET_ERROR();
- Com_EPrintf("%s: gethostbyname: %s\n", __func__, NET_ErrorString());
+ Com_EPrintf("Couldn't resolve %s\n", buffer);
return;
}
- NET_DumpHostInfo(h);
+ dump_hostent(h);
- for (sock = 0; sock < NS_COUNT; sock++) {
- if (udp_sockets[sock] != INVALID_SOCKET) {
- dump_socket(udp_sockets[sock], socketNames[sock], "UDP");
- }
- }
- if (tcp_socket != INVALID_SOCKET) {
- dump_socket(tcp_socket, socketNames[NS_SERVER], "TCP");
- }
+ // dump listening sockets
+ dump_socket(udp_sockets[NS_CLIENT], "Client", "UDP");
+ dump_socket(udp_sockets[NS_SERVER], "Server", "UDP");
+ dump_socket(tcp_socket, "Server", "TCP");
}
/*
@@ -1606,8 +1522,7 @@ static void NET_Dns_f(void)
return;
}
- NET_DumpHostInfo(h);
-
+ dump_hostent(h);
}
/*
@@ -1618,7 +1533,7 @@ NET_Restart_f
static void NET_Restart_f(void)
{
netflag_t flag = net_active;
- qboolean listen = tcp_socket != INVALID_SOCKET;
+ qboolean listen = tcp_socket != -1;
Com_DPrintf("%s\n", __func__);
@@ -1636,75 +1551,6 @@ static void NET_Restart_f(void)
#endif
}
-/*
-====================
-NET_Config
-====================
-*/
-void NET_Config(netflag_t flag)
-{
- netsrc_t sock;
-
- if (flag == net_active) {
- return;
- }
-
- if (flag == NET_NONE) {
- // shut down any existing sockets
- for (sock = 0; sock < NS_COUNT; sock++) {
- if (udp_sockets[sock] != INVALID_SOCKET) {
- IO_Remove(udp_sockets[sock]);
- closesocket(udp_sockets[sock]);
- udp_sockets[sock] = INVALID_SOCKET;
- }
- }
- net_active = NET_NONE;
- return;
- }
-
-#if USE_CLIENT
- if ((flag & NET_CLIENT) && udp_sockets[NS_CLIENT] == INVALID_SOCKET) {
- NET_OpenClient();
- }
-#endif
-
- if ((flag & NET_SERVER) && udp_sockets[NS_SERVER] == INVALID_SOCKET) {
- NET_OpenServer();
- }
-
- net_active |= flag;
-}
-
-qboolean NET_GetAddress(netsrc_t sock, netadr_t *adr)
-{
- struct sockaddr_in sadr;
- socklen_t len;
- SOCKET s = udp_sockets[sock];
-
- if (s == INVALID_SOCKET) {
- return qfalse;
- }
-
- len = sizeof(sadr);
- if (getsockname(s, (struct sockaddr *)&sadr, &len) == -1) {
- return qfalse;
- }
-
- NET_SockadrToNetadr(&sadr, adr);
-
- return qtrue;
-}
-
-static size_t NET_UpRate_m(char *buffer, size_t size)
-{
- return Q_scnprintf(buffer, size, "%"PRIz, net_rate_up);
-}
-
-static size_t NET_DnRate_m(char *buffer, size_t size)
-{
- return Q_scnprintf(buffer, size, "%"PRIz, net_rate_dn);
-}
-
static void net_udp_param_changed(cvar_t *self)
{
// keep TCP socket vars in sync unless modified by user
@@ -1720,7 +1566,7 @@ static void net_udp_param_changed(cvar_t *self)
static void net_tcp_param_changed(cvar_t *self)
{
- if (tcp_socket != INVALID_SOCKET) {
+ if (tcp_socket != -1) {
NET_Listen(qfalse);
NET_Listen(qtrue);
}
@@ -1733,17 +1579,7 @@ NET_Init
*/
void NET_Init(void)
{
-#ifdef _WIN32
- WSADATA ws;
- int ret;
-
- ret = WSAStartup(MAKEWORD(1, 1), &ws);
- if (ret) {
- Com_Error(ERR_FATAL, "Winsock initialization failed, returned %d", ret);
- }
-
- Com_DPrintf("Winsock Initialized\n");
-#endif
+ os_net_init();
net_ip = Cvar_Get("net_ip", "", 0);
net_ip->changed = net_udp_param_changed;
@@ -1794,18 +1630,12 @@ NET_Shutdown
void NET_Shutdown(void)
{
#if _DEBUG
- if (net_logFile) {
- FS_FCloseFile(net_logFile);
- net_logFile = 0;
- }
+ logfile_close();
#endif
NET_Listen(qfalse);
NET_Config(NET_NONE);
-
-#ifdef _WIN32
- WSACleanup();
-#endif
+ os_net_shutdown();
Cmd_RemoveCommand("net_restart");
Cmd_RemoveCommand("net_stats");
diff --git a/src/net_sock.h b/src/net_sock.h
index 8e5a340..07cc660 100644
--- a/src/net_sock.h
+++ b/src/net_sock.h
@@ -33,6 +33,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_PACKETLEN_WRITABLE (MAX_PACKETLEN - PACKET_HEADER)
#define MAX_PACKETLEN_WRITABLE_DEFAULT (MAX_PACKETLEN_DEFAULT - PACKET_HEADER)
+// portable network error codes
+#define NET_OK 0 // success
+#define NET_ERROR -1 // failure (NET_ErrorString returns error message)
+#define NET_AGAIN -2 // operation would block, try again
+#define NET_CLOSED -3 // peer has closed connection
+
+typedef int neterr_t;
+
+#ifdef _WIN32
+typedef intptr_t qsocket_t;
+#else
+typedef int qsocket_t;
+#endif
+
+typedef struct {
+#ifdef _WIN32
+ qsocket_t fd;
+#endif
+ qboolean inuse: 1;
+ qboolean canread: 1;
+ qboolean canwrite: 1;
+ qboolean canexcept: 1;
+ qboolean wantread: 1;
+ qboolean wantwrite: 1;
+ qboolean wantexcept: 1;
+} ioentry_t;
+
typedef enum {
NA_BAD,
NA_LOOPBACK,
@@ -52,20 +79,13 @@ typedef enum {
NET_SERVER = (1 << 1)
} netflag_t;
-typedef enum {
- NET_OK,
- NET_AGAIN,
- NET_CLOSED,
- NET_ERROR,
-} neterr_t;
-
typedef union {
uint8_t u8[4];
uint16_t u16[2];
uint32_t u32;
} netadrip_t;
-typedef struct {
+typedef struct netadr_s {
netadrtype_t type;
netadrip_t ip;
uint16_t port;
@@ -137,27 +157,39 @@ static inline qboolean NET_IsLanAddress(const netadr_t *adr)
return qfalse;
}
+static inline qboolean NET_IsLocalAddress(const netadr_t *adr)
+{
+#if USE_CLIENT && USE_SERVER
+ if (adr->type == NA_LOOPBACK)
+ return qtrue;
+#endif
+ return qfalse;
+}
+
void NET_Init(void);
void NET_Shutdown(void);
void NET_Config(netflag_t flag);
qboolean NET_GetAddress(netsrc_t sock, netadr_t *adr);
+void NET_UpdateStats(void);
+
qboolean NET_GetPacket(netsrc_t sock);
-qboolean NET_SendPacket(netsrc_t sock, const netadr_t *to, size_t length, const void *data);
+qboolean NET_SendPacket(netsrc_t sock, const void *data, size_t len, const netadr_t *to);
qboolean NET_GetLoopPacket(netsrc_t sock);
char *NET_AdrToString(const netadr_t *a);
qboolean NET_StringToAdr(const char *s, netadr_t *a, int port);
-#if USE_CLIENT && USE_SERVER
-#define NET_IsLocalAddress(adr) ((adr)->type == NA_LOOPBACK)
-#else
-#define NET_IsLocalAddress(adr) 0
-#endif
-
const char *NET_ErrorString(void);
+ioentry_t *NET_AddFd(qsocket_t fd);
+void NET_RemoveFd(qsocket_t fd);
+int NET_Sleep(int msec);
+#if USE_AC_SERVER
+int NET_Sleepv(int msec, ...);
+#endif
+
extern cvar_t *net_ip;
extern cvar_t *net_port;
diff --git a/src/net_stream.h b/src/net_stream.h
index 7ccfae2..379e293 100644
--- a/src/net_stream.h
+++ b/src/net_stream.h
@@ -27,14 +27,14 @@ typedef enum netstate_e {
} netstate_t;
typedef struct netstream_s {
- int socket;
+ qsocket_t socket;
netadr_t address;
netstate_t state;
fifo_t recv;
fifo_t send;
} netstream_t;
-void NET_Close(netstream_t *s);
+void NET_CloseStream(netstream_t *s);
neterr_t NET_Listen(qboolean listen);
neterr_t NET_Accept(netstream_t *s);
neterr_t NET_Connect(const netadr_t *peer, netstream_t *s);
diff --git a/src/net_unix.h b/src/net_unix.h
new file mode 100644
index 0000000..9d36aa8
--- /dev/null
+++ b/src/net_unix.h
@@ -0,0 +1,409 @@
+/*
+Copyright (C) 2012 skuller.net
+
+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.
+
+*/
+
+//
+// net_unix.h -- BSD sockets wrapper
+//
+
+static const char *os_error_string(int err)
+{
+ return strerror(err);
+}
+
+// Receiving ICMP errors on unconnected UDP sockets is tricky...
+// Linux 2.2 and higher supports this via IP_RECVERR option, see ip(7).
+// What about BSD?
+
+#ifdef __linux__
+
+static qboolean check_offender(const struct sockaddr_in *from,
+ const struct sockaddr_in *to)
+{
+ if (!to)
+ return qfalse;
+
+ if (from->sin_addr.s_addr != to->sin_addr.s_addr)
+ return qfalse;
+
+ if (from->sin_port && from->sin_port != to->sin_port)
+ return qfalse;
+
+ Com_DPrintf("%s: found offending address %s:%d\n", "process_error_queue",
+ inet_ntoa(from->sin_addr), ntohs(from->sin_port));
+
+ return qtrue;
+}
+
+// Returns true if failed socket operation should be retried.
+// May get called from NET_SendPacket() path, avoid interfering with net_from.
+static qboolean process_error_queue(netsrc_t sock, const struct sockaddr_in *to_addr)
+{
+ byte buffer[1024];
+ struct sockaddr_in from_addr;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct sock_extended_err *ee;
+ netadr_t from;
+ int tries;
+ qboolean found = qfalse;
+
+ for (tries = 0; tries < MAX_ERROR_RETRIES; tries++) {
+ memset(&from_addr, 0, sizeof(from_addr));
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &from_addr;
+ msg.msg_namelen = sizeof(from_addr);
+ msg.msg_control = buffer;
+ msg.msg_controllen = sizeof(buffer);
+
+ if (recvmsg(udp_sockets[sock], &msg, MSG_ERRQUEUE) == -1) {
+ if (errno != EWOULDBLOCK)
+ Com_DPrintf("%s: %s\n", __func__, strerror(errno));
+ break;
+ }
+
+ if (!(msg.msg_flags & MSG_ERRQUEUE)) {
+ Com_DPrintf("%s: no extended error received\n", __func__);
+ break;
+ }
+
+ // find an ICMP error message
+ for (cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != IPPROTO_IP) {
+ continue;
+ }
+ if (cmsg->cmsg_type != IP_RECVERR) {
+ continue;
+ }
+ ee = (struct sock_extended_err *)CMSG_DATA(cmsg);
+ if (ee->ee_origin == SO_EE_ORIGIN_ICMP) {
+ break;
+ }
+ }
+
+ if (!cmsg) {
+ Com_DPrintf("%s: no ICMP error found\n", __func__);
+ break;
+ }
+
+ found |= check_offender(&from_addr, to_addr);
+
+ NET_SockadrToNetadr(&from_addr, &from);
+
+ // handle ICMP error
+ NET_ErrorEvent(sock, &from, ee->ee_errno, ee->ee_info);
+ }
+
+ return !!tries && !found;
+}
+
+#endif // !__linux__
+
+static ssize_t os_udp_recv(netsrc_t sock, void *data,
+ size_t len, netadr_t *from)
+{
+ struct sockaddr_in addr;
+ socklen_t addrlen;
+ ssize_t ret;
+
+#ifdef __linux__
+ int tries;
+ for (tries = 0; tries < MAX_ERROR_RETRIES; tries++) {
+#endif
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+ ret = recvfrom(udp_sockets[sock], data, len, 0,
+ (struct sockaddr *)&addr, &addrlen);
+
+ NET_SockadrToNetadr(&addr, from);
+
+ if (ret >= 0)
+ return ret;
+
+ net_error = errno;
+
+ // wouldblock is silent
+ if (net_error == EWOULDBLOCK)
+ return NET_AGAIN;
+
+#ifdef __linux__
+ // recvfrom() fails on Linux if there is an ICMP originated pending
+ // error on socket. Suck up error queue and retry...
+
+ if (!process_error_queue(sock, NULL))
+ break;
+ }
+#endif
+
+ return NET_ERROR;
+}
+
+static ssize_t os_udp_send(netsrc_t sock, const void *data,
+ size_t len, const netadr_t *to)
+{
+ struct sockaddr_in addr;
+ ssize_t ret;
+
+ NET_NetadrToSockadr(to, &addr);
+
+#ifdef __linux__
+ int tries;
+ for (tries = 0; tries < MAX_ERROR_RETRIES; tries++) {
+#endif
+ ret = sendto(udp_sockets[sock], data, len, 0,
+ (struct sockaddr *)&addr, sizeof(addr));
+ if (ret >= 0)
+ return ret;
+
+ net_error = errno;
+
+ // wouldblock is silent
+ if (net_error == EWOULDBLOCK)
+ return NET_AGAIN;
+
+#ifdef __linux__
+ // sendto() fails on Linux if there is an ICMP originated pending error
+ // on socket. Suck up error queue and retry...
+ //
+ // But how do I distingiush between a failure caused by completely
+ // unrelated ICMP error sitting in the queue and an error directly
+ // related to this sendto() call?
+ //
+ // On one hand, I don't want to drop packets to legitimate clients, and
+ // have to retry sendto() after processing error queue. On other
+ // hand, infinite loop should be avoided if sendto() call regenerates
+ // the message in error queue.
+ //
+ // This mess is worked around by passing destination address to
+ // process_error_queue() and checking if this address/port pair is
+ // found in the queue. If it is found, or the queue is empty, do not
+ // retry.
+
+ if (!process_error_queue(sock, &addr))
+ break;
+ }
+#endif
+
+ return NET_ERROR;
+}
+
+static neterr_t os_get_error(void)
+{
+ net_error = errno;
+ if (net_error == EWOULDBLOCK)
+ return NET_AGAIN;
+
+ return NET_ERROR;
+}
+
+static ssize_t os_recv(qsocket_t sock, void *data, size_t len, int flags)
+{
+ ssize_t ret = recv(sock, data, len, flags);
+
+ if (ret == -1)
+ return os_get_error();
+
+ return ret;
+}
+
+static ssize_t os_send(qsocket_t sock, const void *data, size_t len, int flags)
+{
+ ssize_t ret = send(sock, data, len, flags);
+
+ if (ret == -1)
+ return os_get_error();
+
+ return ret;
+}
+
+static neterr_t os_listen(qsocket_t sock, int backlog)
+{
+ if (listen(sock, backlog) == -1) {
+ net_error = errno;
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_accept(qsocket_t sock, qsocket_t *newsock, netadr_t *from)
+{
+ struct sockaddr_in addr;
+ socklen_t addrlen;
+ int s;
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+ s = accept(sock, (struct sockaddr *)&addr, &addrlen);
+
+ NET_SockadrToNetadr(&addr, from);
+
+ if (s == -1) {
+ *newsock = -1;
+ return os_get_error();
+ }
+
+ *newsock = s;
+ return NET_OK;
+}
+
+static neterr_t os_connect(qsocket_t sock, const netadr_t *to)
+{
+ struct sockaddr_in addr;
+
+ NET_NetadrToSockadr(to, &addr);
+
+ if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ net_error = errno;
+ if (net_error == EINPROGRESS)
+ return NET_OK;
+
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_make_nonblock(qsocket_t sock, int val)
+{
+ if (ioctl(sock, FIONBIO, &val) == -1) {
+ net_error = errno;
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_setsockopt(qsocket_t sock, int level, int name, int val)
+{
+ if (setsockopt(sock, level, name, &val, sizeof(val)) == -1) {
+ net_error = errno;
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_getsockopt(qsocket_t sock, int level, int name, int *val)
+{
+ socklen_t _optlen = sizeof(*val);
+
+ if (getsockopt(sock, level, name, val, &_optlen) == -1) {
+ net_error = errno;
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_bind(qsocket_t sock, const struct sockaddr *addr, size_t addrlen)
+{
+ if (bind(sock, addr, addrlen) == -1) {
+ net_error = errno;
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_getsockname(qsocket_t sock, netadr_t *name)
+{
+ struct sockaddr_in addr;
+ socklen_t addrlen;
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+ if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) == -1) {
+ net_error = errno;
+ return NET_ERROR;
+ }
+
+ NET_SockadrToNetadr(&addr, name);
+ return NET_OK;
+}
+
+static void os_closesocket(qsocket_t sock)
+{
+ close(sock);
+}
+
+static qsocket_t os_socket(int domain, int type, int protocol)
+{
+ int s = socket(domain, type, protocol);
+
+ if (s == -1) {
+ net_error = errno;
+ return -1;
+ }
+
+ return s;
+}
+
+static ioentry_t *_os_get_io(qsocket_t fd, const char *func)
+{
+ if (fd < 0 || fd >= FD_SETSIZE)
+ Com_Error(ERR_FATAL, "%s: fd out of range: %d", func, fd);
+
+ return &io_entries[fd];
+}
+
+static ioentry_t *os_add_io(qsocket_t fd)
+{
+ if (fd >= io_numfds) {
+ io_numfds = fd + 1;
+ }
+
+ return _os_get_io(fd, __func__);
+}
+
+static ioentry_t *os_get_io(qsocket_t fd)
+{
+ return _os_get_io(fd, __func__);
+}
+
+static qsocket_t os_get_fd(ioentry_t *e)
+{
+ return e - io_entries;
+}
+
+static int os_select(int nfds, fd_set *rfds, fd_set *wfds,
+ fd_set *efds, struct timeval *tv)
+{
+ int ret = select(nfds, rfds, wfds, efds, tv);
+
+ if (ret == -1) {
+ net_error = errno;
+ if (net_error == EINTR)
+ return 0;
+ }
+
+ return ret;
+}
+
+static void os_net_init(void)
+{
+}
+
+static void os_net_shutdown(void)
+{
+}
+
diff --git a/src/net_win.h b/src/net_win.h
new file mode 100644
index 0000000..5204780
--- /dev/null
+++ b/src/net_win.h
@@ -0,0 +1,401 @@
+/*
+Copyright (C) 2012 skuller.net
+
+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.
+
+*/
+
+//
+// net_win.h -- Windows sockets wrapper
+//
+
+static const struct {
+ int err;
+ const char *msg;
+} wsa_error_table[] = {
+ { S_OK, "Success" },
+ { WSAEINTR, "Interrupted function call" },
+ { WSAEBADF, "File handle is not valid" },
+ { WSAEACCES, "Permission denied" },
+ { WSAEFAULT, "Bad address" },
+ { WSAEINVAL, "Invalid argument" },
+ { WSAEMFILE, "Too many open files" },
+ { WSAEWOULDBLOCK, "Resource temporarily unavailable" },
+ { WSAEINPROGRESS, "Operation now in progress" },
+ { WSAEALREADY, "Operation already in progress" },
+ { WSAENOTSOCK, "Socket operation on nonsocket" },
+ { WSAEDESTADDRREQ, "Destination address required" },
+ { WSAEMSGSIZE, "Message too long" },
+ { WSAEPROTOTYPE, "Protocol wrong type for socket" },
+ { WSAENOPROTOOPT, "Bad protocol option" },
+ { WSAEPROTONOSUPPORT, "Protocol not supported" },
+ { WSAESOCKTNOSUPPORT, "Socket type not supported" },
+ { WSAEOPNOTSUPP, "Operation not supported" },
+ { WSAEPFNOSUPPORT, "Protocol family not supported" },
+ { WSAEAFNOSUPPORT, "Address family not supported by protocol family" },
+ { WSAEADDRINUSE, "Address already in use" },
+ { WSAEADDRNOTAVAIL, "Cannot assign requested address" },
+ { WSAENETDOWN, "Network is down" },
+ { WSAENETUNREACH, "Network is unreachable" },
+ { WSAENETRESET, "Network dropped connection on reset" },
+ { WSAECONNABORTED, "Software caused connection abort" },
+ { WSAECONNRESET, "Connection reset by peer" },
+ { WSAENOBUFS, "No buffer space available" },
+ { WSAEISCONN, "Socket is already connected" },
+ { WSAENOTCONN, "Socket is not connected" },
+ { WSAESHUTDOWN, "Cannot send after socket shutdown" },
+ { WSAETOOMANYREFS, "Too many references" },
+ { WSAETIMEDOUT, "Connection timed out" },
+ { WSAECONNREFUSED, "Connection refused" },
+ { WSAELOOP, "Cannot translate name" },
+ { WSAENAMETOOLONG, "Name too long" },
+ { WSAEHOSTDOWN, "Host is down" },
+ { WSAEHOSTUNREACH, "No route to host" },
+ { WSAENOTEMPTY, "Directory not empty" },
+ { WSAEPROCLIM, "Too many processes" },
+ { WSAEUSERS, "User quota exceeded" },
+ { WSAEDQUOT, "Disk quota exceeded" },
+ { WSAESTALE, "Stale file handle reference" },
+ { WSAEREMOTE, "Item is remote" },
+ { WSASYSNOTREADY, "Network subsystem is unavailable" },
+ { WSAVERNOTSUPPORTED, "Winsock.dll version out of range" },
+ { WSANOTINITIALISED, "Successful WSAStartup not yet performed" },
+ { WSAEDISCON, "Graceful shutdown in progress" },
+ { WSAENOMORE, "No more results" },
+ { WSAECANCELLED, "Call has been canceled" },
+ { WSAEINVALIDPROCTABLE, "Procedure call table is invalid" },
+ { WSAEINVALIDPROVIDER, "Service provider is invalid" },
+ { WSAEPROVIDERFAILEDINIT, "Service provider failed to initialize" },
+ { WSASYSCALLFAILURE, "System call failure" },
+ { WSASERVICE_NOT_FOUND, "Service not found" },
+ { WSATYPE_NOT_FOUND, "Class type not found" },
+ { WSA_E_NO_MORE, "No more results" },
+ { WSA_E_CANCELLED, "Call was canceled" },
+ { WSAEREFUSED, "Database query was refused" },
+ { WSAHOST_NOT_FOUND, "Host not found" },
+ { WSATRY_AGAIN, "Nonauthoritative host not found" },
+ { WSANO_RECOVERY, "This is a nonrecoverable error" },
+ { WSANO_DATA, "Valid name, no data record of requested type" },
+ { -1, "Unknown error" }
+};
+
+static const char *os_error_string(int err)
+{
+ int i;
+
+ for (i = 0; wsa_error_table[i].err != -1; i++) {
+ if (wsa_error_table[i].err == err)
+ break;
+ }
+
+ return wsa_error_table[i].msg;
+}
+
+static ssize_t os_udp_recv(netsrc_t sock, void *data,
+ size_t len, netadr_t *from)
+{
+ struct sockaddr_in addr;
+ int addrlen;
+ int ret;
+ int tries;
+
+ for (tries = 0; tries < MAX_ERROR_RETRIES; tries++) {
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+ ret = recvfrom(udp_sockets[sock], data, len, 0,
+ (struct sockaddr *)&addr, &addrlen);
+
+ NET_SockadrToNetadr(&addr, from);
+
+ if (ret != SOCKET_ERROR)
+ return ret;
+
+ net_error = WSAGetLastError();
+
+ // wouldblock is silent
+ if (net_error == WSAEWOULDBLOCK)
+ return NET_AGAIN;
+
+#if USE_ICMP
+ if (net_error == WSAECONNRESET || net_error == WSAENETRESET) {
+ // winsock has already provided us with
+ // a valid address from ICMP error packet
+ NET_ErrorEvent(sock, from, net_error, 0);
+ continue;
+ }
+#endif
+
+ break;
+ }
+
+ return NET_ERROR;
+}
+
+static ssize_t os_udp_send(netsrc_t sock, const void *data,
+ size_t len, const netadr_t *to)
+{
+ struct sockaddr_in addr;
+ int ret;
+
+ NET_NetadrToSockadr(to, &addr);
+
+ ret = sendto(udp_sockets[sock], data, len, 0,
+ (struct sockaddr *)&addr, sizeof(addr));
+
+ if (ret != SOCKET_ERROR)
+ return ret;
+
+ net_error = WSAGetLastError();
+
+ // wouldblock is silent
+ if (net_error == WSAEWOULDBLOCK || net_error == WSAEINTR)
+ return NET_AGAIN;
+
+ // some PPP links do not allow broadcasts
+ if (net_error == WSAEADDRNOTAVAIL && to->type == NA_BROADCAST)
+ return NET_AGAIN;
+
+ return NET_ERROR;
+}
+
+static neterr_t os_get_error(void)
+{
+ net_error = WSAGetLastError();
+ if (net_error == WSAEWOULDBLOCK)
+ return NET_AGAIN;
+
+ return NET_ERROR;
+}
+
+static ssize_t os_recv(qsocket_t sock, void *data, size_t len, int flags)
+{
+ int ret = recv(sock, data, len, flags);
+
+ if (ret == SOCKET_ERROR)
+ return os_get_error();
+
+ return ret;
+}
+
+static ssize_t os_send(qsocket_t sock, const void *data, size_t len, int flags)
+{
+ int ret = send(sock, data, len, flags);
+
+ if (ret == SOCKET_ERROR)
+ return os_get_error();
+
+ return ret;
+}
+
+static neterr_t os_listen(qsocket_t sock, int backlog)
+{
+ if (listen(sock, backlog) == SOCKET_ERROR) {
+ net_error = WSAGetLastError();
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_accept(qsocket_t sock, qsocket_t *newsock, netadr_t *from)
+{
+ struct sockaddr_in addr;
+ int addrlen;
+ int s;
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+ s = accept(sock, (struct sockaddr *)&addr, &addrlen);
+
+ NET_SockadrToNetadr(&addr, from);
+
+ if (s == INVALID_SOCKET) {
+ *newsock = -1;
+ return os_get_error();
+ }
+
+ *newsock = s;
+ return NET_OK;
+}
+
+static neterr_t os_connect(qsocket_t sock, const netadr_t *to)
+{
+ struct sockaddr_in addr;
+
+ NET_NetadrToSockadr(to, &addr);
+
+ if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
+ net_error = WSAGetLastError();
+ if (net_error == WSAEWOULDBLOCK)
+ return NET_OK;
+
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_make_nonblock(qsocket_t sock, int val)
+{
+ u_long _val = val;
+
+ if (ioctlsocket(sock, FIONBIO, &_val) == SOCKET_ERROR) {
+ net_error = WSAGetLastError();
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_setsockopt(qsocket_t sock, int level, int name, int val)
+{
+ u_long _val = val;
+
+ if (setsockopt(sock, level, name, (char *)&_val, sizeof(_val)) == SOCKET_ERROR) {
+ net_error = WSAGetLastError();
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_getsockopt(qsocket_t sock, int level, int name, int *val)
+{
+ u_long _val;
+ int optlen = sizeof(_val);
+
+ if (getsockopt(sock, level, name, (char *)&_val, &optlen) == SOCKET_ERROR) {
+ net_error = WSAGetLastError();
+ return NET_ERROR;
+ }
+
+ *val = _val;
+ return NET_OK;
+}
+
+static neterr_t os_bind(qsocket_t sock, const struct sockaddr *addr, size_t addrlen)
+{
+ if (bind(sock, addr, addrlen) == SOCKET_ERROR) {
+ net_error = WSAGetLastError();
+ return NET_ERROR;
+ }
+
+ return NET_OK;
+}
+
+static neterr_t os_getsockname(qsocket_t sock, netadr_t *name)
+{
+ struct sockaddr_in addr;
+ int addrlen;
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+ if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) == SOCKET_ERROR) {
+ net_error = WSAGetLastError();
+ return NET_ERROR;
+ }
+
+ NET_SockadrToNetadr(&addr, name);
+ return NET_OK;
+}
+
+static void os_closesocket(qsocket_t sock)
+{
+ closesocket(sock);
+}
+
+static qsocket_t os_socket(int domain, int type, int protocol)
+{
+ SOCKET s = socket(domain, type, protocol);
+
+ if (s == INVALID_SOCKET) {
+ net_error = WSAGetLastError();
+ return -1;
+ }
+
+ return s;
+}
+
+static ioentry_t *os_add_io(qsocket_t fd)
+{
+ ioentry_t *e;
+ int i;
+
+ for (i = 0, e = io_entries; i < io_numfds; i++, e++) {
+ if (!e->inuse)
+ break;
+ }
+
+ if (i == io_numfds) {
+ if (++io_numfds > FD_SETSIZE)
+ Com_Error(ERR_FATAL, "%s: no more space for fd: %d", __func__, fd);
+ }
+
+ e->fd = fd;
+ return e;
+}
+
+static ioentry_t *os_get_io(qsocket_t fd)
+{
+ ioentry_t *e;
+ int i;
+
+ for (i = 0, e = io_entries; i < io_numfds; i++, e++) {
+ if (!e->inuse)
+ continue;
+ if (e->fd == fd)
+ return e;
+ }
+
+ Com_Error(ERR_FATAL, "%s: fd not found: %d", __func__, fd);
+ return NULL;
+}
+
+static qsocket_t os_get_fd(ioentry_t *e)
+{
+ return e->fd;
+}
+
+static int os_select(int nfds, fd_set *rfds, fd_set *wfds,
+ fd_set *efds, struct timeval *tv)
+{
+ int ret = select(nfds, rfds, wfds, efds, tv);
+
+ if (ret == SOCKET_ERROR)
+ net_error = WSAGetLastError();
+
+ return ret;
+}
+
+static void os_net_init(void)
+{
+ WSADATA ws;
+ int ret;
+
+ ret = WSAStartup(MAKEWORD(1, 1), &ws);
+ if (ret) {
+ Com_Error(ERR_FATAL, "Winsock initialization failed: %s (%d)",
+ os_error_string(ret), ret);
+ }
+
+ Com_DPrintf("Winsock initialized\n");
+}
+
+static void os_net_shutdown(void)
+{
+ WSACleanup();
+}
+
diff --git a/src/sv_ac.c b/src/sv_ac.c
index 7caf93e..bcb795f 100644
--- a/src/sv_ac.c
+++ b/src/sv_ac.c
@@ -531,7 +531,7 @@ static void AC_Drop(void)
{
client_t *cl;
- NET_Close(&ac.stream);
+ NET_CloseStream(&ac.stream);
if (!ac.connected) {
Com_Printf("ANTICHEAT: Server connection failed.\n");
@@ -1189,11 +1189,11 @@ STARTUP STUFF
static void AC_Spin(void)
{
// sleep on stdin and AC server socket
- IO_Sleepv(100,
+ NET_Sleepv(100,
#ifndef _WIN32
- 0,
+ STDIN_FILENO,
#endif
- ac.stream.socket, -1);
+ ac.stream.socket, -1);
#if USE_SYSCON
Sys_RunConsole();
#endif
@@ -1487,7 +1487,7 @@ void AC_Connect(unsigned mvd_spawn)
void AC_Disconnect(void)
{
- NET_Close(&ac.stream);
+ NET_CloseStream(&ac.stream);
AC_FreeChecks();
diff --git a/src/sv_local.h b/src/sv_local.h
index f52dfee..c81e1e8 100644
--- a/src/sv_local.h
+++ b/src/sv_local.h
@@ -39,7 +39,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#if USE_MVD_CLIENT
#include "mvd_public.h"
#endif
-#include "io_sleep.h"
#include "fpu.h"
#if USE_ZLIB
#include <zlib.h>
diff --git a/src/sv_main.c b/src/sv_main.c
index 5d44710..7b617b2 100644
--- a/src/sv_main.c
+++ b/src/sv_main.c
@@ -425,7 +425,7 @@ static void SVC_Status(void)
len += SV_StatusString(buffer + len);
// send the datagram
- NET_SendPacket(NS_SERVER, &net_from, len, buffer);
+ NET_SendPacket(NS_SERVER, buffer, len, &net_from);
}
/*
@@ -461,31 +461,24 @@ The second parameter should be the current protocol version number.
*/
static void SVC_Info(void)
{
- char string[MAX_QPATH];
+ char buffer[MAX_QPATH];
size_t len;
- int count;
- int version;
if (sv_maxclients->integer == 1)
return; // ignore in single player
- version = atoi(Cmd_Argv(1));
-
- if (version != PROTOCOL_VERSION_DEFAULT) {
+ if (atoi(Cmd_Argv(1)) != PROTOCOL_VERSION_DEFAULT)
return;
- }
-
- count = SV_CountClients();
- len = Q_snprintf(string, sizeof(string),
+ len = Q_snprintf(buffer, sizeof(buffer),
"\xff\xff\xff\xffinfo\n%16s %8s %2i/%2i\n",
- sv_hostname->string, sv.name, count, sv_maxclients->integer -
+ sv_hostname->string, sv.name, SV_CountClients(),
+ sv_maxclients->integer -
sv_reserved_slots->integer);
- if (len >= sizeof(string)) {
+ if (len >= sizeof(buffer))
return;
- }
- NET_SendPacket(NS_SERVER, &net_from, len, string);
+ NET_SendPacket(NS_SERVER, buffer, len, &net_from);
}
/*
@@ -810,7 +803,7 @@ static void redirect(const char *addr)
MSG_WriteByte(svc_stufftext);
MSG_WriteString(va("connect %s\n", addr));
- NET_SendPacket(NS_SERVER, &net_from, msg_write.cursize, msg_write.data);
+ NET_SendPacket(NS_SERVER, msg_write.data, msg_write.cursize, &net_from);
SZ_Clear(&msg_write);
}
@@ -1365,13 +1358,46 @@ static void SV_PacketEvent(void)
}
}
+#if USE_PMTUDISC
+// We are doing path MTU discovery and got ICMP fragmentation-needed.
+// Update MTU for connecting clients only to minimize spoofed ICMP interference.
+// Total 64 bytes of headers is assumed.
+static void update_client_mtu(client_t *client, int ee_info)
+{
+ netchan_t *netchan = client->netchan;
+ size_t newpacketlen;
+
+ // sanity check discovered MTU
+ if (ee_info < 576 || ee_info > 4096)
+ return;
+
+ if (client->state != cs_primed)
+ return;
+
+ // TODO: old clients require entire queue flush :(
+ if (netchan->type == NETCHAN_OLD)
+ return;
+
+ if (!netchan->reliable_length)
+ return;
+
+ newpacketlen = ee_info - 64;
+ if (newpacketlen >= netchan->maxpacketlen)
+ return;
+
+ Com_Printf("Fixing up maxmsglen for %s: %"PRIz" --> %"PRIz"\n",
+ client->name, netchan->maxpacketlen, newpacketlen);
+ netchan->maxpacketlen = newpacketlen;
+}
+#endif
+
#if USE_ICMP
/*
=================
SV_ErrorEvent
=================
*/
-void SV_ErrorEvent(int info)
+void SV_ErrorEvent(netadr_t *from, int ee_errno, int ee_info)
{
client_t *client;
netchan_t *netchan;
@@ -1386,29 +1412,16 @@ void SV_ErrorEvent(int info)
continue; // already a zombie
}
netchan = client->netchan;
- if (!NET_IsEqualBaseAdr(&net_from, &netchan->remote_address)) {
+ if (!NET_IsEqualBaseAdr(from, &netchan->remote_address)) {
continue;
}
- if (net_from.port && netchan->remote_address.port != net_from.port) {
+ if (from->port && netchan->remote_address.port != from->port) {
continue;
}
#if USE_PMTUDISC
- if (info) {
- // we are doing path MTU discovery and got ICMP fragmentation-needed
- // update MTU only for connecting clients to minimize spoofed ICMP interference
- // MTU info has already been sanity checked for us by network code
- // assume total 64 bytes of headers
- if (client->state == cs_primed &&
- netchan->reliable_length &&
- info < netchan->maxpacketlen + 64) {
- if (netchan->type == NETCHAN_OLD) {
- // TODO: old clients require entire queue flush :(
- continue;
- }
- Com_Printf("Fixing up maxmsglen for %s: %d --> %d\n",
- client->name, (int)netchan->maxpacketlen, info - 64);
- netchan->maxpacketlen = info - 64;
- }
+ // for EMSGSIZE ee_info should hold discovered MTU
+ if (ee_errno == EMSGSIZE) {
+ update_client_mtu(client, ee_info);
continue;
}
#endif
@@ -1646,7 +1659,7 @@ static void SV_MasterHeartbeat(void)
if (m->adr.port) {
Com_DPrintf("Sending heartbeat to %s\n",
NET_AdrToString(&m->adr));
- NET_SendPacket(NS_SERVER, &m->adr, len, buffer);
+ NET_SendPacket(NS_SERVER, buffer, len, &m->adr);
}
}
}
diff --git a/src/sv_mvd.c b/src/sv_mvd.c
index 3707c4c..9f425f7 100644
--- a/src/sv_mvd.c
+++ b/src/sv_mvd.c
@@ -1216,7 +1216,7 @@ TCP CLIENTS HANDLING
static void remove_client(gtv_client_t *client)
{
- NET_Close(&client->stream);
+ NET_CloseStream(&client->stream);
List_Remove(&client->entry);
if (client->data) {
Z_Free(client->data);
@@ -1655,7 +1655,7 @@ static void accept_client(netstream_t *stream)
if (count >= sv_iplimit->integer) {
Com_Printf("TCP client [%s] rejected: too many connections\n",
NET_AdrToString(&stream->address));
- NET_Close(stream);
+ NET_CloseStream(stream);
return;
}
}
@@ -1665,7 +1665,7 @@ static void accept_client(netstream_t *stream)
if (!client) {
Com_Printf("TCP client [%s] rejected: no free slots\n",
NET_AdrToString(&stream->address));
- NET_Close(stream);
+ NET_CloseStream(stream);
return;
}
diff --git a/src/sv_public.h b/src/sv_public.h
index 9b54e0b..e97827a 100644
--- a/src/sv_public.h
+++ b/src/sv_public.h
@@ -28,7 +28,7 @@ typedef enum {
} server_state_t;
#if USE_ICMP
-void SV_ErrorEvent(int info);
+void SV_ErrorEvent(netadr_t *from, int ee_errno, int ee_info);
#endif
void SV_Init(void);
void SV_Shutdown(const char *finalmsg, error_type_t type);
diff --git a/src/sv_send.c b/src/sv_send.c
index 193e399..722a443 100644
--- a/src/sv_send.c
+++ b/src/sv_send.c
@@ -38,7 +38,7 @@ void SV_FlushRedirect(int redirected, char *outputbuf, size_t len)
if (redirected == RD_PACKET) {
memcpy(buffer, "\xff\xff\xff\xffprint\n", 10);
memcpy(buffer + 10, outputbuf, len);
- NET_SendPacket(NS_SERVER, &net_from, len + 10, buffer);
+ NET_SendPacket(NS_SERVER, buffer, len + 10, &net_from);
} else if (redirected == RD_CLIENT) {
MSG_WriteByte(svc_print);
MSG_WriteByte(PRINT_HIGH);
@@ -336,8 +336,6 @@ void SV_Multicast(vec3_t origin, multicast_t to)
SZ_Clear(&msg_write);
}
-
-
/*
=======================
SV_ClientAddMessage
@@ -700,11 +698,14 @@ static void write_datagram_old(client_t *client)
// send the datagram
cursize = client->netchan->Transmit(client->netchan,
- msg_write.cursize, msg_write.data, client->numpackets);
+ msg_write.cursize,
+ msg_write.data,
+ client->numpackets);
// record the size for rate estimation
SV_CalcSendTime(client, cursize);
+ // clear the write buffer
SZ_Clear(&msg_write);
}
@@ -767,7 +768,9 @@ static void write_datagram_new(client_t *client)
// send the datagram
cursize = client->netchan->Transmit(client->netchan,
- msg_write.cursize, msg_write.data, client->numpackets);
+ msg_write.cursize,
+ msg_write.data,
+ client->numpackets);
// record the size for rate estimation
SV_CalcSendTime(client, cursize);
diff --git a/src/sys_unix.c b/src/sys_unix.c
index d1d7dee..c8e371c 100644
--- a/src/sys_unix.c
+++ b/src/sys_unix.c
@@ -52,7 +52,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "vid_public.h"
#endif
#include "sys_public.h"
-#include "io_sleep.h"
+#include "net_sock.h"
cvar_t *sys_basedir;
cvar_t *sys_libdir;
@@ -205,7 +205,7 @@ static void tty_init_input(void)
static void tty_shutdown_input(void)
{
if (tty_io) {
- IO_Remove(STDIN_FILENO);
+ NET_RemoveFd(STDIN_FILENO);
tty_io = NULL;
}
if (tty_enabled) {
@@ -771,7 +771,7 @@ void Sys_Init(void)
fcntl(STDOUT_FILENO, F_SETFL, ret | O_NONBLOCK);
// add stdin to the list of descriptors to wait on
- tty_io = IO_Add(STDIN_FILENO);
+ tty_io = NET_AddFd(STDIN_FILENO);
tty_io->wantread = qtrue;
// init optional TTY support
diff --git a/src/wsaerr.h b/src/wsaerr.h
deleted file mode 100644
index e335db3..0000000
--- a/src/wsaerr.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-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.
-
-*/
-
-#define MAPERR(x) case x: return #x;
-
-MAPERR(WSAEINTR)
-MAPERR(WSAEBADF)
-MAPERR(WSAEACCES)
-MAPERR(WSAEFAULT)
-MAPERR(WSAEINVAL)
-MAPERR(WSAEMFILE)
-MAPERR(WSAEWOULDBLOCK)
-MAPERR(WSAEINPROGRESS)
-MAPERR(WSAEALREADY)
-MAPERR(WSAENOTSOCK)
-MAPERR(WSAEDESTADDRREQ)
-MAPERR(WSAEMSGSIZE)
-MAPERR(WSAEPROTOTYPE)
-MAPERR(WSAENOPROTOOPT)
-MAPERR(WSAEPROTONOSUPPORT)
-MAPERR(WSAESOCKTNOSUPPORT)
-MAPERR(WSAEOPNOTSUPP)
-MAPERR(WSAEPFNOSUPPORT)
-MAPERR(WSAEAFNOSUPPORT)
-MAPERR(WSAEADDRINUSE)
-MAPERR(WSAEADDRNOTAVAIL)
-MAPERR(WSAENETDOWN)
-MAPERR(WSAENETUNREACH)
-MAPERR(WSAENETRESET)
-MAPERR(WSAECONNABORTED)
-MAPERR(WSAECONNRESET)
-MAPERR(WSAENOBUFS)
-MAPERR(WSAEISCONN)
-MAPERR(WSAENOTCONN)
-MAPERR(WSAESHUTDOWN)
-MAPERR(WSAETOOMANYREFS)
-MAPERR(WSAETIMEDOUT)
-MAPERR(WSAECONNREFUSED)
-MAPERR(WSAELOOP)
-MAPERR(WSAENAMETOOLONG)
-MAPERR(WSAEHOSTDOWN)
-MAPERR(WSAEHOSTUNREACH)
-MAPERR(WSAENOTEMPTY)
-MAPERR(WSAEPROCLIM)
-MAPERR(WSAEUSERS)
-MAPERR(WSAEDQUOT)
-MAPERR(WSAESTALE)
-MAPERR(WSAEREMOTE)
-MAPERR(WSASYSNOTREADY)
-MAPERR(WSAVERNOTSUPPORTED)
-MAPERR(WSANOTINITIALISED)
-MAPERR(WSAEDISCON)
-MAPERR(WSAENOMORE)
-MAPERR(WSAECANCELLED)
-MAPERR(WSAEINVALIDPROCTABLE)
-MAPERR(WSAEINVALIDPROVIDER)
-MAPERR(WSAEPROVIDERFAILEDINIT)
-MAPERR(WSASYSCALLFAILURE)
-MAPERR(WSASERVICE_NOT_FOUND)
-MAPERR(WSATYPE_NOT_FOUND)
-MAPERR(WSA_E_NO_MORE)
-MAPERR(WSA_E_CANCELLED)
-MAPERR(WSAEREFUSED)
-MAPERR(WSAHOST_NOT_FOUND)
-MAPERR(WSATRY_AGAIN)
-MAPERR(WSANO_RECOVERY)
-MAPERR(WSANO_DATA)
-
-#undef MAPERR