Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
309 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/util/network/hawknl/CMakeLists.txt b/util/network/hawknl/CMakeLists.txt
new file mode 100644
index 00000000..d66c035a
--- /dev/null
+++ b/util/network/hawknl/CMakeLists.txt
@@ -0,0 +1,44 @@
+# -------------------------------------------------------
+# hawknl cmake build script for paintown.
+# Written by: juvinious
+# -------------------------------------------------------
+
+# -------------------------------------------------------
+# Set some specific stuff for hawknl
+# -------------------------------------------------------
+if(NOT MSVC)
+ set(CFLAGS "-W -O2 -Wwrite-strings -Wstrict-prototypes -Wall -funroll-loops -Wmissing-declarations -fomit-frame-pointer -Wno-missing-declarations")
+else(NOT MSVC)
+ set(CFLAGS "-O2")
+endif(NOT MSVC)
+
+remove_definitions(${CXXFLAGS})
+add_definitions(${CFLAGS})
+
+# -------------------------------------------------------
+# Source directories containing all the necessary .cpp files
+# -------------------------------------------------------
+set(SRC
+src/crc.c
+src/err.c
+src/errorstr.c
+src/group.c
+src/htcondition.c
+src/hthread.c
+src/htmutex.c
+src/ipx.c
+src/loopback.c
+src/nl.c
+src/nltime.c
+src/sock.c)
+
+# -------------------------------------------------------
+# Include directory
+# -------------------------------------------------------
+include_directories(include hawknl)
+
+# -------------------------------------------------------
+# module
+# -------------------------------------------------------
+add_library (hawknl_module ${SRC})
+
diff --git a/util/network/hawknl/SConscript b/util/network/hawknl/SConscript
new file mode 100644
index 00000000..bbea29e1
--- /dev/null
+++ b/util/network/hawknl/SConscript
@@ -0,0 +1,24 @@
+import os
+Import( 'env' )
+
+# env = Environment( ENV = os.environ )
+
+source = Split("""
+src/crc.c
+src/err.c
+src/errorstr.c
+src/group.c
+src/hthread.c
+src/htcondition.c
+src/ipx.c
+src/loopback.c
+src/htmutex.c
+src/nl.c
+src/nltime.c
+src/sock.c
+""");
+
+env.Append(CPPPATH = 'hawknl')
+
+x = env.StaticLibrary('hawknl', source)
+Return( 'x' )
diff --git a/util/network/hawknl/hawknl/hawklib.h b/util/network/hawknl/hawknl/hawklib.h
new file mode 100644
index 00000000..7e9952c3
--- /dev/null
+++ b/util/network/hawknl/hawknl/hawklib.h
@@ -0,0 +1,66 @@
+/*
+ HawkLib.h version 1.0
+ Copyright (C) 2003-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef HAWKLIB_H
+#define HAWKLIB_H
+
+#if defined (WIN32) || defined (WIN64) || defined (_WIN32_WCE)
+#define HL_WINDOWS_APP
+#endif
+
+#ifdef HL_WINDOWS_APP
+ #ifdef _MSC_VER
+ #pragma warning (disable:4514) /* disable "unreferenced inline function has
+ been removed" warning */
+ #endif /* _MSC_VER */
+ /* The default build for Windows is as a DLL. */
+ /* If you want a static library, define WIN_STATIC_LIB. */
+ #ifdef WIN_STATIC_LIB
+ #define HL_EXP
+ #else
+ #if defined (__LCC__)
+ #define HL_EXP extern
+ #else
+ #define HL_EXP __declspec(dllexport)
+ #endif /* __LCC__ */
+ #endif /* WIN_STATIC_LIB */
+ #define HL_APIENTRY __stdcall
+ #define HL_CALLBACK __cdecl
+ #ifdef __GNUC__
+ #define HL_INLINE extern __inline__
+ #else
+ #define HL_INLINE __inline
+ #endif /* __GNUC__ */
+#else /* !HL_WINDOWS_APP */
+ #define HL_EXP extern
+ #define HL_APIENTRY
+ #define HL_CALLBACK
+ #ifdef __GNUC__
+ #define HL_INLINE extern __inline__
+ #else
+ #define HL_INLINE inline /* assuming C99 compliant compiler */
+ #endif /* __GNUC__ */
+#endif /* !HL_WINDOWS_APP */
+
+
+#endif /* HAWKLIB_H */
+
diff --git a/util/network/hawknl/hawknl/hawkthreads.h b/util/network/hawknl/hawknl/hawkthreads.h
new file mode 100644
index 00000000..426caee9
--- /dev/null
+++ b/util/network/hawknl/hawknl/hawkthreads.h
@@ -0,0 +1,92 @@
+/*
+ HawkThreads cross platform network library
+ Copyright (C) 2003-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef HAWKTHREADS_H
+#define HAWKTHREADS_H
+
+#include "hawklib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HT_VERSION_STRING "HawkThreads 1.0"
+
+typedef void *(*HThreadFunc)(void *data);
+typedef void *HThreadID;
+typedef struct ht_mutex_t *HTmutex;
+typedef struct ht_cond_t *HTcond;
+
+#define HT_INVALID (-1)
+#define HT_FALSE (0)
+#define HT_TRUE (1)
+
+/*
+
+ Multithreading API
+
+*/
+
+/* returns HThreadID on success, or NULL on error */
+HL_EXP /*@null@*/ HThreadID HL_APIENTRY htThreadCreate(HThreadFunc func, void *data, int joinable);
+
+HL_EXP void HL_APIENTRY htThreadYield(void);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htThreadJoin(HThreadID threadID, /*@out@*/ void **status);
+
+HL_EXP void HL_APIENTRY htThreadSleep(int mseconds);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htMutexInit(/*@out@*/ HTmutex *mutex);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htMutexLock(HTmutex *mutex);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htMutexUnlock(HTmutex *mutex);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htMutexDestroy(/*@null@*/ HTmutex *mutex);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htCondInit(/*@out@*/ HTcond *cond);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htCondWait(HTcond *cond, int timeout);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htCondSignal(HTcond *cond);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htCondBroadcast(HTcond *cond);
+
+/* returns 0 on success, or an error number */
+HL_EXP int HL_APIENTRY htCondDestroy(/*@null@*/ HTcond *cond);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* HAWKTHREADS_H */
+
diff --git a/util/network/hawknl/hawknl/htinternal.h b/util/network/hawknl/hawknl/htinternal.h
new file mode 100644
index 00000000..94236c3e
--- /dev/null
+++ b/util/network/hawknl/hawknl/htinternal.h
@@ -0,0 +1,73 @@
+/*
+ HawkThreads cross platform thread library
+ Copyright (C) 2003-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef HTINTERNAL_H
+#define HTINTERNAL_H
+
+#include "hawkthreads.h"
+
+/* for malloc and free */
+#include <stdlib.h>
+#if !defined(MACOSX) && !defined(__FreeBSD__)
+#include <malloc.h>
+#endif
+#ifdef HL_WINDOWS_APP
+/* Windows systems */
+#ifdef _MSC_VER
+#pragma warning (disable:4201)
+#pragma warning (disable:4214)
+#endif /* _MSC_VER */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock.h>
+
+#ifdef _MSC_VER
+#pragma warning (default:4201)
+#pragma warning (default:4214)
+#endif /* _MSC_VER */
+
+#define HT_WIN_THREADS
+#define ETIMEDOUT WSAETIMEDOUT
+
+#endif /* HL_WINDOWS_APP */
+
+/* Windows CE has no errno.h file */
+#if defined (_WIN32_WCE)
+#define EPERM 1
+#define ENOMEM 12
+#define EINVAL 22
+#define EDEADLK 36
+#else
+#include <errno.h>
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* HTINTERNAL_H */
diff --git a/util/network/hawknl/hawknl/ipx.h b/util/network/hawknl/hawknl/ipx.h
new file mode 100644
index 00000000..9dc46283
--- /dev/null
+++ b/util/network/hawknl/hawknl/ipx.h
@@ -0,0 +1,55 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef IPX_H
+#define IPX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NLboolean ipx_Init(void);
+void ipx_Shutdown(void);
+NLsocket ipx_AcceptConnection(NLsocket socket);
+NLsocket ipx_Open(NLushort port, NLenum type);
+NLchar *ipx_AddrToString(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *string);
+NLboolean ipx_StringToAddr(const NLchar *string, /*@out@*/ NLaddress *address);
+NLboolean ipx_GetLocalAddr(NLsocket socket, /*@out@*/ NLaddress *address);
+NLaddress *ipx_GetAllLocalAddr(NLint *count);
+NLboolean ipx_SetLocalAddr(const NLaddress *address);
+NLchar *ipx_GetNameFromAddr(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *name);
+NLboolean ipx_GetNameFromAddrAsync(const NLaddress *address, /*@out@*/ NLchar *name);
+NLboolean ipx_GetAddrFromName(const NLchar *name, /*@out@*/ NLaddress *address);
+NLboolean ipx_GetAddrFromNameAsync(const NLchar *name, /*@out@*/ NLaddress *address);
+NLboolean ipx_AddrCompare(const NLaddress *address1, const NLaddress *address2);
+NLushort ipx_GetPortFromAddr(const NLaddress *address);
+void ipx_SetAddrPort(NLaddress *address, NLushort port);
+NLboolean ipx_Hint(NLenum name, NLint arg);
+NLboolean ipx_SetSocketOpt(NLsocket socket, NLenum name, NLint arg);
+NLint ipx_GetSocketOpt(NLsocket socket, NLenum name);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* IPX_H */
+
diff --git a/util/network/hawknl/hawknl/loopback.h b/util/network/hawknl/hawknl/loopback.h
new file mode 100644
index 00000000..85d420bc
--- /dev/null
+++ b/util/network/hawknl/hawknl/loopback.h
@@ -0,0 +1,63 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef LOOPBACK_H
+#define LOOPBACK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NLboolean loopback_Init(void);
+void loopback_Shutdown(void);
+NLboolean loopback_Listen(NLsocket socket);
+NLsocket loopback_AcceptConnection(NLsocket socket);
+NLsocket loopback_Open(NLushort port, NLenum type);
+NLboolean loopback_Connect(NLsocket socket, const NLaddress *address);
+void loopback_Close(NLsocket socket);
+NLint loopback_Read(NLsocket socket, /*@out@*/ NLvoid *buffer, NLint nbytes);
+NLint loopback_Write(NLsocket socket, const NLvoid *buffer, NLint nbytes);
+NLchar *loopback_AddrToString(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *string);
+NLboolean loopback_StringToAddr(const NLchar *string, /*@out@*/ NLaddress *address);
+NLboolean loopback_GetLocalAddr(/*@unused@*/ NLsocket socket, /*@out@*/ NLaddress *address);
+NLaddress *loopback_GetAllLocalAddr(/*@out@*/ NLint *count);
+NLboolean loopback_SetLocalAddr(/*@unused@*/ const NLaddress *address);
+NLchar *loopback_GetNameFromAddr(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *name);
+NLboolean loopback_GetNameFromAddrAsync(const NLaddress *address, /*@out@*/ NLchar *name);
+NLboolean loopback_GetAddrFromName(const NLchar *name, /*@out@*/ NLaddress *address);
+NLboolean loopback_GetAddrFromNameAsync(const NLchar *name, /*@out@*/ NLaddress *address);
+NLboolean loopback_AddrCompare(const NLaddress *address1, const NLaddress *address2);
+NLushort loopback_GetPortFromAddr(const NLaddress *address);
+void loopback_SetAddrPort(NLaddress *address, NLushort port);
+NLint loopback_GetSystemError(void);
+NLint loopback_PollGroup(NLint group, NLenum name, /*@out@*/ NLsocket *sockets, NLint number, NLint timeout);
+NLboolean loopback_PollSocket(NLsocket socket, NLenum name, NLint timeout);
+NLboolean loopback_Hint(NLenum name, NLint arg);
+NLboolean loopback_SetSocketOpt(NLsocket socket, NLenum name, NLint arg);
+NLint loopback_GetSocketOpt(NLsocket socket, NLenum name);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LOOPBACK_H */
+
diff --git a/util/network/hawknl/hawknl/nl.h b/util/network/hawknl/hawknl/nl.h
new file mode 100644
index 00000000..262a7e10
--- /dev/null
+++ b/util/network/hawknl/hawknl/nl.h
@@ -0,0 +1,485 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef NL_H
+#define NL_H
+
+#include <string.h> /* for strcpy, strlen, and memcpy in macros */
+#include "hawklib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NL_MAJOR_VERSION 1
+#define NL_MINOR_VERSION 7
+#define NL_VERSION_STRING "HawkNL 1.7 beta 1"
+
+/* define NL_SAFE_COPY for Sparc and other processors that do not allow non-aligned
+ memory access. Needed for read* and write* macros */
+/*#define NL_SAFE_COPY */
+
+#ifdef HL_WINDOWS_APP
+/* undefine this to remove IPX code, Windows only */
+#define NL_INCLUDE_IPX
+#endif
+
+/* undefine this to remove loopback code */
+#define NL_INCLUDE_LOOPBACK
+
+/* undefine this to remove serial code */
+#define NL_INCLUDE_SERIAL
+
+/* undefine this to remove modem code */
+#define NL_INCLUDE_MODEM
+
+/* undefine this to remove parallel code */
+#define NL_INCLUDE_PARALLEL
+
+
+/* many CE devices will not allow non-aligned memory access */
+#if defined (_WIN32_WCE)
+#define NL_SAFE_COPY
+#undef NL_INCLUDE_IPX
+#endif
+
+
+/* Any more needed here? */
+#if defined WIN32 || defined WIN64 || defined __i386__ || defined __alpha__ || defined __mips__
+#define NL_LITTLE_ENDIAN
+#else
+#define NL_BIG_ENDIAN
+#endif
+
+/* How do we detect Solaris 64 and Linux 64 bit? */
+#if defined WIN64
+#define IS_64_BIT
+#endif
+
+/* 8 bit */
+typedef char NLbyte;
+typedef unsigned char NLubyte;
+typedef unsigned char NLboolean;
+/* 16 bit */
+typedef short NLshort;
+typedef unsigned short NLushort;
+/* 32 bit */
+typedef float NLfloat;
+#ifdef IS_64_BIT
+typedef int NLlong; /* Longs are 64 bit on a 64 bit CPU, but integers are still 32 bit. */
+typedef unsigned int NLulong; /* This is, of course, not true on Windows (yet another exception), */
+ /* but it does not hurt. */
+#else
+typedef long NLlong;
+typedef unsigned long NLulong;
+#endif
+/* 64 bit */
+typedef double NLdouble;
+/* misc. */
+typedef int NLint;
+typedef unsigned int NLuint;
+typedef unsigned int NLenum;
+typedef void NLvoid;
+typedef NLlong NLsocket;
+/* NOTE: NLchar is only to be used for external strings that might be unicode */
+#if defined _UNICODE
+typedef wchar_t NLchar;
+#else
+typedef char NLchar;
+#endif
+
+typedef struct _NLaddress
+{
+ NLubyte addr[32]; /* large enough to hold IPv6 address */
+ NLenum driver; /* driver type */
+ NLboolean valid; /* set to NL_TRUE when address is valid */
+} NLaddress;
+
+/* for backwards compatability */
+#if !defined(address_t)
+ typedef struct _NLaddress address_t;
+#endif
+
+ typedef struct _NLtime
+ {
+ NLlong seconds; /* seconds since 12:00AM, 1 January, 1970 */
+ NLlong mseconds; /* milliseconds added to the seconds */
+ NLlong useconds; /* microseconds added to the seconds */
+ } NLtime;
+
+/* max string size limited to 256 (255 plus NULL termination) for MacOS */
+#define NL_MAX_STRING_LENGTH 256
+
+/* max packet size for NL_UDP* and NL_TCP_PACKETS */
+#define NL_MAX_PACKET_LENGTH 16384
+
+/* max number groups and sockets per group */
+#define NL_MAX_GROUPS 128
+
+#if defined (macintosh)
+/* WARNING: Macs only allow up to 32K of local data, don't exceed 4096 */
+/* Does NOT apply to Mac OSX */
+#define NL_MAX_GROUP_SOCKETS 4096
+#else
+/* max number of sockets per group NL will handle */
+#define NL_MAX_GROUP_SOCKETS 8192
+#endif
+
+#define NL_INVALID (-1)
+
+/* Boolean values */
+#define NL_FALSE ((NLboolean)(0))
+#define NL_TRUE ((NLboolean)(1))
+
+/* Network types */
+/* Only one can be selected at a time */
+#define NL_IP 0x0003 /* all platforms */
+#define NL_IPV6 0x0004 /* not yet implemented, IPv6 address family */
+#define NL_LOOP_BACK 0x0005 /* all platforms, for single player client/server emulation with no network */
+#define NL_IPX 0x0006 /* Windows only */
+#define NL_SERIAL 0x0007 /* not yet implemented, Windows and Linux only? */
+#define NL_MODEM 0x0008 /* not yet implemented, Windows and Linux only? */
+#define NL_PARALLEL 0x0009 /* not yet implemented, Windows and Linux only? */
+
+/* Socket types */
+#define NL_TCP 0x0010 /* NL_IP (TCP), NL_IPX (SPX), NL_LOOP_BACK */
+#define NL_TCP_PACKETS 0x0011 /* NL_IP (TCP), NL_IPX (SPX), NL_LOOP_BACK */
+#define NL_UDP 0x0012 /* NL_IP (UDP), NL_IPX, NL_LOOP_BACK */
+#define NL_UDP_BROADCAST 0x0013 /* NL_IP (UDP), NL_IPX, NL_LOOP_BACK */
+#define NL_UDP_MULTICAST 0x0014 /* NL_IP (UDP) */
+#define NL_RAW 0x0015 /* NL_SERIAL or NL_PARALLEL */
+#define NL_UDP_ENHANCED 0x0016 /* NL_IP (UDP), NL_LOOP_BACK */
+
+/* for backwards compatability */
+#define NL_RELIABLE NL_TCP
+#define NL_UNRELIABLE NL_UDP
+#define NL_RELIABLE_PACKETS NL_TCP_PACKETS
+#define NL_BROADCAST NL_UDP_BROADCAST
+#define NL_MULTICAST NL_UDP_MULTICAST
+
+/* nlGetString */
+#define NL_VERSION 0x0020 /* the version string */
+#define NL_NETWORK_TYPES 0x0021 /* space delimited list of available network types */
+#define NL_SOCKET_TYPES 0x0022 /* space delimited list of available socket types */
+ /* only valid AFTER nlSelectNetwork */
+/* for backwards compatability */
+#define NL_CONNECTION_TYPES NL_SOCKET_TYPES
+
+/* nlGetInteger, nlGetSocketStat, nlClear */
+#define NL_PACKETS_SENT 0x0030 /* total packets sent since last nlClear */
+#define NL_BYTES_SENT 0x0031 /* total bytes sent since last nlClear */
+#define NL_AVE_BYTES_SENT 0x0032 /* average bytes sent per second for the last 8 seconds */
+#define NL_HIGH_BYTES_SENT 0x0033 /* highest bytes per second ever sent */
+#define NL_PACKETS_RECEIVED 0x0034 /* total packets received since last nlClear */
+#define NL_BYTES_RECEIVED 0x0035 /* total bytes received since last nlClear */
+#define NL_AVE_BYTES_RECEIVED 0x0036 /* average bytes received per second for the last 8 seconds */
+#define NL_HIGH_BYTES_RECEIVED 0x0037 /* highest bytes per second ever received */
+#define NL_ALL_STATS 0x0038 /* nlClear only, clears out all counters */
+#define NL_OPEN_SOCKETS 0x0039 /* number of open sockets */
+
+/* nlEnable, nlDisable, nlSetSocketOpt, nlGetSocketOpt */
+#define NL_BLOCKING_IO 0x0040 /* set IO to blocking, default is NL_FALSE for non-blocking IO */
+
+/* nlEnable, nlDisable */
+#define NL_SOCKET_STATS 0x0041 /* enable collection of socket read/write statistics, default disabled */
+#define NL_BIG_ENDIAN_DATA 0x0042 /* enable big endian data for nlSwap* and read/write macros, default enabled */
+#define NL_LITTLE_ENDIAN_DATA 0x0043 /* enable little endian data for nlSwap* and read/write macros, default disabled */
+#define NL_MULTIPLE_DRIVERS 0x0044 /* enable multiple drivers to be selected */
+
+/* nlPollGroup */
+#define NL_READ_STATUS 0x0050 /* poll the read status for all sockets in the group */
+#define NL_WRITE_STATUS 0x0051 /* poll the write status for all sockets in the group */
+#define NL_ERROR_STATUS 0x0052 /* poll the error status for all sockets in the group */
+
+/* nlHint, advanced network settings for experienced developers */
+#define NL_LISTEN_BACKLOG 0x0060 /* TCP, SPX: the backlog of connections for listen */
+
+/* nlHint, nlSetSocketOpt, nlGetSocketOpt, advanced network settings for experienced developers */
+#define NL_MULTICAST_TTL 0x0061 /* UDP : The multicast TTL value. Default : 1 */
+#define NL_REUSE_ADDRESS 0x0062 /* TCP, UDP : Allow IP address to be reused. Default : NL_FALSE */
+#define NL_TCP_NO_DELAY 0x0063 /* TCP : disable Nagle algorithm, arg != 0 to disable, 0 to enable */
+
+/* errors */
+#define NL_NO_ERROR 0x0000 /* no error is stored */
+#define NL_NO_NETWORK 0x0100 /* no network was found on init or no network is selected */
+#define NL_OUT_OF_MEMORY 0x0101 /* out of memory */
+#define NL_INVALID_ENUM 0x0102 /* function called with an invalid NLenum */
+#define NL_INVALID_SOCKET 0x0103 /* socket is not valid, or has been terminated */
+#define NL_INVALID_PORT 0x0104 /* the port could not be opened */
+#define NL_INVALID_TYPE 0x0105 /* the network type is not available */
+#define NL_SYSTEM_ERROR 0x0106 /* a system error occurred, call nlGetSystemError */
+#define NL_SOCK_DISCONNECT 0x0107 /* the socket should be closed because of a connection loss or error */
+#define NL_NOT_LISTEN 0x0108 /* the socket has not been set to listen */
+#define NL_CON_REFUSED 0x0109 /* connection refused, or socket already connected */
+#define NL_NO_PENDING 0x010a /* there are no pending connections to accept */
+#define NL_BAD_ADDR 0x010b /* the address or port are not valid */
+#define NL_MESSAGE_END 0x010c /* the end of a reliable stream (TCP) message has been reached */
+#define NL_NULL_POINTER 0x010d /* a NULL pointer was passed to a function */
+#define NL_INVALID_GROUP 0x010e /* the group is not valid, or has been destroyed */
+#define NL_OUT_OF_GROUPS 0x010f /* out of internal group objects */
+#define NL_OUT_OF_GROUP_SOCKETS 0x0110 /* the group has no more room for sockets */
+#define NL_BUFFER_SIZE 0x0111 /* the buffer was too small to store the data, retry with a larger buffer */
+#define NL_PACKET_SIZE 0x0112 /* the size of the packet exceeds NL_MAX_PACKET_LENGTH or the protocol max */
+#define NL_WRONG_TYPE 0x0113 /* the function does not support the socket type */
+#define NL_CON_PENDING 0x0114 /* a non-blocking connection is still pending */
+#define NL_SELECT_NET_ERROR 0x0115 /* a network is already selected, and NL_MULTIPLE_DRIVERS is not enabled, call nlShutDown and nlInit first */
+#define NL_PACKET_SYNC 0x0116 /* the NL_RELIABLE_PACKET stream is out of sync */
+#define NL_TLS_ERROR 0x0117 /* thread local storage could not be created */
+#define NL_TIMED_OUT 0x0118 /* the function timed out */
+#define NL_SOCKET_NOT_FOUND 0x0119 /* the socket was not found in the group */
+#define NL_STRING_OVER_RUN 0x011a /* the string is not null terminated, or is longer than NL_MAX_STRING_LENGTH */
+#define NL_CONNECTED 0x011b /* the socket is already connected */
+/* for backwards compatability */
+#define NL_SOCKET_ERROR NL_SYSTEM_ERROR
+#define NL_CON_TERM NL_SOCK_DISCONNECT
+
+/* standard multicast TTL settings as recommended by the */
+/* white paper at http://www.ipmulticast.com/community/whitepapers/howipmcworks.html */
+#define NL_TTL_LOCAL 1 /* local LAN only */
+#define NL_TTL_SITE 15 /* this site */
+#define NL_TTL_REGION 63 /* this region */
+#define NL_TTL_WORLD 127 /* the world */
+
+/*
+
+ Low level API, a thin layer over Sockets or other network provider.
+
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlListen(NLsocket socket);
+
+HL_EXP NLsocket HL_APIENTRY nlAcceptConnection(NLsocket socket);
+
+HL_EXP NLsocket HL_APIENTRY nlOpen(NLushort port, NLenum type);
+
+HL_EXP NLboolean HL_APIENTRY nlConnect(NLsocket socket, const NLaddress *address);
+
+HL_EXP NLboolean HL_APIENTRY nlClose(NLsocket socket);
+
+HL_EXP NLint HL_APIENTRY nlRead(NLsocket socket, /*@out@*/ NLvoid *buffer, NLint nbytes);
+
+HL_EXP NLint HL_APIENTRY nlWrite(NLsocket socket, const NLvoid *buffer, NLint nbytes);
+
+HL_EXP NLlong HL_APIENTRY nlGetSocketStat(NLsocket socket, NLenum name);
+
+HL_EXP NLboolean HL_APIENTRY nlClearSocketStat(NLsocket socket, NLenum name);
+
+HL_EXP NLint HL_APIENTRY nlPollGroup(NLint group, NLenum name, /*@out@*/ NLsocket *sockets, NLint number, NLint timeout);
+
+HL_EXP NLboolean HL_APIENTRY nlPollSocket(NLsocket socket, NLenum name, NLint timeout);
+
+HL_EXP NLboolean HL_APIENTRY nlHint(NLenum name, NLint arg);
+
+HL_EXP NLboolean HL_APIENTRY nlSetSocketOpt(NLsocket socket, NLenum name, NLint arg);
+
+HL_EXP NLint HL_APIENTRY nlGetSocketOpt(NLsocket socket, NLenum name);
+
+/*
+
+ Address management API
+
+*/
+
+HL_EXP /*@null@*/ NLchar* HL_APIENTRY nlAddrToString(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *string);
+
+HL_EXP NLboolean HL_APIENTRY nlStringToAddr(const NLchar *string, /*@out@*/ NLaddress *address);
+
+HL_EXP NLboolean HL_APIENTRY nlGetRemoteAddr(NLsocket socket, /*@out@*/ NLaddress *address);
+
+HL_EXP NLboolean HL_APIENTRY nlSetRemoteAddr(NLsocket socket, const NLaddress *address);
+
+HL_EXP NLboolean HL_APIENTRY nlGetLocalAddr(NLsocket socket, /*@out@*/ NLaddress *address);
+
+HL_EXP NLaddress* HL_APIENTRY nlGetAllLocalAddr(/*@out@*/ NLint *count);
+
+HL_EXP NLboolean HL_APIENTRY nlSetLocalAddr(const NLaddress *address);
+
+HL_EXP /*@null@*/ NLchar* HL_APIENTRY nlGetNameFromAddr(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *name);
+
+HL_EXP NLboolean HL_APIENTRY nlGetNameFromAddrAsync(const NLaddress *address, /*@out@*/ NLchar *name);
+
+HL_EXP NLboolean HL_APIENTRY nlGetAddrFromName(const NLchar *name, /*@out@*/ NLaddress *address);
+
+HL_EXP NLboolean HL_APIENTRY nlGetAddrFromNameAsync(const NLchar *name, /*@out@*/ NLaddress *address);
+
+HL_EXP NLboolean HL_APIENTRY nlAddrCompare(const NLaddress *address1, const NLaddress *address2);
+
+HL_EXP NLushort HL_APIENTRY nlGetPortFromAddr(const NLaddress *address);
+
+HL_EXP NLboolean HL_APIENTRY nlSetAddrPort(NLaddress *address, NLushort port);
+
+
+/*
+
+ Group management API
+
+*/
+
+HL_EXP NLint HL_APIENTRY nlGroupCreate(void);
+
+HL_EXP NLboolean HL_APIENTRY nlGroupDestroy(NLint group);
+
+HL_EXP NLboolean HL_APIENTRY nlGroupAddSocket(NLint group, NLsocket socket);
+
+HL_EXP NLboolean HL_APIENTRY nlGroupGetSockets(NLint group, /*@out@*/ NLsocket *sockets, /*@in@*/ NLint *number);
+
+HL_EXP NLboolean HL_APIENTRY nlGroupDeleteSocket(NLint group, NLsocket socket);
+
+/*
+
+ Time API
+
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlTime(/*@out@*/ NLtime *ts);
+
+/*
+
+ Misc. API
+
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlInit(void);
+
+HL_EXP void HL_APIENTRY nlShutdown(void);
+
+HL_EXP NLboolean HL_APIENTRY nlSelectNetwork(NLenum network);
+
+HL_EXP const /*@observer@*//*@null@*/ NLchar* HL_APIENTRY nlGetString(NLenum name);
+
+HL_EXP NLlong HL_APIENTRY nlGetInteger(NLenum name);
+
+HL_EXP NLboolean HL_APIENTRY nlGetBoolean(NLenum name);
+
+HL_EXP NLboolean HL_APIENTRY nlClear(NLenum name);
+
+HL_EXP NLenum HL_APIENTRY nlGetError(void);
+
+HL_EXP const /*@observer@*/ NLchar* HL_APIENTRY nlGetErrorStr(NLenum err);
+
+HL_EXP NLint HL_APIENTRY nlGetSystemError(void);
+
+HL_EXP const /*@observer@*/ NLchar* HL_APIENTRY nlGetSystemErrorStr(NLint err);
+
+HL_EXP NLboolean HL_APIENTRY nlEnable(NLenum name);
+
+HL_EXP NLboolean HL_APIENTRY nlDisable(NLenum name);
+
+HL_EXP NLushort HL_APIENTRY nlGetCRC16(NLubyte *data, NLint len);
+
+HL_EXP NLulong HL_APIENTRY nlGetCRC32(NLubyte *data, NLint len);
+
+HL_EXP NLushort HL_APIENTRY nlSwaps(NLushort x);
+
+HL_EXP NLulong HL_APIENTRY nlSwapl(NLulong x);
+
+HL_EXP NLfloat HL_APIENTRY nlSwapf(NLfloat f);
+
+HL_EXP NLdouble HL_APIENTRY nlSwapd(NLdouble d);
+
+
+/* macros for writing/reading packet buffers */
+/* NOTE: these also endian swap the data as needed */
+/* write* or read* (buffer *, count, data [, length]) */
+
+#ifdef NL_SAFE_COPY
+#define writeShort(x, y, z) {NLushort nl_temps = nlSwaps(z); memcpy((char *)&x[y], (char *)&nl_temps, 2); y += 2;}
+#define writeLong(x, y, z) {NLulong nl_templ = nlSwapl(z); memcpy((char *)&x[y], (char *)&nl_templ, 4); y += 4;}
+#define writeFloat(x, y, z) {NLfloat nl_tempf = nlSwapf(z); memcpy((char *)&x[y], (char *)&nl_tempf, 4); y += 4;}
+#define writeDouble(x, y, z) {NLdouble nl_tempd = nlSwapd(z); memcpy((char *)&x[y], (char *)&nl_tempd, 8); y += 8;}
+#define readShort(x, y, z) {memcpy((char *)&z, (char *)&x[y], 2); z = nlSwaps(z); y += 2;}
+#define readLong(x, y, z) {memcpy((char *)&z, (char *)&x[y], 4); z = nlSwapl(z); y += 4;}
+#define readFloat(x, y, z) {memcpy((char *)&z, (char *)&x[y], 4); z = nlSwapf(z); y += 4;}
+#define readDouble(x, y, z) {memcpy((char *)&z, (char *)&x[y], 8); z = nlSwapd(z); y += 8;}
+
+#else /* !NL_SAFE_COPY */
+#define writeShort(x, y, z) {*((NLushort *)((NLbyte *)&x[y])) = nlSwaps(z); y += 2;}
+#define writeLong(x, y, z) {*((NLulong *)((NLbyte *)&x[y])) = nlSwapl(z); y += 4;}
+#define writeFloat(x, y, z) {*((NLfloat *)((NLbyte *)&x[y])) = nlSwapf(z); y += 4;}
+#define writeDouble(x, y, z) {*((NLdouble *)((NLbyte *)&x[y])) = nlSwapd(z); y += 8;}
+#define readShort(x, y, z) {z = nlSwaps(*(NLushort *)((NLbyte *)&x[y])); y += 2;}
+#define readLong(x, y, z) {z = nlSwapl(*(NLulong *)((NLbyte *)&x[y])); y += 4;}
+#define readFloat(x, y, z) {z = nlSwapf(*(NLfloat *)((NLbyte *)&x[y])); y += 4;}
+#define readDouble(x, y, z) {z = nlSwapd(*(NLdouble *)((NLbyte *)&x[y])); y += 8;}
+#endif /* !NL_SAFE_COPY */
+
+#define writeByte(x, y, z) (*(NLbyte *)&x[y++] = (NLbyte)z)
+#define writeBlock(x, y, z, a) {memcpy((char *)&x[y], (char *)z, a);y += a;}
+#define readByte(x, y, z) (z = *(NLbyte *)&x[y++])
+#define readBlock(x, y, z, a) {memcpy((char *)z, (char *)&x[y], a);y += a;}
+
+#ifdef _UNICODE
+#include <stdlib.h>
+
+#define writeString(x, y, z) writeStringWC(x, &y, z)
+#define readString(x, y, z) readStringWC(x, &y, z)
+
+HL_INLINE void writeStringWC(NLbyte *x, NLint *y, NLchar *z)
+{
+ int len = (int)wcstombs(&x[*y], z, (size_t)NL_MAX_STRING_LENGTH);
+
+ if(len == NL_MAX_STRING_LENGTH)
+ {
+ /* must null terminate string */
+ x[*y + NL_MAX_STRING_LENGTH - 1] = '\0';
+ *y += NL_MAX_STRING_LENGTH;
+ }
+ else if(len > 0)
+ {
+ *y += (len + 1);
+ }
+ else
+ {
+ /* there was an error in wcstombs, so just add a 0 length string to the buffer */
+ x[*y] = '\0';
+ *y++;
+ }
+}
+
+HL_INLINE void readStringWC(NLbyte *x, NLint *y, NLchar *z)
+{
+ int len = (int)mbstowcs(z, &x[*y], (size_t)NL_MAX_STRING_LENGTH);
+
+ if(len == NL_MAX_STRING_LENGTH)
+ {
+ /* must null terminate string */
+ z[NL_MAX_STRING_LENGTH - 1] = L'\0';
+ }
+ else if(len < 0)
+ {
+ /* must null terminate string */
+ z[0] = L'\0';
+ }
+ *y += (strlen((char *)&x[*y]) + 1);
+}
+
+#else /* !_UNICODE */
+#define writeString(x, y, z) {strcpy((char *)&x[y], (char *)z); y += (strlen((char *)z) + 1);}
+#define readString(x, y, z) {strcpy((char *)z, (char *)&x[y]); y += (strlen((char *)z) + 1);}
+#endif /* !_UNICODE */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* NL_H */
+
diff --git a/util/network/hawknl/hawknl/nlinternal.h b/util/network/hawknl/hawknl/nlinternal.h
new file mode 100644
index 00000000..ce8e7a0f
--- /dev/null
+++ b/util/network/hawknl/hawknl/nlinternal.h
@@ -0,0 +1,269 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef INTERNAL_H
+#define INTERNAL_H
+
+#include "nl.h"
+#include "hawkthreads.h"
+
+/* for malloc and free */
+#include <stdlib.h>
+#if !defined(MACOSX) && !defined(__FreeBSD__)
+#include <malloc.h>
+#endif
+
+/* Windows CE does not have time.h functions */
+#if defined (_WIN32_WCE)
+extern time_t time(time_t *timer);
+#else
+#include <time.h>
+#endif
+
+
+#ifdef NL_LITTLE_ENDIAN
+#define NL_SWAP_TRUE (nlState.nl_big_endian_data == NL_TRUE)
+#else
+#define NL_SWAP_TRUE (nlState.nl_big_endian_data != NL_TRUE)
+#endif /* NL_LITTLE_ENDIAN */
+
+#ifdef HL_WINDOWS_APP
+/* Windows systems */
+#ifdef _MSC_VER
+#pragma warning (disable:4201)
+#pragma warning (disable:4214)
+#endif /* _MSC_VER */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <tchar.h>
+
+#ifdef _MSC_VER
+#pragma warning (default:4201)
+#pragma warning (default:4214)
+#endif /* _MSC_VER */
+
+#endif
+
+/* part of portable unicode support */
+#if !defined _TCHAR_DEFINED && !(defined _WCHAR_T_DEFINED && defined (__LCC__))
+#ifdef _UNICODE
+#define TEXT(x) L##x
+#define _tcsncat wcsncat
+#define _stprintf swprintf
+#define _sntprintf snwprintf
+#define _stscanf swscanf
+#define _tcsncpy wcsncpy
+#define _tcscspn wcscspn
+#define _tcschr wcschr
+#define _tcslen wcslen
+#define _tcsrchr wcsrchr
+#ifdef HL_WINDOWS_APP
+#define _ttoi _wtoi
+#else /* !HL_WINDOWS_APP*/
+#define _ttoi wtoi
+#endif /* !HL_WINDOWS_APP*/
+#else /* !UNICODE */
+#define TEXT(x) x
+#define _tcsncat strncat
+#define _stprintf sprintf
+#define _sntprintf snprintf
+#define _stscanf sscanf
+#define _tcsncpy strncpy
+#define _tcscspn strcspn
+#define _tcschr strchr
+#define _tcslen strlen
+#define _ttoi atoi
+#define _tcsrchr strrchr
+#endif /* !UNICODE */
+#endif /* _INC_TCHAR */
+
+/* internally for TCP packets and UDP connections, all data is big endien,
+ so we force it so here using these macros */
+#undef writeShort
+#define writeShort(x, y, z) {*((NLushort *)((NLbyte *)&x[y])) = htons(z); y += 2;}
+#undef readShort
+#define readShort(x, y, z) {z = ntohs(*(NLushort *)((NLbyte *)&x[y])); y += 2;}
+
+#define NL_FIRST_GROUP (200000 + 1)
+
+/* the minumum number of sockets that will be allocated */
+#define NL_MIN_SOCKETS 16
+
+/* number of buckets for average bytes/second */
+#define NL_NUM_BUCKETS 8
+
+/* number of packets stored for NL_LOOP_BACK */
+#define NL_NUM_PACKETS 8
+#define NL_MAX_ACCEPT 10
+
+/* for nlLockSocket and nlUnlockSocket */
+#define NL_READ 0x0001
+#define NL_WRITE 0x0002
+#define NL_BOTH (NL_READ|NL_WRITE)
+
+/* time in milliseconds that unreliable connect/accepts sleep while waiting */
+#define NL_CONNECT_SLEEP 50
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* the driver object */
+typedef struct
+{
+ const NLchar /*@observer@*/*name;
+ const NLchar /*@observer@*/*socktypes;
+ NLenum type;
+ NLboolean initialized;
+ NLboolean (*Init)(void);
+ void (*Shutdown)(void);
+ NLboolean (*Listen)(NLsocket socket);
+ NLsocket (*AcceptConnection)(NLsocket socket);
+ NLsocket (*Open)(NLushort port, NLenum type);
+ NLboolean (*Connect)(NLsocket socket, const NLaddress *address);
+ void (*Close)(NLsocket socket);
+ NLint (*Read)(NLsocket socket, /*@out@*/ NLvoid *buffer, NLint nbytes);
+ NLint (*Write)(NLsocket socket, const NLvoid *buffer, NLint nbytes);
+ NLchar *(*AddrToString)(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *string);
+ NLboolean (*StringToAddr)(const NLchar *string, /*@out@*/ NLaddress *address);
+ NLboolean (*GetLocalAddr)(NLsocket socket, /*@out@*/ NLaddress *address);
+ NLaddress *(*GetAllLocalAddr)(/*@out@*/ NLint *count);
+ NLboolean (*SetLocalAddr)(const NLaddress *address);
+ NLchar *(*GetNameFromAddr)(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *name);
+ NLboolean (*GetNameFromAddrAsync)(const NLaddress *address, /*@out@*/ NLchar *name);
+ NLboolean (*GetAddrFromName)(const NLchar *name, /*@out@*/ NLaddress *address);
+ NLboolean (*GetAddrFromNameAsync)(const NLchar *name, /*@out@*/ NLaddress *address);
+ NLboolean (*AddrCompare)(const NLaddress *address1, const NLaddress *address2);
+ NLushort (*GetPortFromAddr)(const NLaddress *address);
+ void (*SetAddrPort)(NLaddress *address, NLushort port);
+ NLint (*GetSystemError)(void);
+ NLint (*PollGroup)(NLint group, NLenum name, /*@out@*/ NLsocket *sockets,
+ NLint number, NLint timeout);
+ NLboolean (*PollSocket)(NLsocket socket, NLenum name, NLint timeout);
+ NLboolean (*Hint)(NLenum name, NLint arg);
+ NLboolean (*SetSocketOpt)(NLsocket socket, NLenum name, NLint arg);
+ NLint (*GetSocketOpt)(NLsocket socket, NLenum name);
+} nl_netdriver_t;
+
+typedef struct
+{
+ NLlong bytes; /* bytes sent/received */
+ NLlong packets; /* packets sent/received */
+ NLlong highest; /* highest bytes/sec sent/received */
+ NLlong average; /* average bytes/sec sent/received */
+ time_t stime; /* the last time stats were updated */
+ NLint lastbucket; /* the last bucket that was used */
+ NLlong curbytes; /* current bytes sent/received */
+ NLlong bucket[NL_NUM_BUCKETS];/* buckets for sent/received counts */
+ NLboolean firstround; /* is this the first round through the buckets? */
+} nl_stats_t;
+
+typedef struct
+{
+ /* info for NL_LOOP_BACK, NL_SERIAL, and NL_PARALLEL */
+ NLbyte *outpacket[NL_NUM_PACKETS];/* temp storage for packet data */
+ NLbyte *inpacket[NL_NUM_PACKETS];/* temp storage for packet data */
+ NLint outlen[NL_NUM_PACKETS];/* the length of each packet */
+ NLint inlen[NL_NUM_PACKETS];/* the length of each packet */
+ NLint nextoutused; /* the next used packet */
+ NLint nextinused; /* the next used packet */
+ NLint nextoutfree; /* the next free packet */
+ NLint nextinfree; /* the next free packet */
+ NLsocket accept[NL_MAX_ACCEPT];/* pending connects */
+ NLsocket consock; /* the socket this socket is connected to */
+} nl_extra_t;
+
+/* the internal socket object */
+typedef struct
+{
+ /* the current status of the socket */
+ NLenum driver; /* the driver used with this socket */
+ NLenum type; /* type of socket */
+ NLboolean inuse; /* is in use */
+ NLboolean connecting; /* a non-blocking TCP or UDP connection is in process */
+ NLboolean conerror; /* an error occured on a UDP connect */
+ NLboolean connected; /* is connected */
+ NLboolean reliable; /* do we use reliable */
+ NLboolean blocking; /* is set to blocking */
+ NLboolean listen; /* can receive an incoming connection */
+ NLboolean reuseaddr; /* can we reuse the address */
+ NLboolean TCPNoDelay; /* disable Nagle on TCP */
+ NLint TTL; /* TTL for multicast */
+ NLint realsocket; /* the real socket number */
+ NLushort localport; /* local port number */
+ NLushort remoteport; /* remote port number */
+ NLaddress addressin; /* address of remote system, same as the socket sockaddr_in structure */
+ NLaddress addressout; /* the multicast address set by nlConnect or the remote address for unconnected UDP */
+ HTmutex readlock; /* socket is locked to update data */
+ HTmutex writelock; /* socket is locked to update data */
+
+ /* the current read/write statistics for the socket */
+ nl_stats_t instats; /* stats for received */
+ nl_stats_t outstats; /* stats for sent */
+
+ /* NL_RELIABLE_PACKETS info and storage */
+ NLbyte *outbuf; /* temp storage for partially sent reliable packet data */
+ NLint outbuflen; /* the length of outbuf */
+ NLint sendlen; /* how much still needs to be sent */
+ NLbyte *inbuf; /* temp storage for partially received reliable packet data */
+ NLint inbuflen; /* the length of inbuf */
+ NLint reclen; /* how much of the reliable packet we have received */
+ NLboolean readable; /* a complete packet is in inbuf */
+ NLboolean message_end; /* a message end error ocured but was not yet reported */
+ NLboolean packetsync; /* is the reliable packet stream in sync */
+ /* pointer to extra info needed for NL_LOOP_BACK, NL_SERIAL, and NL_PARALLEL */
+ nl_extra_t *ext;
+} nl_socket_t;
+
+typedef struct
+{
+ NLboolean socketStats; /* enable collection of socket read/write statistics, default disabled */
+ NLboolean nl_big_endian_data; /* is the packet data big endian? */
+} nl_state_t;
+
+/* used by the drivers to allocate and free socket objects */
+NLsocket nlGetNewSocket(void);
+
+/* other functions */
+NLboolean nlGroupInit(void);
+void nlGroupShutdown(void);
+void nlGroupLock(void);
+void nlGroupUnlock(void);
+NLboolean nlGroupGetSocketsINT(NLint group, /*@out@*/ NLsocket *socket, /*@in@*/ NLint *number);
+NLboolean nlIsValidSocket(NLsocket socket);
+NLboolean nlLockSocket(NLsocket socket, NLint which);
+void nlUnlockSocket(NLsocket socket, NLint which);
+void nlSetError(NLenum err);
+
+/* globals (as few as possible) */
+extern volatile nl_state_t nlState;
+
+typedef /*@only@*/ nl_socket_t *pnl_socket_t;
+extern /*@only@*/ pnl_socket_t *nlSockets;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* INTERNAL_H */
+
diff --git a/util/network/hawknl/hawknl/parallel.h b/util/network/hawknl/hawknl/parallel.h
new file mode 100644
index 00000000..f7e71ea6
--- /dev/null
+++ b/util/network/hawknl/hawknl/parallel.h
@@ -0,0 +1,62 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef PARALLEL_H
+#define PARALLEL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NLboolean parallel_Init(void);
+void parallel_Shutdown(void);
+NLboolean parallel_Listen(NLsocket socket);
+NLsocket parallel_AcceptConnection(NLsocket socket);
+NLsocket parallel_Open(NLushort port, NLenum type);
+NLboolean parallel_Connect(NLsocket socket, NLaddress *address);
+NLboolean parallel_Close(NLsocket socket);
+NLint parallel_Read(NLsocket socket, NLvoid *buffer, NLint nbytes);
+NLint parallel_Write(NLsocket socket, NLvoid *buffer, NLint nbytes);
+NLbyte *parallel_AddrToString(NLaddress *address, NLbyte *string);
+NLboolean parallel_StringToAddr(NLbyte *string, NLaddress *address);
+NLboolean parallel_GetLocalAddr(NLsocket socket, NLaddress *address);
+NLboolean parallel_SetLocalAddr(NLaddress *address);
+NLbyte *parallel_GetNameFromAddr(NLaddress *address, NLbyte *name);
+NLboolean parallel_GetNameFromAddrAsync(NLaddress *address, NLbyte *name);
+NLboolean parallel_GetAddrFromName(NLbyte *name, NLaddress *address);
+NLboolean parallel_GetAddrFromNameAsync(NLbyte *name, NLaddress *address);
+NLboolean parallel_AddrCompare(NLaddress *address1, NLaddress *address2);
+NLushort parallel_GetPortFromAddr(NLaddress *address);
+void parallel_SetAddrPort(NLaddress *address, NLushort port);
+NLint parallel_GetSystemError(void);
+NLint parallel_PollGroup(NLint group, NLenum name, NLsocket *sockets, NLint number, NLint timeout);
+NLboolean parallel_PollSocket(NLsocket socket, NLenum name, NLint timeout);
+NLboolean parallel_Hint(NLenum name, NLint arg);
+NLboolean parallel_SetSocketOpt(NLsocket socket, NLenum name, NLint arg);
+NLint parallel_GetSocketOpt(NLsocket socket, NLenum name);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PARALLEL_H */
+
diff --git a/util/network/hawknl/hawknl/serial.h b/util/network/hawknl/hawknl/serial.h
new file mode 100644
index 00000000..579e44d8
--- /dev/null
+++ b/util/network/hawknl/hawknl/serial.h
@@ -0,0 +1,62 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef SERIAL_H
+#define SERIAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NLboolean serial_Init(void);
+void serial_Shutdown(void);
+NLboolean serial_Listen(NLsocket socket);
+NLsocket serial_AcceptConnection(NLsocket socket);
+NLsocket serial_Open(NLushort port, NLenum type);
+NLboolean serial_Connect(NLsocket socket, NLaddress *address);
+NLboolean serial_Close(NLsocket socket);
+NLint serial_Read(NLsocket socket, NLvoid *buffer, NLint nbytes);
+NLint serial_Write(NLsocket socket, NLvoid *buffer, NLint nbytes);
+NLbyte *serial_AddrToString(NLaddress *address, NLbyte *string);
+NLboolean serial_StringToAddr(NLbyte *string, NLaddress *address);
+NLboolean serial_GetLocalAddr(NLsocket socket, NLaddress *address);
+NLboolean serial_SetLocalAddr(NLaddress *address);
+NLbyte *serial_GetNameFromAddr(NLaddress *address, NLbyte *name);
+NLboolean serial_GetNameFromAddrAsync(NLaddress *address, NLbyte *name);
+NLboolean serial_GetAddrFromName(NLbyte *name, NLaddress *address);
+NLboolean serial_GetAddrFromNameAsync(NLbyte *name, NLaddress *address);
+NLboolean serial_AddrCompare(NLaddress *address1, NLaddress *address2);
+NLushort serial_GetPortFromAddr(NLaddress *address);
+void serial_SetAddrPort(NLaddress *address, NLushort port);
+NLint serial_GetSystemError(void);
+NLint serial_PollGroup(NLint group, NLenum name, NLsocket *sockets, NLint number, NLint timeout);
+NLboolean serial_PollSocket(NLsocket socket, NLenum name, NLint timeout);
+NLboolean serial_Hint(NLenum name, NLint arg);
+NLboolean serial_SetSocketOpt(NLsocket socket, NLenum name, NLint arg);
+NLint serial_GetSocketOpt(NLsocket socket, NLenum name);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SERIAL_H */
+
diff --git a/util/network/hawknl/hawknl/sock.h b/util/network/hawknl/hawknl/sock.h
new file mode 100644
index 00000000..26984e2b
--- /dev/null
+++ b/util/network/hawknl/hawknl/sock.h
@@ -0,0 +1,64 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef SOCKETS_H
+#define SOCKETS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NLboolean sock_Init(void);
+void sock_Shutdown(void);
+NLboolean sock_Listen(NLsocket socket);
+NLsocket sock_AcceptConnection(NLsocket socket);
+NLsocket sock_Open(NLushort port, NLenum type);
+NLboolean sock_Connect(NLsocket socket, const NLaddress *address);
+void sock_Close(NLsocket socket);
+NLint sock_Read(NLsocket socket, /*@out@*/ NLvoid *buffer, NLint nbytes);
+NLint sock_Write(NLsocket socket, const NLvoid *buffer, NLint nbytes);
+NLchar *sock_AddrToString(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *string);
+NLboolean sock_StringToAddr(const NLchar *string, /*@out@*/ NLaddress *address);
+NLboolean sock_GetLocalAddr(NLsocket socket, /*@out@*/ NLaddress *address);
+NLaddress *sock_GetAllLocalAddr(/*@out@*/ NLint *count);
+NLboolean sock_SetLocalAddr(const NLaddress *address);
+NLchar *sock_GetNameFromAddr(const NLaddress *address, /*@returned@*/ /*@out@*/ NLchar *name);
+NLboolean sock_GetNameFromAddrAsync(const NLaddress *address, /*@out@*/ NLchar *name);
+NLboolean sock_GetAddrFromName(const NLchar *name, /*@out@*/ NLaddress *address);
+NLboolean sock_GetAddrFromNameAsync(const NLchar *name, /*@out@*/ NLaddress *address);
+NLboolean sock_AddrCompare(const NLaddress *address1, const NLaddress *address2);
+NLushort sock_GetPortFromAddr(const NLaddress *address);
+void sock_SetAddrPort(NLaddress *address, NLushort port);
+NLint sock_GetSystemError(void);
+NLint sock_PollGroup(NLint group, NLenum name, /*@out@*/ NLsocket *sockets, NLint number, NLint timeout);
+NLboolean sock_PollSocket(NLsocket socket, NLenum name, NLint timeout);
+NLboolean sock_Hint(NLenum name, NLint arg);
+NLboolean sock_SetSocketOpt(NLsocket socket, NLenum name, NLint arg);
+NLint sock_GetSocketOpt(NLsocket socket, NLenum name);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SOCKETS_H */
+
diff --git a/util/network/hawknl/hawknl/wsock.h b/util/network/hawknl/hawknl/wsock.h
new file mode 100644
index 00000000..b1d9e6e9
--- /dev/null
+++ b/util/network/hawknl/hawknl/wsock.h
@@ -0,0 +1,191 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#ifndef _hawknl_WSOCK_H
+#define _hawknl_WSOCK_H
+
+#include "nl.h"
+
+/* Windows systems */
+#ifdef _MSC_VER
+#pragma warning (disable:4201)
+#pragma warning (disable:4214)
+#pragma warning (disable:4127) /* bogus FD_SET warning */
+#endif /* _MSC_VER */
+
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#ifdef _MSC_VER
+#pragma warning (default:4201)
+#pragma warning (default:4214)
+#endif /* _MSC_VER */
+
+#define ioctl ioctlsocket
+
+#undef EBADF
+#define EBADF WSAEBADF
+
+#undef EFAULT
+#define EFAULT WSAEFAULT
+
+#undef EMFILE
+#define EMFILE WSAEMFILE
+
+#undef EINTR
+#define EINTR WSAEINTR
+
+#undef EINVAL
+#define EINVAL WSAEINVAL
+
+#undef EACCES
+#define EACCES WSAEACCES
+
+#ifndef ENAMETOOLONG
+#define ENAMETOOLONG WSAENAMETOOLONG
+#endif
+
+#ifndef ENOTEMPTY
+#define ENOTEMPTY WSAENOTEMPTY
+#endif
+
+#ifndef ETIMEDOUT
+#define ETIMEDOUT WSAETIMEDOUT
+#endif
+
+#ifndef EREMOTE
+#define EREMOTE WSAEREMOTE
+#endif
+
+#define TRY_AGAIN WSATRY_AGAIN
+#define NO_RECOVERY WSANO_RECOVERY
+#define NO_DATA WSANO_DATA
+#define HOST_NOT_FOUND WSAHOST_NOT_FOUND
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
+#define ENOTSOCK WSAENOTSOCK
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#define EMSGSIZE WSAEMSGSIZE
+#define EPROTOTYPE WSAEPROTOTYPE
+#define ENOPROTOOPT WSAENOPROTOOPT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define EADDRINUSE WSAEADDRINUSE
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define ENETDOWN WSAENETDOWN
+#define ENETUNREACH WSAENETUNREACH
+#define ENETRESET WSAENETRESET
+#define ECONNABORTED WSAECONNABORTED
+#define ECONNRESET WSAECONNRESET
+#define ENOBUFS WSAENOBUFS
+#define EISCONN WSAEISCONN
+#define ENOTCONN WSAENOTCONN
+#define ESHUTDOWN WSAESHUTDOWN
+#define ETOOMANYREFS WSAETOOMANYREFS
+#define ECONNREFUSED WSAECONNREFUSED
+#define ELOOP WSAELOOP
+#define EHOSTDOWN WSAEHOSTDOWN
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#define EPROCLIM WSAEPROCLIM
+#define EUSERS WSAEUSERS
+#define EDQUOT WSAEDQUOT
+#define ESTALE WSAESTALE
+#define sockerrno WSAGetLastError()
+/* get rid of some nasty LCLint messages */
+#undef FIONBIO
+#define FIONBIO 0x8004667e
+
+typedef int socklen_t;
+
+typedef struct sockaddr_ipx
+{
+ short sa_family;
+ char sa_netnum[4];
+ char sa_nodenum[6];
+ unsigned short sa_socket;
+} SOCKADDR_IPX;
+
+#define NSPROTO_IPX 1000
+#define NSPROTO_SPX 1256
+#define NSPROTO_SPXII 1257
+
+/* These replacement inlined functions are replacements for */
+/* the Winsock macros, but compile without errors :) */
+#undef FD_CLR
+#define FD_CLR nlFD_CLR
+
+#undef FD_SET
+#define FD_SET nlFD_SET
+
+#undef FD_ISSET
+#define FD_ISSET(fd, set) nlWSAFDIsSet((SOCKET)(fd), set)
+
+#if 0
+HL_INLINE void nlFD_CLR(SOCKET fd, fd_set *set)
+{
+ u_int i;
+
+ for(i=0;i<set->fd_count;i++)
+ {
+ if(set->fd_array[i] == fd)
+ {
+ while(i < set->fd_count-1)
+ {
+ set->fd_array[i] = set->fd_array[i+1];
+ i++;
+ }
+ set->fd_count--;
+ break;
+ }
+ }
+}
+
+
+HL_INLINE void nlFD_SET(SOCKET fd, /*@out@*/ fd_set *set)
+{
+ if(set->fd_count < FD_SETSIZE)
+ set->fd_array[set->fd_count++]=fd;
+}
+
+/* This function is inlined for speed over the Winsock function */
+
+
+HL_INLINE int nlWSAFDIsSet(SOCKET fd, fd_set *set)
+{
+ int i = (int)set->fd_count;
+
+ while(i-- != 0)
+ {
+ if (set->fd_array[i] == fd)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+#endif /* WSOCK_H */
+
diff --git a/util/network/hawknl/src/crc.c b/util/network/hawknl/src/crc.c
new file mode 100644
index 00000000..be9f886e
--- /dev/null
+++ b/util/network/hawknl/src/crc.c
@@ -0,0 +1,138 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2002 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include "nl.h"
+
+
+static NLushort crc16tab[256] =
+{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+
+HL_EXP NLushort HL_APIENTRY nlGetCRC16(NLubyte *data, NLint len)
+{
+ register NLushort crc = 0xffff;
+ register NLubyte *cp = data;
+ register NLint cnt = len;
+
+ while(0 != cnt--)
+ {
+ crc = (NLushort)((crc<<8) ^ crc16tab[(crc>>8) ^ *cp++]);
+ }
+
+ return crc;
+}
+
+static NLulong crc32tab[256] =
+{
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+
+HL_EXP NLulong HL_APIENTRY nlGetCRC32(NLubyte *data, NLint len)
+{
+ register NLulong crc = (NLulong)0xffffffff;
+ register NLubyte *cp = data;
+ register NLint cnt = len;
+
+ while(0 != cnt--)
+ {
+ crc = ((crc) >> 8) ^ crc32tab[(NLint)(*cp++) ^ ((crc) & 0x000000FF)];
+ }
+
+ return crc;
+}
+
diff --git a/util/network/hawknl/src/err.c b/util/network/hawknl/src/err.c
new file mode 100644
index 00000000..89e222e3
--- /dev/null
+++ b/util/network/hawknl/src/err.c
@@ -0,0 +1,119 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include "nlinternal.h"
+
+#ifdef HL_WINDOWS_APP
+/* Windows systems */
+#define NL_WIN_THREADS
+
+#ifdef _MSC_VER
+#pragma warning (disable:4201)
+#pragma warning (disable:4214)
+#endif /* _MSC_VER */
+
+#define WIN32_LEAN_AND_MEAN
+#include <winsock.h>
+
+#ifdef _MSC_VER
+#pragma warning (default:4201)
+#pragma warning (default:4214)
+#endif /* _MSC_VER */
+
+#endif
+
+#ifdef NL_WIN_THREADS
+/* native Windows */
+static DWORD key = (DWORD)0xFFFFFFFF;
+#else
+/* POSIX systems */
+#include <pthread.h>
+
+#define KEY_NULL ((pthread_key_t)-1)
+static pthread_key_t key = KEY_NULL;
+#endif
+
+void nlSetError(NLenum err)
+{
+
+#ifdef NL_WIN_THREADS
+ /* check to see if we need to initialize */
+ if(key == (DWORD)0xFFFFFFFF)
+ {
+ key = TlsAlloc();
+ }
+ if(key != (DWORD)0xFFFFFFFF)
+ {
+ (void)TlsSetValue(key, (LPVOID)err);
+ }
+#else
+ /* check to see if we need to initialize */
+ if(key == KEY_NULL)
+ {
+ (void)pthread_key_create(&key, NULL);
+ }
+ if(key != KEY_NULL)
+ {
+ (void)pthread_setspecific(key, (void *)(long)err);
+ }
+#endif
+}
+
+HL_EXP NLenum HL_APIENTRY nlGetError(void)
+{
+ NLenum result;
+#ifdef NL_WIN_THREADS
+ /* check to see if we need to initialize */
+ if(key == (DWORD)0xFFFFFFFF)
+ {
+ key = TlsAlloc();
+ if(key == (DWORD)0xFFFFFFFF)
+ return NL_TLS_ERROR;
+ else
+ return NL_NO_ERROR;
+ }
+ else
+ {
+ int lasterror = WSAGetLastError();
+
+ result = (NLenum)TlsGetValue(key);
+ WSASetLastError(lasterror);
+ return result;
+ }
+#else
+ /* check to see if we need to initialize */
+ if(key == KEY_NULL)
+ {
+ if(pthread_key_create(&key, NULL) != 0)
+ return NL_TLS_ERROR;
+ else
+ return NL_NO_ERROR;
+ }
+ else
+ {
+ result = (NLenum)(long)pthread_getspecific(key);
+ return result;
+ }
+#endif
+}
+
+
diff --git a/util/network/hawknl/src/errorstr.c b/util/network/hawknl/src/errorstr.c
new file mode 100644
index 00000000..ca0b384a
--- /dev/null
+++ b/util/network/hawknl/src/errorstr.c
@@ -0,0 +1,364 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+/*
+ Based on code supplied by Ryan Haksi <cryogen@infoserve.net>
+*/
+
+#if defined WIN32 || defined WIN64 || defined (_WIN32_WCE)
+#if !defined (_WIN32_WCE)
+#include <errno.h>
+#endif
+#include "wsock.h"
+#elif macintosh
+/* POSIX compat Mac systems ie pre OSX with GUSI2 installed */
+#include <unistd.h>
+#include <types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#else
+/* POSIX systems */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <netdb.h>
+#include <string.h>
+#endif
+
+#include "nlinternal.h"
+
+
+HL_EXP const /*@observer@*/ NLchar* HL_APIENTRY nlGetSystemErrorStr(NLint err)
+{
+ NLchar *lpszRetStr;
+ switch(err) {
+#ifdef HL_WINDOWS_APP
+ case WSABASEERR:
+ lpszRetStr=(NLchar *)TEXT("No error.");
+ break;
+ case WSAVERNOTSUPPORTED:
+ lpszRetStr=(NLchar *)TEXT("Version of WinSock not supported.");
+ break;
+ case WSASYSNOTREADY:
+ lpszRetStr=(NLchar *)TEXT("WinSock not present or not responding.");
+ break;
+ case WSANOTINITIALISED:
+ lpszRetStr=(NLchar *)TEXT("WinSock not initialized.");
+ break;
+#endif
+ /* ELOOK is used on some Macs */
+#ifdef ELOOK
+ case ELOOK:
+ lpszRetStr=(NLchar *)TEXT("Internal mapping for kOTLookErr, don't return to client.");
+ break;
+#endif
+ /* EPROCLIM not defined in some UNIXs */
+#ifdef EPROCLIM
+ case EPROCLIM:
+ lpszRetStr=(NLchar *)TEXT("Too many processes.");
+ break;
+#endif
+ /* On some UNIXs, EINTR and NO_DATA have the same value */
+#if (EINTR != NO_DATA)
+ case EINTR:
+ lpszRetStr=(NLchar *)TEXT("Interrupted function call.");
+ break;
+#if defined(NO_DATA)
+ case NO_DATA:
+ lpszRetStr=(NLchar *)TEXT("Valid name, no data record for type.");
+ break;
+#endif
+#else
+ case NO_DATA:
+ lpszRetStr=(NLchar *)TEXT("Interrupted function call or no data record for type.");
+ break;
+#endif
+ case EBADF:
+ lpszRetStr=(NLchar *)TEXT("Bad file descriptor.");
+ break;
+ case EFAULT:
+ lpszRetStr=(NLchar *)TEXT("The namelen argument is incorrect.");
+ break;
+ case EMFILE:
+ lpszRetStr=(NLchar *)TEXT("Too many open files.");
+ break;
+ case EINVAL:
+ lpszRetStr=(NLchar *)TEXT("App version not supported by DLL.");
+ break;
+#if defined(TRY_AGAIN)
+ case TRY_AGAIN:
+ lpszRetStr=(NLchar *)TEXT("Non-authoritive: host not found or server failure.");
+ break;
+#endif
+#if defined(NO_RECOVERY)
+ case NO_RECOVERY:
+ lpszRetStr=(NLchar *)TEXT("Non-recoverable: refused or not implemented.");
+ break;
+#endif
+#if defined(HOST_NOT_FOUND)
+ case HOST_NOT_FOUND:
+ lpszRetStr=(NLchar *)TEXT("Authoritive: Host not found.");
+ break;
+#endif
+ case EACCES:
+ lpszRetStr=(NLchar *)TEXT("Permission to access socket denied.");
+ break;
+ case ENETDOWN:
+ lpszRetStr=(NLchar *)TEXT("Network subsystem failed.");
+ break;
+ case EAFNOSUPPORT:
+ lpszRetStr=(NLchar *)TEXT("Address family not supported.");
+ break;
+ case ENOBUFS:
+ lpszRetStr=(NLchar *)TEXT("No buffer space available.");
+ break;
+ case EPROTONOSUPPORT:
+ lpszRetStr=(NLchar *)TEXT("Specified protocol not supported.");
+ break;
+ case EPROTOTYPE:
+ lpszRetStr=(NLchar *)TEXT("Protocol wrong type for this socket.");
+ break;
+ case ESOCKTNOSUPPORT:
+ lpszRetStr=(NLchar *)TEXT("Socket type not supported for address family.");
+ break;
+ case ENOTSOCK:
+ lpszRetStr=(NLchar *)TEXT("Descriptor is not a socket.");
+ break;
+ case EWOULDBLOCK:
+ lpszRetStr=(NLchar *)TEXT("Non-blocking socket would block.");
+ break;
+ case EADDRINUSE:
+ lpszRetStr=(NLchar *)TEXT("Address already in use.");
+ break;
+ case ECONNABORTED:
+ lpszRetStr=(NLchar *)TEXT("Connection aborted.");
+ break;
+ case ECONNRESET:
+ lpszRetStr=(NLchar *)TEXT("Connection reset.");
+ break;
+ case ENOTCONN:
+ lpszRetStr=(NLchar *)TEXT("Not connected.");
+ break;
+ case ETIMEDOUT:
+ lpszRetStr=(NLchar *)TEXT("Connection timed out.");
+ break;
+ case ECONNREFUSED:
+ lpszRetStr=(NLchar *)TEXT("Connection was refused.");
+ break;
+ case EHOSTDOWN:
+ lpszRetStr=(NLchar *)TEXT("Host is down.");
+ break;
+ case ENETUNREACH:
+ lpszRetStr=(NLchar *)TEXT("Network unreachable.");
+ break;
+ case EHOSTUNREACH:
+ lpszRetStr=(NLchar *)TEXT("Host unreachable.");
+ break;
+ case EADDRNOTAVAIL:
+ lpszRetStr=(NLchar *)TEXT("Address not available.");
+ break;
+ case EINPROGRESS:
+#ifdef HL_WINDOWS_APP
+ lpszRetStr=(NLchar *)TEXT("A blocking sockets call is in progress.");
+#else
+ lpszRetStr=(NLchar *)TEXT("The socket is non-blocking and the connection could not be established immediately.");
+#endif
+ break;
+ case EDESTADDRREQ:
+ lpszRetStr=(NLchar *)TEXT("Destination address is required.");
+ break;
+ case EISCONN:
+ lpszRetStr=(NLchar *)TEXT("Socket is already connected.");
+ break;
+ case ENETRESET:
+ lpszRetStr=(NLchar *)TEXT("Connection has been broken due to the remote host resetting.");
+ break;
+ case EOPNOTSUPP:
+ lpszRetStr=(NLchar *)TEXT("Operation not supported on socket");
+ break;
+ case ESHUTDOWN:
+ lpszRetStr=(NLchar *)TEXT("Socket has been shut down.");
+ break;
+ case EMSGSIZE:
+ lpszRetStr=(NLchar *)TEXT("The message was too large to fit into the specified buffer and was truncated.");
+ break;
+ case EALREADY:
+ lpszRetStr=(NLchar *)TEXT("A non-blocking connect call is in progress on the specified socket.");
+ break;
+ case ENOPROTOOPT:
+ lpszRetStr=(NLchar *)TEXT("Bad protocol option.");
+ break;
+ case EPFNOSUPPORT:
+ lpszRetStr=(NLchar *)TEXT("Protocol family not supported.");
+ break;
+ case ETOOMANYREFS:
+ lpszRetStr=(NLchar *)TEXT("Too many references; can't splice.");
+ break;
+ case ELOOP:
+ lpszRetStr=(NLchar *)TEXT("Too many levels of symbolic links.");
+ break;
+ case ENAMETOOLONG:
+ lpszRetStr=(NLchar *)TEXT("File name too long.");
+ break;
+ case ENOTEMPTY:
+ lpszRetStr=(NLchar *)TEXT("Directory not empty.");
+ break;
+
+#if !defined(macintosh)
+ case EUSERS:
+ lpszRetStr=(NLchar *)TEXT("Too many users.");
+ break;
+ case EDQUOT:
+ lpszRetStr=(NLchar *)TEXT("Disc quota exceeded.");
+ break;
+ case ESTALE:
+ lpszRetStr=(NLchar *)TEXT("Stale NFS file handle.");
+ break;
+ case EREMOTE:
+ lpszRetStr=(NLchar *)TEXT("Too many levels of remote in path.");
+ break;
+#endif
+ default:
+#ifdef HL_WINDOWS_APP
+ {
+ static NLchar temp[256];
+
+ /* FormatMessage is unicode compliant */
+ (void)FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD)err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)temp, 256, NULL);
+ lpszRetStr = temp;
+ }
+#else
+ lpszRetStr=strerror(err);
+#endif
+ break;
+ }
+ return (const NLchar*)lpszRetStr;
+}
+
+HL_EXP const /*@observer@*/ NLchar* HL_APIENTRY nlGetErrorStr(NLenum err)
+{
+ NLchar *retStr;
+
+ switch(err) {
+ case NL_NO_ERROR:
+ retStr = (NLchar *)TEXT("No HawkNL error.");
+ break;
+ case NL_NO_NETWORK:
+ retStr = (NLchar *)TEXT("No network was found on init.");
+ break;
+ case NL_OUT_OF_MEMORY:
+ retStr = (NLchar *)TEXT("Out of memory.");
+ break;
+ case NL_INVALID_ENUM:
+ retStr = (NLchar *)TEXT("Invalid NLenum.");
+ break;
+ case NL_INVALID_SOCKET:
+ retStr = (NLchar *)TEXT("Socket is not valid.");
+ break;
+ case NL_INVALID_PORT:
+ retStr = (NLchar *)TEXT("Port could not be opened.");
+ break;
+ case NL_INVALID_TYPE:
+ retStr = (NLchar *)TEXT("Network type is not available.");
+ break;
+ case NL_SYSTEM_ERROR:
+ retStr = (NLchar *)TEXT("A system error occurred, call nlGetSystemError.");
+ break;
+ case NL_SOCK_DISCONNECT:
+ retStr = (NLchar *)TEXT("Connection error: Close socket.");
+ break;
+ case NL_NOT_LISTEN:
+ retStr = (NLchar *)TEXT("Socket has not been set to listen.");
+ break;
+ case NL_CON_REFUSED:
+ retStr = (NLchar *)TEXT("Connection refused.");
+ break;
+ case NL_NO_PENDING:
+ retStr = (NLchar *)TEXT("No pending connections to accept.");
+ break;
+ case NL_BAD_ADDR:
+ retStr = (NLchar *)TEXT("The address or port are not valid.");
+ break;
+ case NL_MESSAGE_END:
+ retStr = (NLchar *)TEXT("TCP message end.");
+ break;
+ case NL_NULL_POINTER:
+ retStr = (NLchar *)TEXT("A NULL pointer was passed to a function.");
+ break;
+ case NL_INVALID_GROUP:
+ retStr = (NLchar *)TEXT("The group is not valid.");
+ break;
+ case NL_OUT_OF_GROUPS:
+ retStr = (NLchar *)TEXT("Out of groups.");
+ break;
+ case NL_OUT_OF_GROUP_SOCKETS:
+ retStr = (NLchar *)TEXT("The group is full.");
+ break;
+ case NL_BUFFER_SIZE:
+ retStr = (NLchar *)TEXT("The buffer is too small.");
+ break;
+ case NL_PACKET_SIZE:
+ retStr = (NLchar *)TEXT("The packet is too large.");
+ break;
+ case NL_WRONG_TYPE:
+ retStr = (NLchar *)TEXT("Wrong socket type.");
+ break;
+ case NL_CON_PENDING:
+ retStr = (NLchar *)TEXT("A non-blocking connection is still pending.");
+ break;
+ case NL_SELECT_NET_ERROR:
+ retStr = (NLchar *)TEXT("A network type is already selected.");
+ break;
+ case NL_PACKET_SYNC:
+ retStr = (NLchar *)TEXT("The NL_RELIABLE_PACKET stream is out of sync.");
+ break;
+ case NL_TLS_ERROR:
+ retStr = (NLchar *)TEXT("Thread local storage could not be created.");
+ break;
+ case NL_TIMED_OUT:
+ retStr = (NLchar *)TEXT("The function timed out.");
+ break;
+ case NL_SOCKET_NOT_FOUND:
+ retStr = (NLchar *)TEXT("The socket was not found in the group.");
+ break;
+ case NL_STRING_OVER_RUN:
+ retStr = (NLchar *)TEXT("The string could cause a buffer over-run or corrupt memory.");
+ break;
+ case NL_CONNECTED:
+ retStr = (NLchar *)TEXT("The socket is already connected.");
+ break;
+
+ default:
+ retStr = (NLchar *)TEXT("Undefined HawkNL error.");
+ break;
+ }
+ return (const NLchar*)retStr;
+}
+
diff --git a/util/network/hawknl/src/group.c b/util/network/hawknl/src/group.c
new file mode 100644
index 00000000..5fe5b5b6
--- /dev/null
+++ b/util/network/hawknl/src/group.c
@@ -0,0 +1,527 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include <string.h>
+
+#define FD_SETSIZE 8192
+
+#if defined WIN32 || defined WIN64 || defined (_WIN32_WCE)
+/* Windows systems */
+
+#include "wsock.h"
+
+#else
+/* Unix-style systems or macs with posix support */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#define INVALID_SOCKET -1
+#define SOCKET int
+#endif
+
+#include "nlinternal.h"
+
+static HTmutex grouplock;
+
+typedef struct
+{
+ NLsocket *sockets; /* the list of sockets in this group */
+ NLint maxsockets; /* the number of sockets allocated */
+ NLint numsockets; /* the number of sockets stored */
+ fd_set *fdset; /* for nlPollGroup */
+ SOCKET highest; /* for nlPollGroup */
+} nl_group_t;
+
+typedef /*@only@*/ nl_group_t *pnl_group_t;
+static /*@only@*/ pnl_group_t *groups;
+static NLint nlnextgroup = 0;
+static NLint nlnumgroups = 0;
+
+
+/* Internal functions */
+
+void nlGroupLock(void)
+{
+ (void)htMutexLock(&grouplock);
+}
+
+void nlGroupUnlock(void)
+{
+ (void)htMutexUnlock(&grouplock);
+}
+
+NLboolean nlGroupInit(void)
+{
+ if(groups == NULL)
+ {
+ groups = (nl_group_t **)malloc(NL_MAX_GROUPS * sizeof(nl_group_t *));
+ }
+ if(groups == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_FALSE;
+ }
+ memset(groups, 0, NL_MAX_GROUPS * sizeof(nl_group_t *));
+ if(htMutexInit(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+void nlGroupShutdown(void)
+{
+ if(groups != NULL)
+ {
+ NLint i;
+
+ for(i=0;i<NL_MAX_GROUPS;i++)
+ {
+ if(groups[i] != NULL)
+ {
+ (void)nlGroupDestroy(i + NL_FIRST_GROUP);
+ }
+ }
+ free(groups);
+ groups = NULL;
+ }
+ (void)htMutexDestroy(&grouplock);
+}
+
+SOCKET nlGroupGetFdset(NLint group, fd_set *fd)
+{
+ NLint realgroup = group - NL_FIRST_GROUP;
+ nl_group_t *pgroup = NULL;
+
+ if(groups == NULL)
+ {
+ nlSetError(NL_NO_NETWORK);
+ return INVALID_SOCKET;
+ }
+ if(realgroup < 0)
+ {
+ nlSetError(NL_INVALID_GROUP);
+ return INVALID_SOCKET;
+ }
+ pgroup = groups[realgroup];
+ if(pgroup == NULL)
+ {
+ nlSetError(NL_INVALID_GROUP);
+ return INVALID_SOCKET;
+ }
+ /* if fdset is NULL, then create it */
+ if(pgroup->fdset == NULL)
+ {
+ int i;
+ SOCKET realsock;
+ /* create the fd_set */
+ pgroup->fdset = (fd_set *)malloc(sizeof(fd_set));
+ if(pgroup->fdset == NULL)
+ {
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_OUT_OF_MEMORY);
+ return INVALID_SOCKET;
+ }
+ FD_ZERO(pgroup->fdset);
+ pgroup->highest = 0;
+ for(i=0;i<pgroup->numsockets;i++)
+ {
+ realsock = (SOCKET)nlSockets[pgroup->sockets[i]]->realsocket;
+ FD_SET(realsock, pgroup->fdset);
+ if(pgroup->highest < realsock + 1)
+ {
+ pgroup->highest = realsock + 1;
+ }
+ }
+ }
+ memcpy(fd, pgroup->fdset, sizeof(fd_set));
+
+ return pgroup->highest;
+}
+
+/* Group management API */
+
+HL_EXP NLint HL_APIENTRY nlGroupCreate(void)
+{
+ NLint newgroup = NL_INVALID;
+ nl_group_t *pgroup = NULL;
+
+ if(groups == NULL)
+ {
+ nlSetError(NL_NO_NETWORK);
+ return NL_INVALID;
+ }
+ if(htMutexLock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_INVALID;
+ }
+ if(nlnumgroups == NL_MAX_GROUPS)
+ {
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_OUT_OF_GROUPS);
+ return NL_INVALID;
+ }
+ /* get a group number */
+ if(nlnumgroups == nlnextgroup)
+ {
+ /* do not increment nlnextgroup here, wait in case of malloc failure */
+ newgroup = nlnextgroup + 1;
+ }
+ else
+ /* there is an open group slot somewhere below nlnextgroup */
+ {
+ NLint i;
+
+ for(i=0;i<nlnextgroup;i++)
+ {
+ if(groups[i] == NULL)
+ {
+ /* found an open group slot */
+ newgroup = i;
+ }
+ }
+ /* let's check just to make sure we did find a group */
+ if(newgroup == NL_INVALID)
+ {
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_INVALID;
+ }
+ }
+ /* allocate the memory */
+ pgroup = (nl_group_t *)malloc((size_t)(sizeof(nl_group_t)));
+ if(pgroup == NULL)
+ {
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_INVALID;
+ }
+ else
+ {
+ NLint i;
+
+ pgroup->sockets = (NLsocket *)malloc(NL_MIN_SOCKETS * sizeof(NLsocket *));
+ if(pgroup->sockets == NULL)
+ {
+ free(pgroup);
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_INVALID;
+ }
+ pgroup->maxsockets = NL_MIN_SOCKETS;
+ /* fill with -1, since 0 is a valid socket number */
+ for(i=0;i<pgroup->maxsockets;i++)
+ {
+ pgroup->sockets[i] = -1;
+ }
+ pgroup->numsockets = 0;
+ pgroup->fdset = NULL;
+ pgroup->highest = 0;
+ groups[newgroup] = pgroup;
+ }
+
+ nlnumgroups++;
+ if(nlnumgroups == newgroup)
+ {
+ nlnextgroup = nlnumgroups;
+ }
+ if(htMutexUnlock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_INVALID;
+ }
+ /* adjust the group number */
+ return (newgroup + NL_FIRST_GROUP);
+}
+
+HL_EXP NLboolean HL_APIENTRY nlGroupDestroy(NLint group)
+{
+ NLint realgroup = group - NL_FIRST_GROUP;
+
+ if(groups == NULL)
+ {
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+ }
+ if(realgroup < 0)
+ {
+ nlSetError(NL_INVALID_GROUP);
+ return NL_FALSE;
+ }
+ if(htMutexLock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ if(groups[realgroup] != NULL)
+ {
+ if(groups[realgroup]->fdset != NULL)
+ {
+ free(groups[realgroup]->fdset);
+ }
+ if(groups[realgroup]->sockets != NULL)
+ {
+ free(groups[realgroup]->sockets);
+ }
+ free(groups[realgroup]);
+ groups[realgroup] = NULL;
+ nlnumgroups--;
+ }
+ if(htMutexUnlock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlGroupAddSocket(NLint group, NLsocket socket)
+{
+ NLint realgroup = group - NL_FIRST_GROUP;
+ NLint i;
+ nl_group_t *pgroup = NULL;
+
+ if(groups == NULL)
+ {
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+ }
+ if(realgroup < 0)
+ {
+ nlSetError(NL_INVALID_GROUP);
+ return NL_FALSE;
+ }
+
+ /* add the socket to the group */
+ if(htMutexLock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ pgroup = groups[realgroup];
+ /* allocate more sockets as needed */
+ if(pgroup->numsockets == pgroup->maxsockets)
+ {
+ NLint oldmax = pgroup->maxsockets;
+ NLint j;
+ NLsocket *newsockets;
+
+ if(oldmax == NL_MAX_GROUP_SOCKETS)
+ {
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_OUT_OF_GROUP_SOCKETS);
+ return NL_FALSE;
+ }
+ pgroup->maxsockets *= 2;
+ if(pgroup->maxsockets > NL_MAX_GROUP_SOCKETS)
+ {
+ pgroup->maxsockets = NL_MAX_GROUP_SOCKETS;
+ }
+ if((newsockets = (NLsocket *)realloc(pgroup->sockets, pgroup->maxsockets * sizeof(NLsocket *))) == NULL)
+ {
+ pgroup->maxsockets = oldmax;
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_FALSE;
+ }
+ /* set the new sockets to -1 */
+ for(j=oldmax;j<pgroup->maxsockets;j++)
+ {
+ newsockets[j] = -1;
+ }
+ pgroup->sockets = newsockets;
+ }
+
+ for(i=0;i<pgroup->maxsockets;i++)
+ {
+ if(pgroup->sockets[i] == -1)
+ {
+ pgroup->sockets[i] = socket;
+ if(pgroup->fdset != NULL)
+ {
+ SOCKET realsock;
+
+ /* make sure the socket is valid */
+ if(nlIsValidSocket(socket) == NL_FALSE)
+ {
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ realsock = (SOCKET)nlSockets[socket]->realsocket;
+ FD_SET(realsock, pgroup->fdset);
+ if(pgroup->highest < realsock + 1)
+ {
+ pgroup->highest = realsock + 1;
+ }
+ }
+ break;
+ }
+ }
+ if(i == pgroup->maxsockets)
+ {
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_OUT_OF_GROUP_SOCKETS);
+ return NL_FALSE;
+ }
+ pgroup->numsockets++;
+ if(htMutexUnlock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean nlGroupGetSocketsINT(NLint group, NLsocket *socket, NLint *number)
+{
+ NLint realgroup = group - NL_FIRST_GROUP;
+ NLint len, i;
+ nl_group_t *pgroup = NULL;
+
+ if(socket == NULL || number == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ if(groups == NULL)
+ {
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+ }
+ if(realgroup < 0)
+ {
+ nlSetError(NL_INVALID_GROUP);
+ *number = 0;
+ return NL_FALSE;
+ }
+ pgroup = groups[realgroup];
+ len = *number;
+ if(len > pgroup->numsockets)
+ {
+ len = pgroup->numsockets;
+ }
+ for(i=0;i<len;i++)
+ {
+ socket[i] = pgroup->sockets[i];
+ }
+ *number = len;
+ return NL_TRUE;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlGroupGetSockets(NLint group, NLsocket *socket, NLint *number)
+{
+ NLboolean result;
+
+ if(htMutexLock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ result = nlGroupGetSocketsINT(group, socket, number);
+ if(htMutexUnlock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ return result;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlGroupDeleteSocket(NLint group, NLsocket socket)
+{
+ NLint realgroup = group - NL_FIRST_GROUP;
+ NLint i;
+ nl_group_t *pgroup = NULL;
+
+ if(groups == NULL)
+ {
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+ }
+ if(realgroup < 0)
+ {
+ nlSetError(NL_INVALID_GROUP);
+ return NL_FALSE;
+ }
+
+ /* delete the socket from the group */
+ if(htMutexLock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ pgroup = groups[realgroup];
+ for(i=0;i<pgroup->numsockets;i++)
+ {
+ /* check for match */
+ if(pgroup->sockets[i] == socket)
+ break;
+ }
+ if(i == pgroup->numsockets)
+ {
+ /* did not find the socket */
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_SOCKET_NOT_FOUND);
+ return NL_FALSE;
+ }
+ /* now pgroup[i] points to the socket to delete */
+ /* shift all other sockets down to close the gap */
+ i++;
+ for(;i<pgroup->maxsockets;i++)
+ {
+ pgroup->sockets[i - 1] = pgroup->sockets[i];
+ /* check for end of list */
+ if(pgroup->sockets[i] == -1)
+ break;
+ }
+ pgroup->numsockets--;
+ if(pgroup->fdset != NULL)
+ {
+ /* make sure the socket is valid */
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ SOCKET realsock;
+
+ realsock = (SOCKET)nlSockets[socket]->realsocket;
+ FD_CLR(realsock, pgroup->fdset);
+ }
+ else
+ {
+ /* the socket was already closed */
+ /* free the fdset so that it can be rebuilt */
+ free(pgroup->fdset);
+ pgroup->fdset = NULL;
+ (void)htMutexUnlock(&grouplock);
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ }
+ if(htMutexUnlock(&grouplock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
diff --git a/util/network/hawknl/src/htcondition.c b/util/network/hawknl/src/htcondition.c
new file mode 100644
index 00000000..c2cc6b12
--- /dev/null
+++ b/util/network/hawknl/src/htcondition.c
@@ -0,0 +1,276 @@
+/*
+ HawkThreads condition module
+ Copyright (C) 2003-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include "htinternal.h"
+
+#ifdef HT_WIN_THREADS
+
+enum {
+ SIGNAL = 0,
+ BROADCAST = 1,
+ MAX_EVENTS = 2
+};
+
+struct ht_cond_t
+{
+ HANDLE events_[MAX_EVENTS];
+};
+
+#else /* !HT_WIN_THREADS */
+
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
+#include <sys/timeb.h>
+
+#ifdef HL_WINDOWS_APP
+#define timeb _timeb
+#define ftime _ftime
+#else
+#include <sys/time.h>
+#endif /* HL_WINDOWS_APP */
+
+#include <pthread.h>
+struct ht_cond_t
+{
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+};
+
+#endif /* !HT_WIN_THREADS */
+
+HL_EXP int HL_APIENTRY htCondInit(HTcond *cond)
+{
+ if(cond == NULL)
+ {
+ return EINVAL;
+ }
+ else
+ {
+#ifdef HT_WIN_THREADS
+ HTcond cv = NULL;
+
+ cv = (HTcond)malloc(sizeof(struct ht_cond_t));
+ if(cv == NULL)
+ {
+ return ENOMEM;
+ }
+ cv->events_[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL);
+ cv->events_[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL);
+#else
+ int result;
+ HTcond cv = NULL;
+
+ cv = (HTcond)malloc(sizeof(struct ht_cond_t));
+ if(cv == NULL)
+ {
+ return ENOMEM;
+ }
+
+ result = pthread_cond_init((pthread_cond_t *)&cv->cond, NULL);
+ if(result != 0)
+ {
+ free(cv);
+ return result;
+ }
+ result = pthread_mutex_init((pthread_mutex_t *)&cv->mutex, NULL);
+ if(result != 0)
+ {
+ (void)pthread_cond_destroy((pthread_cond_t *)&cv->cond);
+ free(cv);
+ return result;
+ }
+#endif
+ *cond = cv;
+ }
+ return 0;
+}
+
+HL_EXP int HL_APIENTRY htCondWait(HTcond *cond, int timeout)
+{
+ if(cond == NULL)
+ {
+ return EINVAL;
+ }
+ if(*cond == NULL)
+ {
+ return EINVAL;
+ }
+ if(timeout <= 0)
+ {
+ HTcond cv = *cond;
+
+#ifdef HT_WIN_THREADS
+ DWORD result;
+
+ result = WaitForMultipleObjects (2,cv->events_, FALSE, INFINITE);
+ if(result == WAIT_FAILED)
+ {
+ return EINVAL;
+ }
+#else
+ int result = 0;
+
+ (void)pthread_mutex_lock((pthread_mutex_t *)&cv->mutex);
+ result = pthread_cond_wait((pthread_cond_t *)&cv->cond, (pthread_mutex_t *)&cv->mutex);
+ if(result != 0)
+ {
+ return result;
+ }
+ (void)pthread_mutex_unlock((pthread_mutex_t *)&cv->mutex);
+#endif
+ }
+ else
+ {
+ HTcond cv = *cond;
+
+#ifdef HT_WIN_THREADS
+ DWORD result;
+
+ result = WaitForMultipleObjects (2, cv->events_, FALSE, (DWORD)timeout);
+ if(result == WAIT_FAILED)
+ {
+ return EINVAL;
+ }
+ else if(result == (DWORD)WAIT_TIMEOUT)
+ {
+ return (int)ETIMEDOUT;
+ }
+ }
+#else
+ int result = 0;
+ struct timespec tv;
+ struct timeb t;
+ long ms;
+
+ /* convert timeout to an absolute time */
+ ftime(&t);
+ ms = t.millitm + timeout;
+ tv.tv_sec = t.time + (ms / 1000);
+ tv.tv_nsec = (ms % 1000) * 1000000;
+
+ (void)pthread_mutex_lock((pthread_mutex_t *)&cv->mutex);
+ result = pthread_cond_timedwait((pthread_cond_t *)&cv->cond,
+ (pthread_mutex_t *)&cv->mutex, &tv);
+ if(result == ETIMEDOUT)
+ {
+ (void)pthread_mutex_unlock((pthread_mutex_t *)&cv->mutex);
+ return ETIMEDOUT;
+ }
+ else if(result != 0)
+ {
+ return result;
+ }
+ (void)pthread_mutex_unlock((pthread_mutex_t *)&cv->mutex);
+ }
+#endif
+ return 0;
+}
+
+HL_EXP int HL_APIENTRY htCondSignal(HTcond *cond)
+{
+ HTcond cv;
+
+ if(cond == NULL)
+ {
+ return EINVAL;
+ }
+ if(*cond == NULL)
+ {
+ return EINVAL;
+ }
+ else
+ {
+#ifdef HT_WIN_THREADS
+ cv = *cond;
+ if(PulseEvent(cv->events_[SIGNAL]) == 0)
+ {
+ return EINVAL;
+ }
+#else
+ int result;
+
+ cv = *cond;
+ result = pthread_cond_signal((pthread_cond_t *)&cv->cond);
+ if(result != 0)
+ {
+ return result;
+ }
+#endif
+ }
+ return 0;
+}
+
+HL_EXP int HL_APIENTRY htCondBroadcast(HTcond *cond)
+{
+ if(cond == NULL)
+ {
+ return EINVAL;
+ }
+ if(*cond == NULL)
+ {
+ return EINVAL;
+ }
+ else
+ {
+ HTcond cv = *cond;
+
+#ifdef HT_WIN_THREADS
+ if(PulseEvent(cv->events_[BROADCAST]) == 0)
+ {
+ return EINVAL;
+ }
+ return 0;
+#else
+ return pthread_cond_broadcast((pthread_cond_t *)&cv->cond);
+#endif
+ }
+}
+
+HL_EXP int HL_APIENTRY htCondDestroy(HTcond *cond)
+{
+ if(cond == NULL)
+ {
+ return EINVAL;
+ }
+ if(*cond == NULL)
+ {
+ return EINVAL;
+ }
+ else
+ {
+ HTcond cv = *cond;
+ int result = 0;
+
+#ifdef HT_WIN_THREADS
+ (void)CloseHandle(cv->events_[SIGNAL]);
+ (void)CloseHandle(cv->events_[BROADCAST]);
+#else
+ result = pthread_cond_destroy((pthread_cond_t *)&cv->cond);
+#endif
+ free(*cond);
+ *cond = NULL;
+ return result;
+ }
+}
+
+
diff --git a/util/network/hawknl/src/hthread.c b/util/network/hawknl/src/hthread.c
new file mode 100644
index 00000000..780823e9
--- /dev/null
+++ b/util/network/hawknl/src/hthread.c
@@ -0,0 +1,180 @@
+/*
+ HawkThreads thread module
+ Copyright (C) 2003-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include "htinternal.h"
+
+#ifdef HT_WIN_THREADS
+
+typedef struct {
+ void *(*func) (void *);
+ void *arg;
+} ThreadParms;
+
+static unsigned __stdcall threadfunc(void *arg)
+{
+ void *(*func) (void *);
+ void *args;
+
+ func = ((ThreadParms *)arg)->func;
+ args = ((ThreadParms *)arg)->arg;
+ free(arg);
+
+ return (unsigned)((*func)(args));
+}
+#if defined (_WIN32_WCE)
+#define _beginthreadex(security, \
+ stack_size, \
+ start_proc, \
+ arg, \
+ flags, \
+ pid) \
+ CreateThread(security, \
+ stack_size, \
+ (LPTHREAD_START_ROUTINE) start_proc, \
+ arg, \
+ flags, \
+ pid)
+#else /* !(_WIN32_WCE) */
+#include <process.h>
+#endif /* !(_WIN32_WCE) */
+
+#else /* !HT_WIN_THREADS */
+/* POSIX systems */
+#include <pthread.h>
+#include <sched.h>
+#endif /* !HT_WIN_THREADS */
+
+#ifndef HL_WINDOWS_APP
+#include <unistd.h>
+#endif /* HL_WINDOWS_APP */
+
+HL_EXP HThreadID HL_APIENTRY htThreadCreate(HThreadFunc func, void *data, int joinable)
+{
+ /* Windows threads */
+#ifdef HT_WIN_THREADS
+ HANDLE h;
+ unsigned tid;
+ ThreadParms *p;
+
+ p = (ThreadParms *)malloc(sizeof(ThreadParms));
+ if(p == NULL)
+ {
+ SetLastError((DWORD)ENOMEM);
+ return (HThreadID)HT_INVALID;
+ }
+ p->func = func;
+ p->arg = data;
+ h = (HANDLE)_beginthreadex(NULL, 0, threadfunc, p, 0, &tid);
+ if(h == (HANDLE)(0))
+ {
+ return (HThreadID)HT_INVALID;
+ }
+ if(joinable == HT_FALSE)
+ {
+ (void)CloseHandle(h);
+ return NULL;
+ }
+ return (HThreadID)h;
+
+ /* POSIX systems */
+#else
+ pthread_attr_t attr;
+ pthread_t tid;
+ int result;
+
+ (void)pthread_attr_init(&attr);
+ if(joinable == HT_FALSE)
+ {
+ (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ }
+ else
+ {
+ (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ }
+ result = pthread_create(&tid, &attr, func, data);
+ (void)pthread_attr_destroy(&attr);
+ if(result != 0)
+ {
+#ifdef HL_WINDOWS_APP
+ SetLastError((DWORD)result);
+#endif
+ return (HThreadID)HT_INVALID;
+ }
+ if(joinable == HT_FALSE)
+ {
+ return NULL;
+ }
+ return (HThreadID)tid;
+#endif
+}
+
+HL_EXP void HL_APIENTRY htThreadYield(void)
+{
+ /* Windows threads */
+#ifdef HT_WIN_THREADS
+ Sleep((DWORD)0);
+
+ /* POSIX systems */
+#else
+ (void)sched_yield();
+
+#endif
+}
+
+HL_EXP int HL_APIENTRY htThreadJoin(HThreadID threadID, void **status)
+{
+#ifdef HT_WIN_THREADS
+ /* Windows threads */
+ if(WaitForSingleObject((HANDLE)threadID, INFINITE) == WAIT_FAILED)
+ {
+ return EINVAL;
+ }
+ if(status != NULL)
+ {
+ (void)GetExitCodeThread((HANDLE)threadID, (LPDWORD)status);
+ }
+ (void)CloseHandle((HANDLE)threadID);
+ return 0;
+
+#else
+ /* POSIX systems */
+ return pthread_join((pthread_t)threadID, status);
+#endif
+}
+
+HL_EXP void HL_APIENTRY htThreadSleep(int mseconds)
+{
+#ifdef HL_WINDOWS_APP
+ Sleep((DWORD)mseconds);
+#else /* !HL_WINDOWS_APP */
+ struct timespec tv;
+
+ tv.tv_sec = mseconds / 1000;
+ tv.tv_nsec = (mseconds % 1000) * 1000;
+
+ (void)nanosleep(&tv, NULL);
+#endif /* !HL_WINDOWS_APP */
+ /* can use usleep if nanosleep is not supported on your platform */
+/* (void)usleep(mseconds*1000); */
+}
+
+
diff --git a/util/network/hawknl/src/htmutex.c b/util/network/hawknl/src/htmutex.c
new file mode 100644
index 00000000..a3fdb1c3
--- /dev/null
+++ b/util/network/hawknl/src/htmutex.c
@@ -0,0 +1,192 @@
+/*
+ HawkThreads mutex module
+ Copyright (C) 2003-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include "htinternal.h"
+
+#ifdef HT_WIN_THREADS
+
+struct ht_mutex_t
+{
+ CRITICAL_SECTION mutex;
+ DWORD thread;
+};
+#else /* !HT_WIN_THREADS */
+#include <pthread.h>
+#ifndef HL_WINDOWS_APP
+#include <sys/errno.h>
+#endif /* HL_WINDOWS_APP */
+
+
+struct ht_mutex_t
+{
+ pthread_mutex_t mutex;
+};
+#endif /* HT_WIN_THREADS */
+
+HL_EXP int HL_APIENTRY htMutexInit(HTmutex *mutex)
+{
+ if(mutex == NULL)
+ {
+ return EINVAL;
+ }
+ else
+ {
+ HTmutex mx;
+#ifdef HT_WIN_THREADS
+ /* native Windows */
+
+ mx = (HTmutex)malloc(sizeof(struct ht_mutex_t));
+ if(mx == NULL)
+ {
+ return ENOMEM;
+ }
+ InitializeCriticalSection(&mx->mutex);
+ mx->thread = 0;
+#else
+ /* POSIX */
+ pthread_mutexattr_t attr;
+ int result;
+
+ mx = (HTmutex)malloc(sizeof(struct ht_mutex_t));
+ if(mx == NULL)
+ {
+ return ENOMEM;
+ }
+ (void)pthread_mutexattr_init(&attr);
+#if defined MACOSX || defined __FreeBSD__
+ /* GUSI is not fully POSIX compliant, and does not
+ * define PTHREAD_MUTEX_ERRORCHECK
+ * http://lists.apple.com/archives/unix-porting/2005/May/msg00021.html
+ */
+ (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+#else
+ (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
+#endif
+ result = pthread_mutex_init((pthread_mutex_t *)&mx->mutex, &attr);
+ (void)pthread_mutexattr_destroy(&attr);
+ if(result != 0)
+ {
+ return result;
+ }
+#endif
+ *mutex = mx;
+ }
+ return 0;
+}
+
+HL_EXP int HL_APIENTRY htMutexLock(HTmutex *mutex)
+{
+ if(mutex == NULL)
+ {
+ return EINVAL;
+ }
+ if(*mutex == NULL)
+ {
+ return EINVAL;
+ }
+ else
+ {
+ HTmutex mx = *mutex;
+#ifdef HT_WIN_THREADS
+ DWORD threadid = GetCurrentThreadId();
+
+ /* native Windows */
+ /* this call will not stop recursion on a single thread */
+ EnterCriticalSection(&mx->mutex);
+ /* check for recursion */
+ if(mx->thread == threadid)
+ {
+ /* must call LeaveCriticalSection for each EnterCriticalSection */
+ /* so this nullifies the above call to EnterCriticalSection*/
+ LeaveCriticalSection(&mx->mutex);
+ return EDEADLK;
+ }
+ else
+ {
+ mx->thread = threadid;
+ }
+ return 0;
+#else
+ /* POSIX */
+ return pthread_mutex_lock((pthread_mutex_t *)&mx->mutex);
+#endif
+ }
+}
+
+HL_EXP int HL_APIENTRY htMutexUnlock(HTmutex *mutex)
+{
+ if(mutex == NULL)
+ {
+ return EINVAL;
+ }
+ if(*mutex == NULL)
+ {
+ return EINVAL;
+ }
+ else
+ {
+ HTmutex mx = *mutex;
+#ifdef HT_WIN_THREADS
+ DWORD threadid = GetCurrentThreadId();
+
+ /* native Windows */
+ if((mx->thread == 0) ||(mx->thread != threadid))
+ {
+ return EPERM;
+ }
+ mx->thread = 0;
+ LeaveCriticalSection(&mx->mutex);
+ return 0;
+#else
+ /* POSIX */
+ return pthread_mutex_unlock((pthread_mutex_t *)&mx->mutex);
+#endif
+ }
+}
+
+HL_EXP int HL_APIENTRY htMutexDestroy(HTmutex *mutex)
+{
+ if(mutex == NULL)
+ {
+ return EINVAL;
+ }
+ if(*mutex == NULL)
+ {
+ return EINVAL;
+ }
+ else
+ {
+ HTmutex mx = *mutex;
+ int result = 0;
+#ifdef HT_WIN_THREADS
+ /* native Windows */
+ DeleteCriticalSection(&mx->mutex);
+#else
+ /* POSIX */
+ result = pthread_mutex_destroy((pthread_mutex_t *)&mx->mutex);
+#endif
+ free(*mutex);
+ *mutex = NULL;
+ return result;
+ }
+}
+
diff --git a/util/network/hawknl/src/ipx.c b/util/network/hawknl/src/ipx.c
new file mode 100644
index 00000000..35c8a05f
--- /dev/null
+++ b/util/network/hawknl/src/ipx.c
@@ -0,0 +1,563 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+
+#define FD_SETSIZE 8192
+
+
+#if defined WIN32 || defined WIN64
+
+#include "wsock.h"
+
+#ifdef _MSC_VER
+#pragma warning (disable:4100) /* disable "unreferenced formal parameter" */
+#endif
+
+#else
+/* Unix-style systems */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#define closesocket close
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define SOCKET int
+/* define INADDR_NONE if not already */
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#define sockerrno errno
+#endif
+
+#endif
+
+#include "nlinternal.h"
+#include "sock.h"
+
+
+#ifdef NL_INCLUDE_IPX
+#include "ipx.h"
+
+typedef struct
+{
+ NLaddress /*@temp@*/*address;
+ NLchar /*@temp@*/*name;
+ NLsocket socket;
+} NLaddress_ex_t;
+
+extern SOCKET nlGroupGetFdset(NLint group, /*@out@*/ fd_set *fd);
+extern NLint sock_Error(void);
+extern NLboolean sock_SetBlocking(SOCKET socket, NLboolean arg);
+extern NLboolean sock_SetBroadcast(SOCKET socket);
+extern NLboolean sock_SetReuseAddr(nl_socket_t *sock);
+extern void sock_Close(NLsocket socket);
+extern NLsocket sock_OpenINT(NLushort port, NLenum type, NLenum driver);
+
+#define MAXHOSTNAMELEN 256
+#define NL_CONNECT_STRING "HawkNL request connection."
+#define NL_REPLY_STRING "HawkNL connection OK."
+
+static NLaddress ipx_ouraddress;
+static NLaddress ipx_ouraddress_copy;
+static NLint ipxport = 0;
+extern int backlog;
+extern NLboolean reuseaddress;
+
+
+/* is there a better way to get our address? */
+static NLboolean ipx_GetHostAddress(NLaddress *address)
+{
+ NLint addrlen = (NLint)sizeof(NLaddress);
+ SOCKET sock;
+
+ sock = socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX);
+
+ if(sock == INVALID_SOCKET)
+ {
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+ }
+
+ ((struct sockaddr_ipx *)address)->sa_family = AF_IPX;
+ memset(((struct sockaddr_ipx *)address)->sa_netnum, 0, 4);
+ memset(((struct sockaddr_ipx *)address)->sa_nodenum, 0, 6);
+ ((struct sockaddr_ipx *)address)->sa_socket = 0;
+
+ if(bind(sock, (struct sockaddr *)address, (int)sizeof(struct sockaddr_ipx)) == SOCKET_ERROR)
+ {
+ nlSetError(NL_NO_NETWORK);
+ (void)closesocket(sock);
+ return NL_FALSE;
+ }
+
+ if(getsockname(sock, (struct sockaddr *)address, &addrlen) != 0)
+ {
+ nlSetError(NL_NO_NETWORK);
+ (void)closesocket(sock);
+ return NL_FALSE;
+ }
+
+ (void)closesocket(sock);
+ return NL_TRUE;
+}
+
+NLushort ipx_GetPort(SOCKET socket)
+{
+ struct sockaddr_ipx addr;
+ int len;
+
+ len = (int)sizeof(struct sockaddr_ipx);
+ if(getsockname(socket, (struct sockaddr *)&addr, &len) != 0)
+ {
+ return 0;
+ }
+
+ return ntohs(addr.sa_socket);
+}
+
+
+NLboolean ipx_Init(void)
+{
+#ifdef HL_WINDOWS_APP
+ WSADATA libmibWSAdata;
+
+ if(WSAStartup(0x101,&libmibWSAdata) != 0)
+ {
+ return NL_FALSE;
+ }
+#endif
+ if(ipx_GetHostAddress(&ipx_ouraddress) == NL_FALSE)
+ {
+ ipx_Shutdown();
+ return NL_FALSE;
+ }
+
+ return NL_TRUE;
+}
+
+void ipx_Shutdown(void)
+{
+#ifdef HL_WINDOWS_APP
+ (void)WSACleanup();
+#endif
+}
+
+static SOCKET ipx_AcceptIPX(NLsocket nlsocket, struct sockaddr_ipx /*@out@*/ *newaddr)
+{
+ nl_socket_t *sock = nlSockets[nlsocket];
+ struct sockaddr_ipx ouraddr;
+ SOCKET newsocket;
+ NLushort localport;
+ NLbyte buffer[NL_MAX_STRING_LENGTH];
+ socklen_t len = (socklen_t)sizeof(struct sockaddr_ipx);
+ NLint slen = (NLint)sizeof(NL_CONNECT_STRING);
+ NLbyte reply = (NLbyte)0x00;
+ NLint count = 0;
+
+ /* Get the packet and remote host address */
+ if(recvfrom((SOCKET)sock->realsocket, buffer, (int)sizeof(buffer), 0,
+ (struct sockaddr *)newaddr, &len) < (int)sizeof(NL_CONNECT_STRING))
+ {
+ nlSetError(NL_NO_PENDING);
+ return INVALID_SOCKET;
+ }
+ /* Let's check for the connection string */
+ buffer[slen - 1] = (NLbyte)0; /* null terminate for peace of mind */
+ if(strcmp(buffer, NL_CONNECT_STRING) != 0)
+ {
+ nlSetError(NL_NO_PENDING);
+ return INVALID_SOCKET;
+ }
+ /* open up a new socket on this end */
+ newsocket = socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX);
+ if(newsocket == INVALID_SOCKET)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+
+ ouraddr.sa_family = AF_IPX;
+ memset(&ouraddr.sa_netnum, 0, 4);
+ memset(&ouraddr.sa_nodenum, 0, 6);
+ ouraddr.sa_socket = 0;
+
+ if(bind(newsocket, (struct sockaddr *)&ouraddr, len) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+ /* get the new port */
+ localport = ipx_GetPort(newsocket);
+
+ /* create the return message */
+ writeShort(buffer, count, localport);
+ writeString(buffer, count, (NLchar *)TEXT(NL_REPLY_STRING));
+
+ /* send back the reply with our new port */
+ if(sendto((SOCKET)sock->realsocket, buffer, count, 0, (struct sockaddr *)newaddr,
+ (int)sizeof(struct sockaddr_ipx)) < count)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+ /* send back a 0 length packet from our new port, needed for firewalls */
+ if(sendto(newsocket, &reply, 0, 0,
+ (struct sockaddr *)newaddr,
+ (int)sizeof(struct sockaddr_ipx)) < 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+ /* connect the socket */
+ if(connect(newsocket, (struct sockaddr *)newaddr,
+ (int)sizeof(struct sockaddr_ipx)) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+
+ return newsocket;
+}
+
+NLsocket ipx_AcceptConnection(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ nl_socket_t *newsock;
+ NLsocket newsocket;
+ SOCKET realsocket;
+ struct sockaddr_ipx newaddr;
+
+ if(sock->listen == NL_FALSE)
+ {
+ nlSetError(NL_NOT_LISTEN);
+ return NL_INVALID;
+ }
+
+ if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS)
+ {
+ NLint len = (NLint)sizeof(newaddr);
+
+ realsocket = accept((SOCKET)sock->realsocket,
+ (struct sockaddr *)&newaddr, &len);
+
+ if(realsocket == INVALID_SOCKET)
+ {
+ if(sockerrno == (int)EWOULDBLOCK || errno == EAGAIN)/* yes, we need to use errno here */
+ {
+ nlSetError(NL_NO_PENDING);
+ }
+ else
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ }
+ return NL_INVALID;
+ }
+ }
+ else if(sock->type == NL_UNRELIABLE)
+ {
+ realsocket = ipx_AcceptIPX(socket, &newaddr);
+
+ if(realsocket == INVALID_SOCKET)
+ {
+ /* error is already set in sock_AcceptUDP */
+ return NL_INVALID;
+ }
+ }
+ else
+ {
+ nlSetError(NL_WRONG_TYPE);
+ return NL_INVALID;
+ }
+
+ newsocket = nlGetNewSocket();
+ if(newsocket == NL_INVALID)
+ {
+ return NL_INVALID;
+ }
+ if(nlLockSocket(newsocket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ newsock = nlSockets[newsocket];
+
+ /* update the remote address */
+ memcpy((char *)&newsock->addressin, (char *)&newaddr, sizeof(struct sockaddr_ipx));
+ newsock->realsocket = (NLint)realsocket;
+ newsock->localport = ipx_GetPort(realsocket);
+ newsock->remoteport = ipx_GetPortFromAddr((NLaddress *)&newsock->addressin);
+
+ if(newsock->blocking == NL_FALSE)
+ {
+ if(sock_SetBlocking((SOCKET)newsock->realsocket, NL_FALSE) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ sock_Close(newsocket);
+ return NL_INVALID;
+ }
+ }
+
+ newsock->reliable = sock->reliable;
+
+ return newsocket;
+}
+
+NLsocket ipx_Open(NLushort port, NLenum type)
+{
+ return sock_OpenINT(port, type, NL_IPX);
+}
+
+NLchar *ipx_AddrToString(const NLaddress *address, NLchar *string)
+{
+ _stprintf(string, TEXT("%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u"),
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_netnum[0] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_netnum[1] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_netnum[2] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_netnum[3] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[0] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[1] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[2] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[3] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[4] & 0xff,
+ (unsigned int)((struct sockaddr_ipx *)address)->sa_nodenum[5] & 0xff,
+ ntohs(((struct sockaddr_ipx *)address)->sa_socket));
+ return string;
+}
+
+NLboolean ipx_StringToAddr(const NLchar *string, NLaddress *address)
+{
+ int val = 0;
+ NLchar buffer[3];
+
+ buffer[2] = (NLchar)0;
+ memset(address, 0, sizeof(NLaddress));
+ ((struct sockaddr_ipx *)address)->sa_family = AF_IPX;
+ address->valid = NL_FALSE;
+
+#define DO(src,dest) \
+ buffer[0] = string[(sizeof(NLchar) * src)]; \
+ buffer[1] = string[src + 1]; \
+ if(_stscanf (buffer, (const NLchar *)TEXT("%x"), &val) != 1) \
+ return NL_FALSE; \
+ ((struct sockaddr_ipx *)address)->dest = (char)val
+
+ DO(0, sa_netnum[0]);
+ DO(2, sa_netnum[1]);
+ DO(4, sa_netnum[2]);
+ DO(6, sa_netnum[3]);
+ DO(9, sa_nodenum[0]);
+ DO(11, sa_nodenum[1]);
+ DO(13, sa_nodenum[2]);
+ DO(15, sa_nodenum[3]);
+ DO(17, sa_nodenum[4]);
+ DO(19, sa_nodenum[5]);
+#undef DO
+
+ (void)_stscanf(&string[(sizeof(NLchar) * 22)], (const NLchar *)TEXT("%d"), &val);
+ ((struct sockaddr_ipx *)address)->sa_socket = htons((unsigned short)val);
+ address->valid = NL_TRUE;
+ return NL_TRUE;
+}
+
+NLboolean ipx_GetLocalAddr(NLsocket socket, NLaddress *address)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ memcpy(address, &ipx_ouraddress, sizeof(NLaddress));
+ ipx_SetAddrPort(address, sock->localport);
+ address->valid = NL_TRUE;
+ return NL_TRUE;
+}
+
+NLaddress *ipx_GetAllLocalAddr(NLint *count)
+{
+ *count = 1;
+ memcpy(&ipx_ouraddress_copy, &ipx_ouraddress, sizeof(NLaddress));
+ ipx_ouraddress_copy.valid = NL_TRUE;
+ return &ipx_ouraddress_copy;
+}
+
+NLboolean ipx_SetLocalAddr(const NLaddress *address)
+{
+ memcpy(&ipx_ouraddress, address, sizeof(NLaddress));
+ return NL_TRUE;
+}
+
+NLchar *ipx_GetNameFromAddr(const NLaddress *address, NLchar *name)
+{
+ return ipx_AddrToString(address, name);
+}
+
+NLboolean ipx_GetNameFromAddrAsync(const NLaddress *address, NLchar *name)
+{
+ (void)ipx_AddrToString(address, name);
+ return NL_TRUE;
+}
+
+NLboolean ipx_GetAddrFromName(const NLchar *name, NLaddress *address)
+{
+ NLint n;
+ NLchar buffer[(sizeof(NLchar) * 32)];
+
+ address->valid = NL_TRUE;
+ n = (NLint)_tcslen(name);
+
+ if(n == (NLint)(sizeof(NLchar) * 12))
+ {
+ _stprintf(buffer, TEXT("00000000:%s:%d"), name, ipxport);
+ return ipx_StringToAddr (buffer, address);
+ }
+ if(n == (NLint)(sizeof(NLchar) * 21))
+ {
+ _stprintf(buffer, TEXT("%s:%d"), name, ipxport);
+ return ipx_StringToAddr (buffer, address);
+ }
+ if((n > (NLint)(sizeof(NLchar) * 21)) && (n <= (NLint)(sizeof(NLchar) * 27)))
+ {
+ return ipx_StringToAddr (name, address);
+ }
+ memset(address, 0, sizeof(NLaddress));
+ address->valid = NL_FALSE;
+ return NL_FALSE;
+}
+
+NLboolean ipx_GetAddrFromNameAsync(const NLchar *name, NLaddress *address)
+{
+ return ipx_GetAddrFromName(name, address);
+}
+
+NLboolean ipx_AddrCompare(const NLaddress *address1, const NLaddress *address2)
+{
+ if(((struct sockaddr_ipx *)address1)->sa_family != ((struct sockaddr_ipx *)address2)->sa_family)
+ return NL_FALSE;
+
+ if(memcmp(((struct sockaddr_ipx *)address1)->sa_netnum, ((struct sockaddr_ipx *)address2)->sa_netnum, 4) != 0)
+ return NL_FALSE;
+ if(memcmp(((struct sockaddr_ipx *)address1)->sa_nodenum, ((struct sockaddr_ipx *)address2)->sa_nodenum, 6) != 0)
+ return NL_FALSE;
+
+ if(((struct sockaddr_ipx *)address1)->sa_socket != ((struct sockaddr_ipx *)address2)->sa_socket)
+ return NL_FALSE;
+
+ return NL_TRUE;
+}
+
+NLushort ipx_GetPortFromAddr(const NLaddress *address)
+{
+ return ntohs(((struct sockaddr_ipx *)address)->sa_socket);
+}
+
+void ipx_SetAddrPort(NLaddress *address, NLushort port)
+{
+ ((struct sockaddr_ipx *)address)->sa_socket = htons((NLushort)port);
+}
+
+NLboolean ipx_Hint(NLenum name, NLint arg)
+{
+ switch(name) {
+
+ case NL_LISTEN_BACKLOG:
+ backlog = arg;
+ break;
+
+ case NL_REUSE_ADDRESS:
+ reuseaddress = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean ipx_SetSocketOpt(NLsocket socket, NLenum name, NLint arg)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ sock->blocking = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
+ if(sock_SetBlocking((SOCKET)sock->realsocket, sock->blocking) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ break;
+ case NL_REUSE_ADDRESS:
+ if(sock_SetReuseAddr(sock) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLint ipx_GetSocketOpt(NLsocket socket, NLenum name)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ return (NLint)sock->blocking;
+
+ case NL_REUSE_ADDRESS:
+ return (NLint)sock->reuseaddr;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_INVALID;
+ }
+}
+
+#else /* NL_INCLUDE_IPX */
+/* include dummy functions so that sock.c will compile */
+NLushort ipx_GetPort(SOCKET socket)
+{
+ return 0;
+}
+
+NLushort ipx_GetPortFromAddr(const NLaddress *address)
+{
+ return 0;
+}
+
+#endif /* NL_INCLUDE_IPX */
diff --git a/util/network/hawknl/src/loopback.c b/util/network/hawknl/src/loopback.c
new file mode 100644
index 00000000..f13aff8a
--- /dev/null
+++ b/util/network/hawknl/src/loopback.c
@@ -0,0 +1,1045 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+
+#include <string.h>
+#include <stdio.h>
+
+#if defined (_WIN32_WCE)
+#define errno GetLastError()
+#else
+#include <errno.h>
+#endif
+
+#include "nlinternal.h"
+
+#ifdef HL_WINDOWS_APP
+/* Windows systems */
+
+#include "wsock.h"
+
+#else
+/* Unix-style systems or macs with posix support */
+#include <netinet/in.h> /* for ntohs and htons */
+#endif
+
+#ifdef NL_INCLUDE_LOOPBACK
+#include "loopback.h"
+
+static NLaddress loopback_ouraddress;
+static NLint loopgroup;
+static volatile NLboolean reuseaddress = NL_FALSE;
+
+static HTmutex portlock; /* In memory of my step-father, Don Portlock,
+ who passed away Jan 12, 2001 - Phil */
+
+static volatile NLushort newport = 1024;
+
+static NLushort loopback_getNextPort(void)
+{
+ (void)htMutexLock(&portlock);
+ newport += 1;
+ if (newport < 1024){
+ newport = 1024;
+ }
+ (void)htMutexUnlock(&portlock);
+ return newport;
+}
+
+static NLboolean loopback_ScanPort(NLushort port, NLenum type)
+{
+ NLint numsockets = NL_MAX_GROUP_SOCKETS;
+ NLsocket temp[NL_MAX_GROUP_SOCKETS];
+
+ if(reuseaddress == NL_TRUE)
+ {
+ return NL_TRUE;
+ }
+ if(nlGroupGetSockets(loopgroup, (NLsocket *)&temp, &numsockets) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ if(numsockets == 0)
+ {
+ return NL_TRUE;
+ }
+ while(numsockets-- > 0)
+ {
+ nl_socket_t *sock = nlSockets[temp[numsockets]];
+
+ if(sock->type == type && sock->localport == port)
+ {
+ return NL_FALSE;
+ }
+ }
+ return NL_TRUE;
+}
+
+static NLushort loopback_TryPort(NLushort port, NLenum type)
+{
+ NLint ntries = 500; /* this is to prevent an infinite loop */
+
+ if(port > 0)
+ {
+ if(loopback_ScanPort(port, type) == NL_TRUE)
+ {
+ return port;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ /* let's find our own port number */
+ while(ntries-- > 0)
+ {
+ port = loopback_getNextPort();
+ if(loopback_ScanPort(port, type) == NL_TRUE)
+ {
+ return port;
+ }
+ }
+ return 0;
+}
+
+NLboolean loopback_Init(void)
+{
+ loopgroup = nlGroupCreate();
+
+ if(loopgroup == NL_INVALID)
+ {
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+void loopback_Shutdown(void)
+{
+ (void)nlGroupDestroy(loopgroup);
+}
+
+NLboolean loopback_Listen(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ NLint i = NL_MAX_ACCEPT;
+
+ if(sock->type == NL_BROADCAST)
+ {
+ nlSetError(NL_WRONG_TYPE);
+ return NL_FALSE;
+ }
+ sock->listen = NL_TRUE;
+ while(i-- > 0)
+ {
+ sock->ext->accept[i] = NL_INVALID;
+ }
+ return NL_TRUE;
+}
+
+NLsocket loopback_AcceptConnection(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ if(sock->listen == NL_FALSE)
+ {
+ nlSetError(NL_NOT_LISTEN);
+ return NL_INVALID;
+ }
+ if(sock->inuse == NL_FALSE)
+ {
+ /* socket was closed by nlShutdown */
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_INVALID;
+ }
+ if(sock->ext == NULL)
+ {
+ /* socket was closed on another thread */
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_INVALID;
+ }
+ if(sock->ext->accept[0] != NL_INVALID)
+ {
+ NLsocket newsocket;
+ NLsocket osock = sock->ext->accept[0];
+ nl_socket_t *othersock = nlSockets[osock];
+
+ /* make sure the other socket is valid */
+ if(nlIsValidSocket(osock) == NL_FALSE)
+ {
+ NLint i;
+
+ for(i=1;i<NL_MAX_ACCEPT;i++)
+ {
+ sock->ext->accept[i-1] = sock->ext->accept[i];
+ }
+ sock->ext->accept[NL_MAX_ACCEPT-1] = NL_INVALID;
+ return loopback_AcceptConnection(socket);
+ }
+ newsocket = loopback_Open(0, sock->type);
+ if(newsocket != NL_INVALID)
+ {
+ NLint i;
+ nl_socket_t *newsock = nlSockets[newsocket];
+
+ /* we must unlock the socket briefly or else nlConnect will deadlock */
+ nlUnlockSocket(socket, NL_BOTH);
+ if(nlLockSocket(osock, NL_READ) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ (void)nlLockSocket(socket, NL_BOTH);
+ /* do the connecting */
+ newsock->ext->consock = osock;
+ newsock->remoteport = othersock->localport;
+ othersock->ext->consock = newsocket;
+ othersock->remoteport = newsock->localport;
+ newsock->connected = NL_TRUE;
+ loopback_SetAddrPort(&othersock->addressin, othersock->remoteport);
+ loopback_SetAddrPort(&newsock->addressin, newsock->remoteport);
+ othersock->connected = NL_TRUE;
+ othersock->connecting = NL_FALSE;
+ /* move the accept que down one */
+ for(i=1;i<NL_MAX_ACCEPT;i++)
+ {
+ sock->ext->accept[i-1] = sock->ext->accept[i];
+ }
+ sock->ext->accept[NL_MAX_ACCEPT-1] = NL_INVALID;
+ nlUnlockSocket(socket, NL_BOTH);
+ nlUnlockSocket(osock, NL_READ);
+ (void)nlLockSocket(socket, NL_BOTH);
+ return newsocket;
+ }
+ }
+ nlSetError(NL_NO_PENDING);
+ return NL_INVALID;
+}
+
+NLsocket loopback_Open(NLushort port, NLenum type)
+{
+ nl_socket_t *newsock;
+ NLsocket newsocket;
+ NLint i;
+ NLushort lport;
+
+ switch (type) {
+
+ case NL_RELIABLE:
+ case NL_UNRELIABLE:
+ case NL_RELIABLE_PACKETS:
+ case NL_BROADCAST:
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_INVALID;
+ }
+
+ lport = loopback_TryPort(port, type);
+ if(lport == 0)
+ {
+ nlSetError(NL_INVALID_PORT);
+ return NL_INVALID;
+ }
+ newsocket = nlGetNewSocket();
+ if(newsocket == NL_INVALID)
+ {
+ return NL_INVALID;
+ }
+ if(nlLockSocket(newsocket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ newsock = nlSockets[newsocket];
+ newsock->type = type;
+ newsock->localport = lport;
+ if(type == NL_BROADCAST)
+ {
+ newsock->remoteport = lport;
+ }
+
+ if((newsock->ext = (nl_extra_t *)malloc(sizeof(nl_extra_t))) == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ nlUnlockSocket(newsocket, NL_BOTH);
+ loopback_Close(newsocket);
+ return NL_INVALID;
+ }
+ /* clear out the structure */
+ memset(newsock->ext, 0, sizeof(nl_extra_t));
+ for(i=0;i<NL_NUM_PACKETS;i++)
+ {
+ NLboolean err = NL_FALSE;
+
+ /* malloc the max packet length plus two bytes for the port number */
+ if((newsock->ext->inpacket[i] = (NLbyte *)malloc((size_t)(NL_MAX_PACKET_LENGTH + 2))) == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ err = NL_TRUE;
+ }
+ if(err == NL_TRUE)
+ {
+ while(i-- > 0)
+ {
+ free(newsock->ext->inpacket[i]);
+ }
+ nlUnlockSocket(newsocket, NL_BOTH);
+ loopback_Close(newsocket);
+ return NL_INVALID;
+ }
+ }
+
+ (void)nlGroupAddSocket(loopgroup, newsocket);
+ nlUnlockSocket(newsocket, NL_BOTH);
+
+ return newsocket;
+}
+
+NLboolean loopback_Connect(NLsocket socket, const NLaddress *address)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ NLushort port;
+ NLint numsockets = NL_MAX_GROUP_SOCKETS;
+ NLsocket temp[NL_MAX_GROUP_SOCKETS];
+
+ /* no need to connect a broadcast socket */
+ if(sock->type == NL_BROADCAST)
+ {
+ nlSetError(NL_WRONG_TYPE);
+ }
+ port = loopback_GetPortFromAddr(address);
+ /* make sure socket is not already connected */
+ if(sock->connected == NL_TRUE)
+ {
+ nlSetError(NL_CONNECTED);
+ return NL_FALSE;
+ }
+ if(sock->connecting == NL_TRUE)
+ {
+ nlSetError(NL_CON_PENDING);
+ return NL_FALSE;
+ }
+ if(nlGroupGetSockets(loopgroup, (NLsocket *)&temp, &numsockets) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ if(numsockets == 0)
+ {
+ return NL_FALSE;
+ }
+ while(numsockets-- > 0)
+ {
+ NLsocket s = temp[numsockets];
+ nl_socket_t *othersock = nlSockets[s];
+
+ if(sock->type == othersock->type && port == othersock->localport
+ && othersock->listen == NL_TRUE && othersock->connected == NL_FALSE
+ && othersock->connecting == NL_FALSE)
+ {
+ /* we found the right socket, so connect */
+ NLint i;
+
+ if(nlLockSocket(s, NL_BOTH) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ for(i=0;i<NL_MAX_ACCEPT;i++)
+ {
+ if(othersock->ext->accept[i] == NL_INVALID)
+ {
+ othersock->ext->accept[i] = socket;
+ sock->connecting = NL_TRUE;
+ sock->ext->consock = s;
+ nlUnlockSocket(s, NL_BOTH);
+ if(sock->blocking == NL_TRUE)
+ {
+ nlUnlockSocket(socket, NL_BOTH);
+ /* wait for nlAccept to be called */
+ while(sock->connecting == NL_TRUE)
+ {
+ if(sock->inuse == NL_FALSE)
+ {
+ /* nlShutdown has been called */
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ htThreadSleep(NL_CONNECT_SLEEP);
+ }
+ (void)nlLockSocket(socket, NL_BOTH);
+ }
+ return NL_TRUE;
+ }
+ }
+ nlUnlockSocket(s, NL_BOTH);
+ }
+ }
+ nlSetError(NL_CON_REFUSED);
+ return NL_FALSE;
+}
+
+void loopback_Close(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ int i;
+
+ if(sock->connected == NL_TRUE || sock->connecting == NL_TRUE)
+ {
+ /* break the connection */
+ nl_socket_t *othersock = nlSockets[sock->ext->consock];
+
+ if(othersock->ext != NULL)
+ {
+ othersock->ext->consock = NL_INVALID;
+ }
+ othersock->connected = NL_FALSE;
+ sock->connected = NL_FALSE;
+ sock->listen = NL_FALSE;
+ if(sock->type != NL_BROADCAST)
+ {
+ /* this allows nlPollGroup to report socket is readable */
+ /* so that the app can get the NL_SOCK_DISCONNECT message*/
+ if(othersock->ext != NULL)
+ {
+ othersock->ext->inlen[othersock->ext->nextinused] = -1;
+ }
+ }
+ }
+ for(i=0;i<NL_NUM_PACKETS;i++)
+ {
+ void /*@owned@*/*t = sock->ext->inpacket[i];
+
+ free(t);
+ sock->ext->inpacket[i] = NULL;
+ }
+ free(sock->ext);
+ sock->ext = NULL;
+}
+
+NLint loopback_Read(NLsocket socket, NLvoid *buffer, NLint nbytes)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ NLint len = sock->ext->inlen[sock->ext->nextinused];
+ NLint c = 0;
+ NLushort port;
+
+ if(sock->blocking == NL_TRUE)
+ {
+ while(len == 0)
+ {
+ nlUnlockSocket(socket, NL_READ);
+ htThreadSleep(NL_CONNECT_SLEEP);
+ (void)nlLockSocket(socket, NL_READ);
+ if(sock->inuse == NL_FALSE)
+ {
+ /* nlShutdown has been called */
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_INVALID;
+ }
+ len = sock->ext->inlen[sock->ext->nextinused];
+ }
+ }
+ if(len > 0)
+ {
+ if(len > nbytes)
+ {
+ nlSetError(NL_BUFFER_SIZE);
+ return NL_INVALID;
+ }
+ if(sock->connecting == NL_TRUE)
+ {
+ nlSetError(NL_CON_PENDING);
+ return NL_INVALID;
+ }
+ /* get the port number */
+ readShort(sock->ext->inpacket[sock->ext->nextinused], c, port);
+ loopback_SetAddrPort(&sock->addressin, port);
+ /* copy the packet */
+ memcpy(buffer, sock->ext->inpacket[sock->ext->nextinused] + 2, (size_t)len);
+ /* zero out length and set up for next packet */
+ sock->ext->inlen[sock->ext->nextinused] = 0;
+ sock->ext->nextinused++;
+ if(sock->ext->nextinused >= NL_NUM_PACKETS)
+ {
+ sock->ext->nextinused = 0;
+ }
+ }
+ /* check for broken connection */
+ else if((len == -1) || (sock->connected == NL_TRUE && sock->ext->consock == NL_INVALID)
+ || (sock->connected == NL_FALSE && sock->type != NL_BROADCAST))
+ {
+ nlSetError(NL_SOCK_DISCONNECT);
+ return NL_INVALID;
+ }
+ return len;
+}
+
+static NLint loopback_WritePacket(NLsocket to, const NLvoid *buffer, NLint nbytes, NLushort fromport)
+{
+ nl_socket_t *sock = nlSockets[to];
+ NLint i, j;
+ NLint c = 0;
+
+ /* check the packet size */
+ if(nbytes > NL_MAX_PACKET_LENGTH)
+ {
+ nlSetError(NL_PACKET_SIZE);
+ return NL_INVALID;
+ }
+ if(nlLockSocket(to, NL_READ) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ /* make sure we have an empty packet buffer */
+ if(sock->ext->nextinfree == NL_INVALID)
+ {
+ /* all buffers were filled by last write */
+ /* check to see if any were emptied by a read */
+ i = NL_NUM_PACKETS;
+ j = sock->ext->nextinused;
+
+ while(i-- > 0)
+ {
+ if(sock->ext->inlen[j] == 0)
+ {
+ /* found the first free */
+ sock->ext->nextinfree = j;
+ break;
+ }
+ j++;
+ if(j >= NL_NUM_PACKETS)
+ {
+ j = 0;
+ }
+ }
+ if(sock->ext->nextinfree == NL_INVALID)
+ {
+ nlUnlockSocket(to, NL_READ);
+ /* none are free */
+ if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS)
+ {
+ return 0;
+ }
+ else
+ {
+ /* silently fail */
+ return nbytes;
+ }
+ }
+ }
+ /* write the port number */
+ writeShort(sock->ext->inpacket[sock->ext->nextinfree], c, fromport);
+ /* copy the packet buffer */
+ memcpy(sock->ext->inpacket[sock->ext->nextinfree] + 2, buffer, (size_t)nbytes);
+ sock->ext->inlen[sock->ext->nextinfree] = nbytes;
+ sock->ext->nextinfree++;
+ if(sock->ext->nextinfree >= NL_NUM_PACKETS)
+ {
+ sock->ext->nextinfree = 0;
+ }
+ /* check for full packet buffers */
+ if(sock->ext->inlen[sock->ext->nextinfree] != 0)
+ {
+ sock->ext->nextinfree = NL_INVALID;
+ }
+ nlUnlockSocket(to, NL_READ);
+ return nbytes;
+}
+
+NLint loopback_Write(NLsocket socket, const NLvoid *buffer, NLint nbytes)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ nl_socket_t *othersock;
+ NLsocket s[NL_MAX_GROUP_SOCKETS];
+ NLint number = NL_MAX_GROUP_SOCKETS;
+ NLint i;
+ NLint count;
+
+ switch (sock->type) {
+
+ case NL_RELIABLE:
+ case NL_RELIABLE_PACKETS:
+ default:
+ {
+ if(sock->connected == NL_TRUE)
+ {
+ /* check for broken connection */
+ if(sock->ext->consock == NL_INVALID)
+ {
+ nlSetError(NL_SOCK_DISCONNECT);
+ return NL_INVALID;
+ }
+ count = loopback_WritePacket(sock->ext->consock, buffer, nbytes, sock->localport);
+ }
+ else if(sock->connecting == NL_TRUE)
+ {
+ nlSetError(NL_CON_PENDING);
+ return NL_INVALID;
+ }
+ else
+ {
+ nlSetError(NL_SOCK_DISCONNECT);
+ return NL_INVALID;
+ }
+ }
+ break;
+ case NL_UNRELIABLE:
+ {
+ if(sock->connected == NL_TRUE)
+ {
+ /* check for broken connection */
+ if(sock->ext->consock == NL_INVALID)
+ {
+ nlSetError(NL_SOCK_DISCONNECT);
+ return NL_INVALID;
+ }
+ count = loopback_WritePacket(sock->ext->consock, buffer, nbytes, sock->localport);
+ }
+ else if(sock->connecting == NL_TRUE)
+ {
+ nlSetError(NL_CON_PENDING);
+ return NL_INVALID;
+ }
+ /* unconnected UDP emulation */
+ count = nbytes;
+ (void)nlGroupGetSockets(loopgroup, (NLsocket *)s, &number);
+ for(i=0;i<number;i++)
+ {
+ if(nlIsValidSocket(s[i]) == NL_TRUE)
+ {
+ othersock = nlSockets[s[i]];
+
+ if(sock->remoteport == othersock->localport &&
+ othersock->connected == NL_FALSE &&
+ sock->type == othersock->type)
+ {
+ (void)loopback_WritePacket(s[i], buffer, nbytes, sock->localport);
+ }
+ }
+ }
+ }
+ break;
+ case NL_BROADCAST:
+ {
+ count = nbytes;
+ (void)nlGroupGetSockets(loopgroup, (NLsocket *)s, &number);
+ for(i=0;i<number;i++)
+ {
+ if(nlIsValidSocket(s[i]) == NL_TRUE)
+ {
+ othersock = nlSockets[s[i]];
+
+ if(sock->localport == othersock->localport &&
+ sock->type == othersock->type)
+ {
+ (void)loopback_WritePacket(s[i], buffer, nbytes, sock->localport);
+ }
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+NLchar *loopback_AddrToString(const NLaddress *address, NLchar *string)
+{
+ _stprintf(string, TEXT("127.0.0.1:%u"), loopback_GetPortFromAddr(address));
+
+ return string;
+}
+
+NLboolean loopback_StringToAddr(const NLchar *string, NLaddress *address)
+{
+ NLchar *st;
+ NLint port;
+
+ memset(address, 0, sizeof(NLaddress));
+ address->valid = NL_TRUE;
+ /* check for a port number */
+ st = _tcschr(string, TEXT(':'));
+ if(st != NULL)
+ {
+ st++;
+ port = _ttoi(st);
+ if(port < 0 || port > 65535)
+ {
+ nlSetError(NL_BAD_ADDR);
+ address->valid = NL_FALSE;
+ return NL_FALSE;
+ }
+ loopback_SetAddrPort(address, (NLushort)port);
+ }
+ return NL_TRUE;
+}
+
+NLboolean loopback_GetLocalAddr(NLsocket socket, NLaddress *address)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ memset(address, 0, sizeof(NLaddress));
+ loopback_SetAddrPort(address, sock->localport);
+ address->valid = NL_TRUE;
+ return NL_TRUE;
+}
+
+NLaddress *loopback_GetAllLocalAddr(NLint *count)
+{
+ *count = 1;
+ memset(&loopback_ouraddress, 0, sizeof(NLaddress));
+ loopback_ouraddress.valid = NL_TRUE;
+ return &loopback_ouraddress;
+}
+
+NLboolean loopback_SetLocalAddr(const NLaddress *address)
+{
+ /* this is just to keep compilers happy */
+ if(address == NULL)
+ {
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLchar *loopback_GetNameFromAddr(const NLaddress *address, NLchar *name)
+{
+ _stprintf(name, TEXT("%s:%u"), TEXT("localhost"), loopback_GetPortFromAddr(address));
+ return name;
+}
+
+NLboolean loopback_GetNameFromAddrAsync(const NLaddress *address, NLchar *name)
+{
+ (void)loopback_GetNameFromAddr(address, name);
+ return NL_TRUE;
+}
+
+NLboolean loopback_GetAddrFromName(const NLchar *name, NLaddress *address)
+{
+ return loopback_StringToAddr(name, address);
+}
+
+NLboolean loopback_GetAddrFromNameAsync(const NLchar *name, NLaddress *address)
+{
+ return loopback_GetAddrFromName(name, address);
+}
+
+NLboolean loopback_AddrCompare(const NLaddress *address1, const NLaddress *address2)
+{
+ if(*(NLushort *)(&address1->addr[0]) == *(NLushort *)(&address2->addr[0]))
+ {
+ return NL_TRUE;
+ }
+ return NL_FALSE;
+}
+
+NLushort loopback_GetPortFromAddr(const NLaddress *address)
+{
+ return *(NLushort *)(&address->addr[0]);
+}
+
+void loopback_SetAddrPort(NLaddress *address, NLushort port)
+{
+ *(NLushort *)(&address->addr[0]) = port;
+}
+
+NLint loopback_GetSystemError(void)
+{
+ return errno;
+}
+
+NLint loopback_PollGroup(NLint group, NLenum name, NLsocket *sockets, NLint number, NLint timeout)
+{
+ NLint count = 0;
+ NLint numsockets = NL_MAX_GROUP_SOCKETS;
+ NLsocket temp[NL_MAX_GROUP_SOCKETS];
+ NLtime end, now;
+
+ nlGroupLock();
+ if(nlGroupGetSocketsINT(group, (NLsocket *)&temp, &numsockets) == NL_FALSE)
+ {
+ /* any error is set by nlGroupGetSockets */
+ nlGroupUnlock();
+ return NL_INVALID;
+ }
+ nlGroupUnlock();
+ if(numsockets == 0)
+ {
+ return 0;
+ }
+
+ (void)nlTime(&now);
+ end.seconds = now.seconds;
+ end.mseconds = now.mseconds;
+ if(timeout > 0)
+ {
+ end.mseconds += timeout;
+ while(end.mseconds > 999)
+ {
+ end.mseconds -= 1000;
+ end.seconds++;
+ }
+ }
+
+ while(count == 0)
+ {
+ switch(name) {
+
+ case NL_READ_STATUS:
+ {
+ NLint i = 0;
+ NLint j = numsockets;
+
+ while(j-- > 0)
+ {
+ /* check for a packet */
+ nl_socket_t *sock;
+
+ if(nlIsValidSocket(temp[i]) != NL_TRUE)
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_INVALID;
+ }
+ sock = nlSockets[temp[i]];
+
+ if(sock->ext->inlen[sock->ext->nextinused] != 0)
+ {
+ *sockets = temp[i];
+ sockets++;
+ count++;
+ if(count > number)
+ {
+ nlSetError(NL_BUFFER_SIZE);
+ return NL_INVALID;
+ }
+ }
+ i++;
+ }
+ }
+ break;
+
+ case NL_WRITE_STATUS:
+ {
+ NLint i = 0;
+ NLint j = numsockets;
+
+ while(j-- > 0)
+ {
+ nl_socket_t *sock;
+
+ if(nlIsValidSocket(temp[i]) != NL_TRUE)
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_INVALID;
+ }
+ sock = nlSockets[temp[i]];
+
+ /* check for a free packet if reliable and connected */
+ if((sock->type == NL_TCP || sock->type == NL_TCP_PACKETS)
+ && (sock->connecting == NL_TRUE || sock->connected == NL_TRUE))
+ {
+ nl_socket_t *othersock = nlSockets[sock->ext->consock];
+
+ if(othersock->ext->nextinfree == NL_INVALID)
+ {
+ continue;
+ }
+ }
+ /* add the socket to the list */
+ *sockets = temp[i];
+ sockets++;
+ count++;
+ if(count > number)
+ {
+ nlSetError(NL_BUFFER_SIZE);
+ return NL_INVALID;
+ }
+ i++;
+ }
+ }
+ break;
+
+ case NL_ERROR_STATUS:
+ {
+ NLint i = 0;
+ NLint j = numsockets;
+
+ while(j-- > 0)
+ {
+ nl_socket_t *sock;
+
+ if(nlIsValidSocket(temp[i]) != NL_TRUE)
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_INVALID;
+ }
+ sock = nlSockets[temp[i]];
+
+ if(sock->connected == NL_FALSE && sock->type != NL_UDP_BROADCAST)
+ {
+ /* add the socket to the list */
+ *sockets = temp[i];
+ sockets++;
+ count++;
+ if(count > number)
+ {
+ nlSetError(NL_BUFFER_SIZE);
+ return NL_INVALID;
+ }
+ i++;
+ }
+ }
+ }
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_INVALID;
+ }
+ if(timeout != 0)
+ {
+ htThreadSleep(1);
+ (void)nlTime(&now);
+ if(timeout > 0 && (now.seconds > end.seconds || (now.seconds == end.seconds && now.mseconds > end.mseconds)))
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return count;
+}
+
+NLboolean loopback_PollSocket(NLsocket socket, NLenum name, NLint timeout)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ NLtime end, now;
+
+ nlSetError(NL_NO_ERROR);
+ (void)nlTime(&now);
+ end.seconds = now.seconds;
+ end.mseconds = now.mseconds;
+ if(timeout > 0)
+ {
+ end.mseconds += timeout;
+ while(end.mseconds > 999)
+ {
+ end.mseconds -= 1000;
+ end.seconds++;
+ }
+ }
+
+ while(!(timeout > 0 && (now.seconds > end.seconds || (now.seconds == end.seconds && now.mseconds > end.mseconds))))
+ {
+ switch(name) {
+
+ case NL_READ_STATUS:
+ if(sock->ext->inlen[sock->ext->nextinused] > 0)
+ return NL_TRUE;
+ break;
+
+ case NL_WRITE_STATUS:
+ /* check for a free packet if reliable and connected */
+ if((sock->type == NL_TCP || sock->type == NL_TCP_PACKETS)
+ && (sock->connecting == NL_TRUE || sock->connected == NL_TRUE))
+ {
+ nl_socket_t *othersock = nlSockets[sock->ext->consock];
+
+ if(othersock->ext->nextinfree != NL_INVALID)
+ {
+ return NL_TRUE;
+ }
+ }
+ else
+ {
+ return NL_TRUE;
+ }
+ break;
+
+ case NL_ERROR_STATUS:
+ if(sock->connected == NL_FALSE && sock->type != NL_UDP_BROADCAST)
+ return NL_TRUE;
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ }
+ if(timeout != 0)
+ {
+ htThreadSleep(1);
+ (void)nlTime(&now);
+ }
+ else
+ {
+ break;
+ }
+ }
+ return NL_FALSE;
+}
+
+NLboolean loopback_Hint(NLenum name, NLint arg)
+{
+ switch (name) {
+
+ case NL_REUSE_ADDRESS:
+ reuseaddress = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean loopback_SetSocketOpt(NLsocket socket, NLenum name, NLint arg)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ sock->blocking = (NLboolean)((NLboolean)arg != NL_FALSE ? NL_FALSE : NL_TRUE);
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLint loopback_GetSocketOpt(NLsocket socket, NLenum name)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ return (NLint)sock->blocking;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_INVALID;
+ }
+}
+
+#endif /* NL_INCLUDE_LOOPBACK */
+
diff --git a/util/network/hawknl/src/nl.c b/util/network/hawknl/src/nl.c
new file mode 100644
index 00000000..b99143de
--- /dev/null
+++ b/util/network/hawknl/src/nl.c
@@ -0,0 +1,1928 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include <string.h>
+#include "nlinternal.h"
+#include "sock.h"
+#include "serial.h"
+#include "parallel.h"
+
+#ifdef NL_INCLUDE_LOOPBACK
+#include "loopback.h"
+#endif
+
+#if defined HL_WINDOWS_APP && defined NL_INCLUDE_IPX
+ #include "ipx.h"
+#endif
+
+#define MAX_NET_DRIVERS 6
+
+volatile nl_state_t nlState = {NL_FALSE, NL_TRUE};
+
+/* mutexes for global variables */
+static HTmutex socklock, instatlock, outstatlock;
+
+static volatile NLboolean nlBlocking = NL_FALSE;
+
+static volatile nl_stats_t nlInstats;
+static volatile nl_stats_t nlOutstats;
+
+static volatile NLsocket nlNextsocket = 0;
+static volatile NLint nlNumsockets = 0;
+static volatile NLint nlMaxNumsockets = NL_MIN_SOCKETS; /* this is dynamic, and can grow as needed */
+static volatile NLint nlInitCount = 0;
+
+pnl_socket_t *nlSockets = NULL;
+
+/* the current selected driver */
+static nl_netdriver_t /*@null@*/*driver = NULL;
+
+static nl_netdriver_t netdrivers[] =
+{
+ {
+ (NLchar*)TEXT("NL_IP"),
+ (NLchar*)TEXT("NL_RELIABLE NL_UNRELIABLE NL_RELIABLE_PACKETS NL_BROADCAST NL_UDP_MULTICAST NL_MULTICAST"),
+ NL_IP,
+ NL_FALSE,
+ sock_Init,
+ sock_Shutdown,
+ sock_Listen,
+ sock_AcceptConnection,
+ sock_Open,
+ sock_Connect,
+ sock_Close,
+ sock_Read,
+ sock_Write,
+ sock_AddrToString,
+ sock_StringToAddr,
+ sock_GetLocalAddr,
+ sock_GetAllLocalAddr,
+ sock_SetLocalAddr,
+ sock_GetNameFromAddr,
+ sock_GetNameFromAddrAsync,
+ sock_GetAddrFromName,
+ sock_GetAddrFromNameAsync,
+ sock_AddrCompare,
+ sock_GetPortFromAddr,
+ sock_SetAddrPort,
+ sock_GetSystemError,
+ sock_PollGroup,
+ sock_PollSocket,
+ sock_Hint,
+ sock_SetSocketOpt,
+ sock_GetSocketOpt
+ }
+#ifdef NL_INCLUDE_LOOPBACK
+ ,
+ {
+ (NLchar*)TEXT("NL_LOOP_BACK"),
+ (NLchar*)TEXT("NL_RELIABLE NL_UNRELIABLE NL_RELIABLE_PACKETS NL_BROADCAST"),
+ NL_LOOP_BACK,
+ NL_FALSE,
+ loopback_Init,
+ loopback_Shutdown,
+ loopback_Listen,
+ loopback_AcceptConnection,
+ loopback_Open,
+ loopback_Connect,
+ loopback_Close,
+ loopback_Read,
+ loopback_Write,
+ loopback_AddrToString,
+ loopback_StringToAddr,
+ loopback_GetLocalAddr,
+ loopback_GetAllLocalAddr,
+ loopback_SetLocalAddr,
+ loopback_GetNameFromAddr,
+ loopback_GetNameFromAddrAsync,
+ loopback_GetAddrFromName,
+ loopback_GetAddrFromNameAsync,
+ loopback_AddrCompare,
+ loopback_GetPortFromAddr,
+ loopback_SetAddrPort,
+ loopback_GetSystemError,
+ loopback_PollGroup,
+ loopback_PollSocket,
+ loopback_Hint,
+ loopback_SetSocketOpt,
+ loopback_GetSocketOpt
+ }
+#endif /* NL_INCLUDE_LOOPBACK */
+#if defined HL_WINDOWS_APP && defined NL_INCLUDE_IPX
+ ,
+ {
+ (NLchar*)TEXT("NL_IPX"),
+ (NLchar*)TEXT("NL_RELIABLE NL_UNRELIABLE NL_RELIABLE_PACKETS NL_BROADCAST"),
+ NL_IPX,
+ NL_FALSE,
+ ipx_Init,
+ ipx_Shutdown,
+ sock_Listen,
+ ipx_AcceptConnection,
+ ipx_Open,
+ sock_Connect,
+ sock_Close,
+ sock_Read,
+ sock_Write,
+ ipx_AddrToString,
+ ipx_StringToAddr,
+ ipx_GetLocalAddr,
+ ipx_GetAllLocalAddr,
+ ipx_SetLocalAddr,
+ ipx_GetNameFromAddr,
+ ipx_GetNameFromAddrAsync,
+ ipx_GetAddrFromName,
+ ipx_GetAddrFromNameAsync,
+ ipx_AddrCompare,
+ ipx_GetPortFromAddr,
+ ipx_SetAddrPort,
+ sock_GetSystemError,
+ sock_PollGroup,
+ sock_PollSocket,
+ ipx_Hint,
+ ipx_SetSocketOpt,
+ ipx_GetSocketOpt
+ }
+#endif /* HL_WINDOWS_APP && NL_INCLUDE_IPX */
+ ,
+ {
+ (NLchar*)NULL,
+ }
+};
+
+/*
+
+ Internal helper functions.
+
+*/
+
+static NLboolean isSafeString(const NLchar *string)
+{
+ int i;
+ NLboolean nullfound = NL_FALSE;
+
+ /* make sure string is null terminated at less than NL_MAX_STRING_LENGTH */
+ for(i=0;i<NL_MAX_STRING_LENGTH;i++)
+ {
+ if(string[i] == (NLchar)'\0')
+ {
+ nullfound = NL_TRUE;
+ break;
+ }
+ }
+ if(nullfound == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ /* check for formating characters */
+ if(_tcsrchr(string, '%') != NULL)
+ {
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+static void safecat(NLchar *dest, const NLchar *src)
+{
+ int len;
+
+ if(isSafeString(dest) != NL_TRUE || isSafeString(src) != NL_TRUE)
+ {
+ /* don't do anything */
+ return;
+ }
+ len = (int)_tcslen(dest);
+ if( len < (NL_MAX_STRING_LENGTH - 1))
+ {
+ _tcsncat(dest, src, (size_t)(NL_MAX_STRING_LENGTH - len));
+ dest[NL_MAX_STRING_LENGTH - 1] = (NLchar)'\0';
+ }
+}
+
+NLsocket nlGetNewSocket(void)
+{
+ NLsocket newsocket = NL_INVALID;
+ nl_socket_t *sock = NULL;
+
+ if(htMutexLock(&socklock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_INVALID;
+ }
+ if(nlNumsockets == nlMaxNumsockets)
+ {
+ nl_socket_t **temp;
+ NLint tempmaxnumsockets = nlMaxNumsockets;
+
+ /* expand the list of sockets pointers */
+ tempmaxnumsockets *= 2;
+ temp = (nl_socket_t **)realloc((void *)nlSockets, tempmaxnumsockets * sizeof(nl_socket_t *));
+ if(temp == NULL)
+ {
+ (void)htMutexUnlock(&socklock);
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_INVALID;
+ }
+ nlSockets = temp;
+ nlMaxNumsockets = tempmaxnumsockets;
+ }
+ /* get a socket number */
+ if(nlNumsockets == (NLint)nlNextsocket)
+ {
+ newsocket = nlNextsocket++;
+ /* allocate the memory */
+ sock = (nl_socket_t *)malloc(sizeof(nl_socket_t));
+ if(sock == NULL)
+ {
+ (void)htMutexUnlock(&socklock);
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_INVALID;
+ }
+ else
+ {
+ nlSockets[newsocket] = sock;
+ }
+ /* clear the structure */
+ memset(sock, 0, sizeof(nl_socket_t));
+
+ if(htMutexInit(&sock->readlock) != 0 || htMutexInit(&sock->writelock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)htMutexUnlock(&socklock);
+ return NL_INVALID;
+ }
+ }
+ else
+ /* there is an open socket slot somewhere below nlNextsocket */
+ {
+ NLsocket i;
+ HTmutex readlock, writelock;
+
+ for(i=0;i<nlNextsocket;i++)
+ {
+ if(nlSockets[i]->inuse == NL_FALSE)
+ {
+ /* found an open socket slot */
+ newsocket = i;
+ sock = nlSockets[i];
+ break;
+ }
+ }
+ /* let's check just to make sure we did find a socket */
+ if(sock == NULL)
+ {
+ (void)htMutexUnlock(&socklock);
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_INVALID;
+ }
+ readlock = sock->readlock;
+ writelock = sock->writelock;
+ /* clear the structure */
+ memset(sock, 0, sizeof(nl_socket_t));
+ sock->readlock = readlock;
+ sock->writelock = writelock;
+ }
+
+ /* sockets are blocking until set for non-blocking */
+ sock->blocking = nlBlocking;
+ sock->inuse = NL_TRUE;
+ nlNumsockets++;
+ (void)htMutexUnlock(&socklock);
+ return newsocket;
+}
+
+static void nlReturnSocket(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ if((sock != NULL) && (sock->inuse == NL_TRUE))
+ {
+ sock->inuse = NL_FALSE;
+ if(sock->inbuf != NULL)
+ {
+ free(sock->inbuf);
+ sock->inbuf = NULL;
+ }
+ if(sock->outbuf != NULL)
+ {
+ free(sock->outbuf);
+ sock->outbuf = NULL;
+ }
+ nlNumsockets--;
+ }
+}
+
+void nlFreeSocket(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ if(sock != NULL)
+ {
+ if(sock->inbuf != NULL)
+ {
+ free(sock->inbuf);
+ }
+ if(sock->outbuf != NULL)
+ {
+ free(sock->outbuf);
+ }
+ (void)htMutexDestroy(&sock->readlock);
+ (void)htMutexDestroy(&sock->writelock);
+ free(sock);
+ }
+}
+
+NLboolean nlIsValidSocket(NLsocket socket)
+{
+ nl_socket_t *sock;
+
+ if(socket < 0 || socket > nlMaxNumsockets)
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ sock = nlSockets[socket];
+ if(sock == NULL)
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ if(sock->inuse == NL_FALSE)
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean nlLockSocket(NLsocket socket, NLint which)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ if((which&NL_READ) > 0)
+ {
+ if(htMutexLock(&sock->readlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ }
+ if((which&NL_WRITE) > 0)
+ {
+ if(htMutexLock(&sock->writelock) != 0)
+ {
+ if((which&NL_READ) > 0)
+ {
+ (void)htMutexUnlock(&sock->readlock);
+ }
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ }
+ return NL_TRUE;
+}
+
+void nlUnlockSocket(NLsocket socket, NLint which)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ if((which&NL_WRITE) > 0)
+ {
+ (void)htMutexUnlock(&sock->writelock);
+ }
+ if((which&NL_READ) > 0)
+ {
+ (void)htMutexUnlock(&sock->readlock);
+ }
+}
+
+static void nlUpdateStats(volatile nl_stats_t *stats, NLint nbytes, NLint npackets)
+{
+ time_t t;
+
+ (void)time(&t);
+ if(stats->stime == 0)
+ {
+ /* must be the first time through */
+ stats->stime = t;
+ stats->lastbucket = -1;
+ stats->firstround = NL_TRUE;
+ }
+ /* do the basic update */
+ stats->packets += npackets;
+ stats->bytes += nbytes;
+
+ /* check to see if we need to do the full update */
+ if(stats->stime != t)
+ {
+ NLint i;
+ NLlong count = 0;
+ time_t diff = t - stats->stime;
+
+ stats->stime = t;
+
+ if(stats->curbytes > stats->highest)
+ {
+ stats->highest = stats->curbytes;
+ }
+ if(diff >= NL_NUM_BUCKETS)
+ {
+ diff = NL_NUM_BUCKETS;
+ }
+
+ while(diff > 1)
+ {
+ /* we need to zero out skipped over buckets */
+ stats->lastbucket++;
+ if(stats->lastbucket == NL_NUM_BUCKETS)
+ {
+ stats->lastbucket = 0;
+ }
+ stats->bucket[stats->lastbucket] = 0;
+ diff--;
+ }
+ stats->lastbucket++;
+ if(stats->lastbucket == NL_NUM_BUCKETS)
+ {
+ stats->lastbucket = 0;
+ stats->firstround = NL_FALSE;
+ }
+ stats->bucket[stats->lastbucket] = stats->curbytes;
+ if(stats->firstround == NL_TRUE)
+ {
+ /* this corrects the stats for the first second */
+ for(i=stats->lastbucket + 1;i<NL_NUM_BUCKETS;i++)
+ {
+ stats->bucket[i] = stats->curbytes;
+ }
+ }
+ stats->curbytes = 0;
+
+ for(i=0;i<NL_NUM_BUCKETS;i++)
+ {
+ count += stats->bucket[i];
+ }
+ stats->average = count / NL_NUM_BUCKETS;
+ }
+ stats->curbytes += nbytes;
+}
+
+static void nlUpdateInStats(NLint nbytes, NLint npackets)
+{
+ if(nlState.socketStats == NL_FALSE)
+ {
+ return;
+ }
+ (void)htMutexLock(&instatlock);
+ nlUpdateStats(&nlInstats, nbytes, npackets);
+ (void)htMutexUnlock(&instatlock);
+}
+
+static void nlUpdateOutStats(NLint nbytes, NLint npackets)
+{
+ if(nlState.socketStats == NL_FALSE)
+ {
+ return;
+ }
+ (void)htMutexLock(&outstatlock);
+ nlUpdateStats(&nlOutstats, nbytes, npackets);
+ (void)htMutexUnlock(&outstatlock);
+}
+
+static void nlUpdateSocketInStats(NLsocket socket, NLint nbytes, NLint npackets)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ if(nlState.socketStats == NL_FALSE)
+ {
+ return;
+ }
+ nlUpdateStats(&sock->instats, nbytes, npackets);
+}
+
+static void nlUpdateSocketOutStats(NLsocket socket, NLint nbytes, NLint npackets)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ if(nlState.socketStats == NL_FALSE)
+ {
+ return;
+ }
+ nlUpdateStats(&sock->outstats, nbytes, npackets);
+}
+
+/*
+
+ Low level functions, a thin layer over Sockets.
+
+*/
+
+/*
+ Trys to init all drivers, BUT DOES NOT SELECT A DRIVER
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlInit(void)
+{
+ int i, numdrivers = 0;
+
+ nlSetError(NL_NO_ERROR);
+ /* init socket memory, mutexes, and global variables */
+ if(nlInitCount == 0)
+ {
+ nlMaxNumsockets = NL_MIN_SOCKETS;
+ if(nlSockets == NULL)
+ {
+ nlSockets = (nl_socket_t **)malloc(nlMaxNumsockets * sizeof(nl_socket_t *));
+ }
+ if(nlSockets == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ nlShutdown();
+ return NL_FALSE;
+ }
+ if(nlGroupInit() == NL_FALSE)
+ {
+ nlShutdown();
+ return NL_FALSE;
+ }
+ if(htMutexInit(&socklock) != 0 || htMutexInit(&instatlock) != 0 ||
+ htMutexInit(&outstatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ nlShutdown();
+ return NL_FALSE;
+ }
+ nlNumsockets = 0;
+ nlNextsocket = 0;
+ nlBlocking = NL_FALSE;
+ nlState.socketStats = NL_FALSE;
+ nlState.nl_big_endian_data = NL_TRUE;
+
+ for(i=0;i<MAX_NET_DRIVERS;i++)
+ {
+ if(netdrivers[i].name == NULL)
+ {
+ break;
+ }
+ if(netdrivers[i].initialized == NL_TRUE)
+ {
+ numdrivers++;
+ }
+ else if(netdrivers[i].Init() == NL_TRUE)
+ {
+ netdrivers[i].initialized = NL_TRUE;
+ numdrivers++;
+ }
+ }
+ if(numdrivers == 0)
+ {
+ nlSetError(NL_NO_NETWORK);
+ nlShutdown();
+ return NL_FALSE;
+ }
+ }
+ nlInitCount++;
+ return NL_TRUE;
+}
+
+/*
+ Called at the end of your program, shuts down the active driver and frees memory
+*/
+
+HL_EXP void HL_APIENTRY nlShutdown(void)
+{
+ --nlInitCount;
+
+ if(nlInitCount > 0)
+ {
+ return;
+ }
+ if(driver != NULL)
+ {
+ /* close any open sockets */
+ (void)htMutexLock(&socklock);
+ if(nlSockets != NULL)
+ {
+ NLsocket s;
+
+ for(s=0;s<nlNextsocket;s++)
+ {
+ if(nlSockets[s] != NULL)
+ {
+ if(nlIsValidSocket(s) == NL_TRUE)
+ {
+ driver->Close(s);
+ htThreadYield();
+ }
+ }
+ }
+ }
+ /* now we can shutdown the driver */
+ driver->Shutdown();
+ driver->initialized = NL_FALSE;
+ driver = NULL;
+ }
+ else
+ {
+ nlSetError(NL_NO_NETWORK);
+ }
+
+ htThreadSleep(1);
+
+ /* now free all the socket structures */
+ if(nlSockets != NULL)
+ {
+ NLsocket s;
+
+ for(s=0;s<nlNextsocket;s++)
+ {
+ if(nlSockets[s] != NULL)
+ {
+ if(nlIsValidSocket(s) == NL_TRUE)
+ {
+ (void)nlLockSocket(s, NL_BOTH);
+ nlReturnSocket(s);
+ nlUnlockSocket(s, NL_BOTH);
+ htThreadYield();
+ }
+ nlFreeSocket(s);
+ }
+ }
+ free(nlSockets);
+ nlSockets = NULL;
+ }
+ (void)htMutexUnlock(&socklock);
+ nlGroupShutdown();
+ /* destroy the mutexes */
+ (void)htMutexDestroy(&socklock);
+ (void)htMutexDestroy(&instatlock);
+ (void)htMutexDestroy(&outstatlock);
+}
+
+/*
+ Enables a socket to listen for incomming connections
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlListen(NLsocket socket)
+{
+ if(driver != NULL)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ NLboolean result;
+
+ if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ result = driver->Listen(socket);
+ nlUnlockSocket(socket, NL_BOTH);
+ return result;
+ }
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Accepts a pending connection.
+ Creates a new socket object for this connection.
+*/
+
+HL_EXP NLsocket HL_APIENTRY nlAcceptConnection(NLsocket socket)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ NLsocket newsocket;
+
+ if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ newsocket = driver->AcceptConnection(socket);
+ nlUnlockSocket(socket, NL_BOTH);
+ if(newsocket != NL_INVALID)
+ {
+ /* the new socket was locked when it is created */
+ nlUnlockSocket(newsocket, NL_BOTH);
+ }
+ return newsocket;
+ }
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_INVALID;
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_INVALID;
+}
+
+/*
+ Creates a new socket object.
+ Can be used for reading or broadcast as is.
+ For non-broadcast use, call nlConnectSocket to connect to a remote address.
+*/
+
+HL_EXP NLsocket HL_APIENTRY nlOpen(NLushort port, NLenum type)
+{
+ if(driver)
+ {
+ return (driver->Open(port, type));
+ }
+
+ nlSetError(NL_NO_NETWORK);
+ return NL_INVALID;
+}
+
+/*
+ Connect a socket to a remote address.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlConnect(NLsocket socket, const NLaddress *address)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ if(address == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ }
+ else
+ {
+ NLboolean result;
+
+ if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ result = driver->Connect(socket, address);
+ nlUnlockSocket(socket, NL_BOTH);
+ return result;
+ }
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ }
+ return NL_FALSE;
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Close the socket.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlClose(NLsocket socket)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ if(htMutexLock(&socklock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ /*
+ if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ */
+ driver->Close(socket);
+ /* return the socket for reuse */
+ nlReturnSocket(socket);
+ // nlUnlockSocket(socket, NL_BOTH);
+ if(htMutexUnlock(&socklock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_TRUE;
+ }
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Reads from a socket.
+*/
+
+HL_EXP NLint HL_APIENTRY nlRead(NLsocket socket, NLvoid *buffer, NLint nbytes)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ if(buffer == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ }
+ else
+ {
+ NLint received;
+
+ if(nlLockSocket(socket, NL_READ) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ received = driver->Read(socket, buffer, nbytes);
+
+ if(received > 0)
+ {
+ nlUpdateSocketInStats(socket, received, 1);
+ nlUpdateInStats(received, 1);
+ }
+ nlUnlockSocket(socket, NL_READ);
+ return received;
+ }
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ }
+ return NL_INVALID;
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_INVALID;
+}
+
+/*
+ Writes to a socket.
+*/
+
+HL_EXP NLint HL_APIENTRY nlWrite(NLsocket socket, const NLvoid *buffer, NLint nbytes)
+{
+ if(driver)
+ {
+ /* check for group */
+ if(socket >= NL_FIRST_GROUP)
+ {
+ NLint number = NL_MAX_GROUP_SOCKETS;
+ NLsocket s[NL_MAX_GROUP_SOCKETS];
+ NLint i;
+ NLint sent = nbytes;
+
+ if(nlGroupGetSockets((NLint)socket, (NLsocket *)s, &number) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+
+ for(i=0;i<number;i++)
+ {
+ NLint result;
+
+ if(nlIsValidSocket(s[i]) == NL_TRUE)
+ {
+ result = nlWrite(s[i], buffer, nbytes);
+ if(result < sent)
+ {
+ sent = result;
+ }
+ }
+ }
+ return sent;
+ }
+ else
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ if(buffer == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ }
+ else
+ {
+ NLint sent;
+
+ if(nlLockSocket(socket, NL_WRITE) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ sent = driver->Write(socket, buffer, nbytes);
+ if(sent > 0)
+ {
+ nlUpdateSocketOutStats(socket, sent, 1);
+ nlUpdateOutStats(sent, 1);
+ }
+ nlUnlockSocket(socket, NL_WRITE);
+ return sent;
+ }
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ }
+ return NL_INVALID;
+ }
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_INVALID;
+}
+
+/*
+ Polls all sockets in the group to see which have data waiting to be read.
+ nlPollGroup uses select() on TCP or UDP sockets.
+ Returns number of sockets waiting, and a list of those sockets, or NL_INVALID
+ on an error.
+*/
+
+HL_EXP NLint HL_APIENTRY nlPollGroup(NLint group, NLenum name, /*@out@*/ NLsocket *sockets, NLint number, NLint timeout)
+{
+ if(driver)
+ {
+ if(sockets == NULL )
+ {
+ nlSetError(NL_NULL_POINTER);
+ return 0;
+ }
+ return (driver->PollGroup(group, name, sockets, number, timeout));
+ }
+ nlSetError(NL_NO_NETWORK);
+ return 0;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlPollSocket(NLsocket socket, NLenum name, NLint timeout)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE )
+ {
+ return (driver->PollSocket(socket, name, timeout));
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlHint(NLenum name, NLint arg)
+{
+ if(driver)
+ {
+ return driver->Hint(name, arg);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlSetSocketOpt(NLsocket socket, NLenum name, NLint arg)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE )
+ {
+ return driver->SetSocketOpt(socket, name, arg);
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+HL_EXP NLint HL_APIENTRY nlGetSocketOpt(NLsocket socket, NLenum name)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE )
+ {
+ return driver->GetSocketOpt(socket, name);
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_INVALID;
+ }
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_INVALID;
+}
+
+/*
+ Converts the numeric address in the NLaddress structure to a string.
+*/
+
+HL_EXP /*@null@*/ NLchar* HL_APIENTRY nlAddrToString(const NLaddress *address, NLchar *string)
+{
+ if(driver)
+ {
+ if((string == NULL) || (address == NULL))
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NULL;
+ }
+ return (driver->AddrToString(address, string));
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NULL;
+}
+
+/*
+ Takes a string that contains a full network address (ie, for IP 192.168.0.1:27000),
+ and adds it to the NLaddress structure.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlStringToAddr(const NLchar *string, NLaddress *address)
+{
+ if(driver)
+ {
+ if((string == NULL) || (address == NULL))
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ if(isSafeString(string) == NL_FALSE)
+ {
+ nlSetError(NL_STRING_OVER_RUN);
+ return NL_FALSE;
+ }
+ return driver->StringToAddr(string, address);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Gets the remote address of the socket if connected to a remote host,
+ or the local address if not connected.
+*/
+
+/* Note: the drivers put a copy of address in nl_socket_t, so we just need to copy it */
+HL_EXP NLboolean HL_APIENTRY nlGetRemoteAddr(NLsocket socket, NLaddress *address)
+{
+ if(driver)
+ {
+ if(address == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ nl_socket_t *sock = nlSockets[socket];
+
+ if(nlLockSocket(socket, NL_READ) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ memcpy(address, &sock->addressin, sizeof(NLaddress));
+ address->valid = NL_TRUE;
+ nlUnlockSocket(socket, NL_READ);
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ memset(address, 0, sizeof(NLaddress));
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Sets the remote address of an unconnected UDP socket.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlSetRemoteAddr(NLsocket socket, const NLaddress *address)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ if(address == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ else
+ {
+ nl_socket_t *sock = nlSockets[socket];
+
+ if(nlLockSocket(socket, NL_WRITE) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ memcpy(&sock->addressout, address, sizeof(NLaddress));
+ nlUnlockSocket(socket, NL_WRITE);
+ }
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Gets the local address.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlGetLocalAddr(NLsocket socket, NLaddress *address)
+{
+ if(driver)
+ {
+ if(nlIsValidSocket(socket) == NL_TRUE)
+ {
+ if(address == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ if(nlLockSocket(socket, NL_READ) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ if(driver->GetLocalAddr(socket, address) != NL_TRUE)
+ {
+ nlUnlockSocket(socket, NL_READ);
+ return NL_FALSE;
+ }
+ nlUnlockSocket(socket, NL_READ);
+ }
+ else
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+HL_EXP NLaddress * HL_APIENTRY nlGetAllLocalAddr(/*@out@*/ NLint *count)
+{
+ if(driver)
+ {
+ if(count == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NULL;
+ }
+ return driver->GetAllLocalAddr(count);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NULL;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlSetLocalAddr(const NLaddress *address)
+{
+ if(driver)
+ {
+ if(address == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ return driver->SetLocalAddr(address);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Resolves the name from the address.
+*/
+
+HL_EXP /*@null@*/ NLchar* HL_APIENTRY nlGetNameFromAddr(const NLaddress *address, NLchar *name)
+{
+ if(driver)
+ {
+ if((name == NULL) || (address == NULL))
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NULL;
+ }
+ return (driver->GetNameFromAddr(address, name));
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NULL;
+}
+
+/*
+ Resolves the name from the address asynchronously.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlGetNameFromAddrAsync(const NLaddress *address, NLchar *name)
+{
+ if(driver)
+ {
+ if((name == NULL) || (address == NULL))
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ return driver->GetNameFromAddrAsync(address, name);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Get the address from a host name.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlGetAddrFromName(const NLchar *name, NLaddress *address)
+{
+ if(driver)
+ {
+ if((name == NULL) || (address == NULL))
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ if(isSafeString(name) == NL_FALSE)
+ {
+ nlSetError(NL_STRING_OVER_RUN);
+ return NL_FALSE;
+ }
+ return driver->GetAddrFromName(name, address);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Get the address from a host name asynchronously.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlGetAddrFromNameAsync(const NLchar *name, NLaddress *address)
+{
+ if(driver)
+ {
+ if((name == NULL) || (address == NULL))
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ if(isSafeString(name) == NL_FALSE)
+ {
+ nlSetError(NL_STRING_OVER_RUN);
+ return NL_FALSE;
+ }
+ return driver->GetAddrFromNameAsync(name, address);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Compare two addresses.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlAddrCompare(const NLaddress *address1, const NLaddress *address2)
+{
+ if(driver)
+ {
+ if((address1 == NULL) || (address2 == NULL))
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ return driver->AddrCompare(address1, address2);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+/*
+ Get the port number from an address.
+*/
+
+HL_EXP NLushort HL_APIENTRY nlGetPortFromAddr(const NLaddress *address)
+{
+ if(driver)
+ {
+ if(address == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return 0;
+ }
+ return driver->GetPortFromAddr(address);
+ }
+ nlSetError(NL_NO_NETWORK);
+ return 0;
+}
+
+/*
+ Set the port number in the address.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlSetAddrPort(NLaddress *address, NLushort port)
+{
+ if(driver)
+ {
+ if(address == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ driver->SetAddrPort(address, port);
+ return NL_TRUE;
+ }
+ nlSetError(NL_NO_NETWORK);
+ return NL_FALSE;
+}
+
+
+/*
+
+ Non-socket functions
+
+*/
+
+/*
+ Select the network to use.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlSelectNetwork(NLenum network)
+{
+ int i, found = 0;
+
+ if(driver != NULL)
+ {
+ /* we cannot select a new network without shutting down first */
+ nlSetError(NL_SELECT_NET_ERROR);
+ return NL_FALSE;
+ }
+
+ for(i=0;i<MAX_NET_DRIVERS;i++)
+ {
+ if(netdrivers[i].name == NULL)
+ {
+ break;
+ }
+ if(netdrivers[i].type == network)
+ {
+ found++;
+ if(netdrivers[i].initialized == NL_TRUE)
+ {
+ driver = &netdrivers[i];
+ return NL_TRUE;
+ }
+ }
+ }
+ if(found > 0)
+ {
+ nlSetError(NL_INVALID_TYPE);
+ }
+ else
+ {
+ nlSetError(NL_INVALID_ENUM);
+ }
+ return NL_FALSE;
+}
+
+/*
+ Returns a string corresponding to the NLenum.
+*/
+
+HL_EXP const /*@observer@*//*@null@*/ NLchar* HL_APIENTRY nlGetString(NLenum name)
+{
+ /* use seperate strings for thread safety */
+ static NLchar vstring[NL_MAX_STRING_LENGTH];
+ static NLchar tstring[NL_MAX_STRING_LENGTH];
+ NLint i;
+
+ nlSetError(NL_NO_ERROR);
+ /* intitialize the version string */
+ _tcsncpy(vstring, (NLchar *)TEXT(NL_VERSION_STRING), (size_t)NL_MAX_STRING_LENGTH);
+ vstring[NL_MAX_STRING_LENGTH - 1] = (NLchar) '\0';
+#ifdef _UNICODE
+ /* add the UNICODE string */
+ safecat(vstring, (NLchar *)TEXT(" UNICODE version"));
+#endif
+ /* intitialize the network types string */
+ memset(tstring, 0, sizeof(NLchar) * NL_MAX_STRING_LENGTH);
+ for(i=0;i<MAX_NET_DRIVERS;i++)
+ {
+ if(netdrivers[i].name == NULL)
+ {
+ break;
+ }
+ if(netdrivers[i].initialized == NL_TRUE)
+ {
+ safecat((NLchar *)tstring, (const NLchar *)netdrivers[i].name);
+ safecat((NLchar *)tstring, (NLchar *)TEXT(" "));
+ }
+ }
+
+ switch (name) {
+
+ case NL_VERSION:
+ return (const NLchar*)vstring;
+
+ case NL_NETWORK_TYPES:
+ return (const NLchar*)tstring;
+
+ case NL_SOCKET_TYPES:
+ if(driver != NULL)
+ {
+ return (const NLchar*)(driver->socktypes);
+ }
+ else
+ {
+ nlSetError(NL_NO_NETWORK);
+ }
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ }
+
+ return NULL;
+}
+
+/*
+ Returns an integer corresponding to the NLenum.
+*/
+
+HL_EXP NLlong HL_APIENTRY nlGetInteger(NLenum name)
+{
+ switch (name) {
+
+ case NL_PACKETS_SENT:
+ return nlOutstats.packets;
+
+ case NL_BYTES_SENT:
+ return nlOutstats.bytes;
+
+ case NL_AVE_BYTES_SENT:
+ nlUpdateOutStats(0, 0);
+ return nlOutstats.average;
+
+ case NL_HIGH_BYTES_SENT:
+ return nlOutstats.highest;
+
+ case NL_PACKETS_RECEIVED:
+ return nlInstats.packets;
+
+ case NL_BYTES_RECEIVED:
+ return nlInstats.bytes;
+
+ case NL_AVE_BYTES_RECEIVED:
+ nlUpdateInStats(0, 0);
+ return nlInstats.average;
+
+ case NL_HIGH_BYTES_RECEIVED:
+ return nlInstats.highest;
+
+ case NL_OPEN_SOCKETS:
+ return nlNumsockets;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ }
+ return 0;
+}
+
+/*
+ Clears the stat corresponding to the NLenum.
+*/
+
+HL_EXP NLboolean HL_APIENTRY nlClear(NLenum name)
+{
+ switch (name) {
+
+ case NL_PACKETS_SENT:
+ if(htMutexLock(&outstatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ nlOutstats.packets = 0;
+ (void)htMutexUnlock(&outstatlock);
+ break;
+
+ case NL_BYTES_SENT:
+ if(htMutexLock(&outstatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ nlOutstats.bytes = 0;
+ (void)htMutexUnlock(&outstatlock);
+ break;
+
+ case NL_AVE_BYTES_SENT:
+ if(htMutexLock(&outstatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ nlOutstats.average = 0;
+ memset((NLbyte *)nlOutstats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
+ (void)htMutexUnlock(&outstatlock);
+ break;
+
+ case NL_HIGH_BYTES_SENT:
+ if(htMutexLock(&outstatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ nlOutstats.highest = 0;
+ (void)htMutexUnlock(&outstatlock);
+ break;
+
+ case NL_PACKETS_RECEIVED:
+ if(htMutexLock(&instatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ nlInstats.packets = 0;
+ (void)htMutexUnlock(&instatlock);
+ break;
+
+ case NL_BYTES_RECEIVED:
+ if(htMutexLock(&instatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ nlInstats.bytes = 0;
+ (void)htMutexUnlock(&instatlock);
+ break;
+
+ case NL_AVE_BYTES_RECEIVED:
+ if(htMutexLock(&instatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ nlInstats.average = 0;
+ memset((NLbyte *)nlInstats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
+ (void)htMutexUnlock(&instatlock);
+ break;
+
+ case NL_HIGH_BYTES_RECEIVED:
+ if(htMutexLock(&instatlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ nlInstats.highest = 0;
+ (void)htMutexUnlock(&instatlock);
+ break;
+
+ case NL_ALL_STATS:
+ (void)nlClear(NL_PACKETS_SENT);
+ (void)nlClear(NL_BYTES_SENT);
+ (void)nlClear(NL_AVE_BYTES_SENT);
+ (void)nlClear(NL_HIGH_BYTES_SENT);
+ (void)nlClear(NL_PACKETS_RECEIVED);
+ (void)nlClear(NL_BYTES_RECEIVED);
+ (void)nlClear(NL_AVE_BYTES_RECEIVED);
+ (void)nlClear(NL_HIGH_BYTES_RECEIVED);
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+/*
+ Get the socket or system error.
+*/
+
+HL_EXP NLint HL_APIENTRY nlGetSystemError(void)
+{
+ if(driver)
+ {
+ return driver->GetSystemError();
+ }
+ return NL_NO_NETWORK;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlEnable(NLenum name)
+{
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ nlBlocking = NL_TRUE;
+ break;
+
+ case NL_TCP_NO_DELAY:
+ return nlHint(NL_TCP_NO_DELAY, (NLint)NL_TRUE);
+
+ case NL_SOCKET_STATS:
+ nlState.socketStats = NL_TRUE;
+ break;
+
+ case NL_BIG_ENDIAN_DATA:
+ nlState.nl_big_endian_data = NL_TRUE;
+ break;
+
+ case NL_LITTLE_ENDIAN_DATA:
+ nlState.nl_big_endian_data = NL_FALSE;
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlDisable(NLenum name)
+{
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ nlBlocking = NL_FALSE;
+ break;
+
+ case NL_TCP_NO_DELAY:
+ return nlHint(NL_TCP_NO_DELAY, NL_FALSE);
+
+ case NL_SOCKET_STATS:
+ nlState.socketStats = NL_FALSE;
+ break;
+
+ case NL_BIG_ENDIAN_DATA:
+ nlState.nl_big_endian_data = NL_FALSE;
+ break;
+
+ case NL_LITTLE_ENDIAN_DATA:
+ nlState.nl_big_endian_data = NL_TRUE;
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlGetBoolean(NLenum name)
+{
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ return nlBlocking;
+
+ case NL_SOCKET_STATS:
+ return nlState.socketStats;
+
+ case NL_BIG_ENDIAN_DATA:
+ return nlState.nl_big_endian_data;
+
+ case NL_LITTLE_ENDIAN_DATA:
+ return (NLboolean)(nlState.nl_big_endian_data == NL_TRUE ? NL_FALSE:NL_TRUE);
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+}
+
+HL_EXP NLlong HL_APIENTRY nlGetSocketStat(NLsocket socket, NLenum name)
+{
+ nl_socket_t *sock;
+ NLlong result = 0;
+
+ if(nlIsValidSocket(socket) == NL_FALSE)
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return 0;
+ }
+ if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
+ {
+ return 0;
+ }
+ sock = nlSockets[socket];
+
+ switch (name) {
+
+ case NL_PACKETS_SENT:
+ result = sock->outstats.packets;
+ break;
+
+ case NL_BYTES_SENT:
+ result = sock->outstats.bytes;
+ break;
+
+ case NL_AVE_BYTES_SENT:
+ nlUpdateSocketOutStats(socket, 0, 0);
+ result = sock->outstats.average;
+ if(result == 0)
+ {
+ /* this corrects the stats for the first second */
+ result = sock->outstats.curbytes;
+ }
+ break;
+
+ case NL_HIGH_BYTES_SENT:
+ result = sock->outstats.highest;
+ break;
+
+ case NL_PACKETS_RECEIVED:
+ result = sock->instats.packets;
+ break;
+
+ case NL_BYTES_RECEIVED:
+ result = sock->instats.bytes;
+ break;
+
+ case NL_AVE_BYTES_RECEIVED:
+ nlUpdateSocketInStats(socket, 0, 0);
+ result = sock->instats.average;
+ if(result == 0)
+ {
+ /* this corrects the stats for the first second */
+ result = sock->instats.curbytes;
+ }
+ break;
+
+ case NL_HIGH_BYTES_RECEIVED:
+ result = sock->instats.highest;
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ }
+ nlUnlockSocket(socket, NL_BOTH);
+ return result;
+}
+
+HL_EXP NLboolean HL_APIENTRY nlClearSocketStat(NLsocket socket, NLenum name)
+{
+ nl_socket_t *sock;
+
+ if(nlIsValidSocket(socket) == NL_FALSE)
+ {
+ nlSetError(NL_INVALID_SOCKET);
+ return NL_FALSE;
+ }
+ if(nlLockSocket(socket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_FALSE;
+ }
+ sock = nlSockets[socket];
+
+ switch (name) {
+
+ case NL_PACKETS_SENT:
+ sock->outstats.packets = 0;
+ break;
+
+ case NL_BYTES_SENT:
+ sock->outstats.bytes = 0;
+ break;
+
+ case NL_AVE_BYTES_SENT:
+ sock->outstats.average = 0;
+ memset((NLbyte *)sock->outstats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
+ break;
+
+ case NL_HIGH_BYTES_SENT:
+ sock->outstats.highest = 0;
+ break;
+
+ case NL_PACKETS_RECEIVED:
+ sock->instats.packets = 0;
+ break;
+
+ case NL_BYTES_RECEIVED:
+ sock->instats.bytes = 0;
+ break;
+
+ case NL_AVE_BYTES_RECEIVED:
+ sock->instats.average = 0;
+ memset((NLbyte *)sock->instats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
+ break;
+
+ case NL_HIGH_BYTES_RECEIVED:
+ sock->instats.highest = 0;
+ break;
+
+ case NL_ALL_STATS:
+ sock->outstats.packets = 0;
+ sock->outstats.bytes = 0;
+ sock->outstats.average = 0;
+ memset((NLbyte *)sock->outstats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
+ sock->outstats.highest = 0;
+ sock->instats.packets = 0;
+ sock->instats.bytes = 0;
+ sock->instats.average = 0;
+ memset((NLbyte *)sock->instats.bucket, 0, sizeof(NLlong) * NL_NUM_BUCKETS);
+ sock->instats.highest = 0;
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ nlUnlockSocket(socket, NL_BOTH);
+ return NL_FALSE;
+ }
+ nlUnlockSocket(socket, NL_BOTH);
+ return NL_TRUE;
+}
+
+HL_EXP NLushort HL_APIENTRY nlSwaps(NLushort x)
+{
+ if(NL_SWAP_TRUE)
+ {
+ return (NLushort)(((((NLushort)x) & 0x00ff) << 8) | ((((NLushort)x) & 0xff00) >> 8));
+ }
+ else
+ {
+ return x;
+ }
+}
+
+HL_EXP NLulong HL_APIENTRY nlSwapl(NLulong x)
+{
+ if(NL_SWAP_TRUE)
+ {
+ return (NLulong)(((((NLulong)x) & 0x000000ff) << 24) | ((((NLulong)x) & 0x0000ff00) << 8) | ((((NLulong)x) & 0x00ff0000) >> 8) | ((((NLulong)x) & 0xff000000) >> 24));
+ }
+ else
+ {
+ return x;
+ }
+}
+
+HL_EXP NLfloat HL_APIENTRY nlSwapf(NLfloat f)
+{
+ if(NL_SWAP_TRUE)
+ {
+ NLulong temp = (NLulong)nlSwapl(*(NLulong *)&f);
+
+ return *((float *)&temp);
+ }
+ else
+ {
+ return f;
+ }
+}
+
+HL_EXP NLdouble HL_APIENTRY nlSwapd(NLdouble d)
+{
+ if(NL_SWAP_TRUE)
+ {
+ union {NLulong l[2]; NLdouble d;} in, out;
+
+ in.d = d;
+ out.l[0] = nlSwapl(in.l[1]);
+ out.l[1] = nlSwapl(in.l[0]);
+ return out.d;
+ }
+ else
+ {
+ return d;
+ }
+}
+
+#if defined (__LCC__)
+BOOL WINAPI __declspec(dllexport) LibMain(/*@unused@*/HINSTANCE hinstDLL, /*@unused@*/DWORD fdwReason, /*@unused@*/LPVOID lpvReserved)
+{
+ return TRUE;
+}
+#endif /* WINDOWS APP */
diff --git a/util/network/hawknl/src/nltime.c b/util/network/hawknl/src/nltime.c
new file mode 100644
index 00000000..1fb8a4d3
--- /dev/null
+++ b/util/network/hawknl/src/nltime.c
@@ -0,0 +1,185 @@
+/*
+ HawkNL time module
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+#include "nlinternal.h"
+
+#ifdef HL_WINDOWS_APP
+#ifdef _MSC_VER
+#pragma warning (disable:4201)
+#pragma warning (disable:4214)
+#endif /* _MSC_VER */
+
+#include <windows.h>
+#include <winbase.h>
+#include <limits.h>
+
+#ifdef _MSC_VER
+#pragma warning (default:4201)
+#pragma warning (default:4214)
+#endif /* _MSC_VER */
+
+struct mytimeb {
+ time_t time;
+ unsigned short millitm;
+};
+
+static void myftime(/*@out@*/ struct mytimeb *tb)
+{
+ static int needinit = 1;
+ static time_t currentseconds;
+ static DWORD currentmseconds;
+ static DWORD lastmseconds;
+
+ if(needinit == 1)
+ {
+ time_t t;
+
+ currentseconds = time(&t);
+ lastmseconds = GetTickCount();
+ currentmseconds = lastmseconds % 1000;
+ needinit = 0;
+ }
+ else
+ {
+ DWORD mseconds = GetTickCount();
+
+ /* check for roll over */
+ if(mseconds < lastmseconds)
+ {
+ currentmseconds += (UINT_MAX - lastmseconds) + mseconds + 1;
+ }
+ else
+ {
+ currentmseconds += mseconds - lastmseconds;
+ }
+ lastmseconds = mseconds;
+ while(currentmseconds > 1000)
+ {
+ currentseconds++;
+ currentmseconds -= 1000;
+ }
+
+ }
+ tb->time = currentseconds;
+ tb->millitm = (unsigned short)currentmseconds;
+}
+#else /* !HL_WINDOWS_APP */
+
+#include <sys/time.h>
+
+#endif /* !HL_WINDOWS_APP */
+
+HL_EXP NLboolean HL_APIENTRY nlTime(NLtime *t)
+{
+#ifdef HL_WINDOWS_APP
+ static NLboolean needinit = NL_TRUE;
+ static NLboolean haspcounter = NL_FALSE;
+ static LARGE_INTEGER freq;
+ static LARGE_INTEGER lastcount;
+ static NLtime currenttime;
+
+ if(t == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ if(needinit == NL_TRUE)
+ {
+ if(QueryPerformanceFrequency(&freq) != 0)
+ {
+ if(QueryPerformanceCounter(&lastcount) != 0)
+ {
+ /* get the current time */
+ struct mytimeb tb;
+
+ myftime(&tb);
+ currenttime.seconds = (NLlong)(tb.time);
+ currenttime.useconds = (NLlong)(tb.millitm * 1000);
+ haspcounter = NL_TRUE;
+ }
+ }
+ needinit = NL_FALSE;
+ }
+ if(haspcounter == NL_TRUE)
+ {
+ LARGE_INTEGER currentcount;
+ LARGE_INTEGER diffcount;
+
+ (void)QueryPerformanceCounter(&currentcount);
+ diffcount.QuadPart = currentcount.QuadPart - lastcount.QuadPart;
+ lastcount.QuadPart = currentcount.QuadPart;
+ while(diffcount.QuadPart >= freq.QuadPart)
+ {
+ diffcount.QuadPart -= freq.QuadPart;
+ currenttime.seconds++;
+ }
+ currenttime.useconds += (NLlong)(diffcount.QuadPart * 1000000 / freq.QuadPart);
+ if(currenttime.useconds >= 1000000)
+ {
+ currenttime.useconds -= 1000000;
+ currenttime.seconds++;
+ }
+ t->seconds = currenttime.seconds;
+ t->mseconds = currenttime.useconds / 1000;
+ t->useconds = currenttime.useconds;
+ }
+ else
+ {
+ /* fall back to myftime */
+ struct mytimeb tb;
+
+ myftime(&tb);
+ t->seconds = (NLlong)(tb.time);
+ t->mseconds = (NLlong)(tb.millitm);
+ t->useconds = (NLlong)(tb.millitm * 1000);
+ }
+#else /* !HL_WINDOWS_APP */
+ struct timeval tv;
+
+ if(t == NULL)
+ {
+ nlSetError(NL_NULL_POINTER);
+ return NL_FALSE;
+ }
+ gettimeofday(&tv, NULL);
+ t->seconds = (NLlong)(tv.tv_sec);
+ t->mseconds = (NLlong)(tv.tv_usec / 1000);
+ t->useconds = (NLlong)(tv.tv_usec);
+#endif /* !HL_WINDOWS_APP */
+ return NL_TRUE;
+}
+
+/* Windows CE does not have time.h functions */
+#if defined (_WIN32_WCE)
+
+time_t time(time_t *timer)
+{
+ NLtime t;
+
+ nlTime(&t);
+ *timer = t.seconds;
+
+ return *timer;
+}
+
+#endif
+
diff --git a/util/network/hawknl/src/sock.c b/util/network/hawknl/src/sock.c
new file mode 100644
index 00000000..de53bdfb
--- /dev/null
+++ b/util/network/hawknl/src/sock.c
@@ -0,0 +1,2698 @@
+/*
+ HawkNL cross platform network library
+ Copyright (C) 2000-2004 Phil Frisbie, Jr. (phil@hawksoft.com)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Or go to http://www.gnu.org/copyleft/lgpl.html
+*/
+
+
+#define FD_SETSIZE 8192
+
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined (_WIN32_WCE)
+#define EAGAIN 11
+#define errno GetLastError()
+#else
+#include <errno.h>
+#endif
+
+
+#if defined WIN32 || defined WIN64 || defined (_WIN32_WCE)
+
+#include "wsock.h"
+
+#elif defined Macintosh
+
+#include <Types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <sys/time.h>
+#include <LowMem.h>
+#define closesocket close
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define SOCKET int
+#define sockerrno errno
+
+/* define INADDR_NONE if not already */
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#endif
+
+#else
+
+/* Unix-style systems */
+#ifdef SOLARIS
+#include <sys/filio.h> /* for FIONBIO */
+#endif
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#define closesocket close
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define SOCKET int
+#define SD_RECEIVE 0
+#define SD_SEND 1
+#define SD_BOTH 2
+#define sockerrno errno
+
+/* define INADDR_NONE if not already */
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#endif
+
+/* SGI and MacOS X do not include socklen_t */
+// #if defined __sgi || defined MACOSX
+#if defined __sgi
+typedef int socklen_t;
+#endif
+
+#endif /* HL_WINDOWS_APP*/
+
+
+#include "nlinternal.h"
+#include "sock.h"
+
+#ifndef IN_MULTICAST
+#define IN_MULTICAST(i) (((unsigned long)(i) & 0xF0000000) == (unsigned long)0xE0000000)
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN NL_MAX_STRING_LENGTH
+#endif
+
+#define NL_CONNECT_STRING "HawkNL request connection."
+#define NL_REPLY_STRING "HawkNL connection OK."
+#define NL_HEADER_LEN 4
+
+/*
+* Portable NLMAX() function macro
+*/
+#define NLMAX( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
+#define NLMIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
+
+static volatile NLuint ouraddress, bindaddress;
+int backlog = SOMAXCONN;
+static volatile int multicastTTL = 1;
+NLboolean reuseaddress = NL_FALSE;
+static volatile NLboolean nlTCPNoDelay = NL_FALSE;
+
+static NLaddress *alladdr = NULL;
+
+typedef struct
+{
+ NLaddress /*@temp@*/*address;
+ NLchar /*@temp@*/*name;
+ NLsocket socket;
+} NLaddress_ex_t;
+
+extern SOCKET nlGroupGetFdset(NLint group, /*@out@*/ fd_set *fd);
+extern NLushort ipx_GetPort(SOCKET socket);
+extern NLushort ipx_GetPortFromAddr(const NLaddress *address);
+
+/*
+This is a Winsock work around to be able to bind() to more than 3976 ports
+*/
+
+#ifdef HL_WINDOWS_APP
+
+static HTmutex portlock; /* In memory of my step-father, Don Portlock,
+who passed away Jan 12, 2001 - Phil */
+
+static volatile NLushort nextport = 1024;
+
+static NLushort sock_getNextPort(void)
+{
+ NLlong temp;
+
+ (void)htMutexLock(&portlock);
+ temp = (NLlong)nextport;
+ if(++temp > 65535)
+ {
+ /* skip the well known ports */
+ temp = 1024;
+ }
+ nextport = (NLushort)temp;
+ (void)htMutexUnlock(&portlock);
+ return nextport;
+}
+
+static NLint sock_bind(SOCKET socket, const struct sockaddr *a, int len)
+{
+ struct sockaddr_in *addr = (struct sockaddr_in *)a;
+ int ntries = 500; /* this is to prevent an infinite loop */
+ NLboolean found = NL_FALSE;
+
+ /* check to see if the port is already specified */
+ if(addr->sin_port != 0)
+ {
+ /* do the normal bind */
+ return bind(socket, a, len);
+ }
+
+ /* let's find our own port number */
+ while(ntries-- > 0)
+ {
+ addr->sin_port = htons(sock_getNextPort());
+ if(bind(socket, (struct sockaddr *)addr, len) != SOCKET_ERROR)
+ {
+ found = NL_TRUE;
+ break;
+ }
+ }
+ if(found == NL_TRUE)
+ {
+ return 0;
+ }
+ /* could not find a port, restore the port number back to 0 */
+ addr->sin_port = 0;
+ /* return error */
+ return SOCKET_ERROR;
+}
+
+static int sock_connect(SOCKET socket, const struct sockaddr* a, int len )
+{
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = 0;
+
+ if(sock_bind(socket, (struct sockaddr *)&addr, (int)sizeof(addr)) == SOCKET_ERROR)
+ {
+ return SOCKET_ERROR;
+ }
+ return connect(socket, a, len);
+}
+
+
+void nlFD_CLR(SOCKET fd, fd_set *set)
+{
+ u_int i;
+
+ for(i=0;i<set->fd_count;i++)
+ {
+ if(set->fd_array[i] == fd)
+ {
+ while(i < set->fd_count-1)
+ {
+ set->fd_array[i] = set->fd_array[i+1];
+ i++;
+ }
+ set->fd_count--;
+ break;
+ }
+ }
+}
+
+
+void nlFD_SET(SOCKET fd, /*@out@*/ fd_set *set)
+{
+ if(set->fd_count < FD_SETSIZE)
+ set->fd_array[set->fd_count++]=fd;
+}
+
+/* This function is inlined for speed over the Winsock function */
+
+
+int nlWSAFDIsSet(SOCKET fd, fd_set *set)
+{
+ int i = (int)set->fd_count;
+
+ while(i-- != 0)
+ {
+ if (set->fd_array[i] == fd)
+ return 1;
+ }
+ return 0;
+}
+
+#else
+#define sock_bind bind
+#define sock_connect connect
+#endif /* HL_WINDOWS_APP */
+
+/*
+helper functions for NL_RELIABLE_PACKETS
+*/
+
+static NLint rpGroup; /* the group to hold all the NL_RELIABLE_PACKETS sockets */
+static HTmutex rpMutex; /* mutex to lock the functions */
+static NLboolean needThread = NL_TRUE; /* do we need to spawn a thread? */
+static NLint rpSocketCount = 0; /* total count of NL_RELIABLE_PACKETS sockets */
+static volatile NLint rpBufferedCount = 0;/* count of sockets that are buffering data */
+
+static void sock_WritePacketCheckPending(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ /* first check for data waiting to be sent */
+ if(sock->sendlen > 0)
+ {
+ NLint count, size = NL_MAX_PACKET_LENGTH + NL_HEADER_LEN;
+
+ if(size > sock->sendlen)
+ {
+ size = sock->sendlen;
+ }
+ count = send((SOCKET)sock->realsocket, (char *)sock->outbuf, size, 0);
+ if(count > 0)
+ {
+ sock->sendlen -= count;
+ if(sock->sendlen > 0)
+ {
+ /* move remaining data to beginning of outbuf */
+ memmove(sock->outbuf, (sock->outbuf + count), (size_t)sock->sendlen);
+ }
+ else
+ {
+ rpBufferedCount--;
+ }
+ }
+ }
+}
+
+static void *sock_rpThread(void *p)
+{
+ static NLsocket *sockets = NULL;
+ static NLint maxsockets = 0;
+
+ /* allocate memory */
+ if(sockets == NULL)
+ {
+ sockets = (NLsocket *)malloc(sizeof(NLsocket *) * 16);
+ if(sockets == NULL)
+ {
+ needThread = NL_TRUE;
+ return NULL;
+ }
+ maxsockets = 16;
+ }
+ while(rpGroup != NL_INVALID)
+ {
+ NLint count = maxsockets;
+
+ /* make sure there is something to do */
+ if(rpSocketCount == 0 || rpBufferedCount == 0)
+ {
+ goto loopend;
+ }
+ /* see if we need to allocate more memory */
+ if(maxsockets < rpSocketCount)
+ {
+ NLsocket *temp;
+
+ while(maxsockets < rpSocketCount)
+ {
+ maxsockets *= 2;
+ }
+ temp = (NLsocket *)realloc((void *)sockets, sizeof(NLsocket *) * maxsockets);
+ if(temp == NULL)
+ {
+ goto cleanup;
+ }
+ sockets = temp;
+ }
+ /* we can now get the sockets */
+ if(nlGroupGetSockets(rpGroup, sockets, &count) == NL_FALSE)
+ {
+ goto cleanup;
+ }
+ while(count-- > 0 && rpBufferedCount > 0)
+ {
+ NLsocket socket = sockets[count];
+
+ (void)nlLockSocket(socket, NL_WRITE);
+ sock_WritePacketCheckPending(socket);
+ nlUnlockSocket(socket, NL_WRITE);
+ }
+loopend:
+ htThreadSleep(50);
+ }
+cleanup:
+ free(sockets);
+ sockets = NULL;
+ maxsockets = 0;
+ needThread = NL_TRUE;
+ return p;
+}
+
+static void sock_AddSocket(NLsocket socket)
+{
+ (void)htMutexLock(&rpMutex);
+ (void)nlGroupAddSocket(rpGroup, socket);
+ rpSocketCount++;
+ if(needThread == NL_TRUE)
+ {
+ (void)htThreadCreate(sock_rpThread, NULL, NL_FALSE);
+ needThread = NL_FALSE;
+ }
+ (void)htMutexUnlock(&rpMutex);
+}
+
+static void sock_DeleteSocket(NLsocket socket)
+{
+ (void)htMutexLock(&rpMutex);
+ (void)nlGroupDeleteSocket(rpGroup, socket);
+ rpSocketCount--;
+ (void)htMutexUnlock(&rpMutex);
+}
+
+/*
+handle some common connection errors so the app knows when a connection has been dropped
+*/
+
+NLint sock_Error(void)
+{
+ switch (sockerrno) {
+
+#ifdef HL_WINDOWS_APP
+ case WSABASEERR:
+ return 0;
+#endif
+
+ case EWOULDBLOCK:
+ return 0;
+
+ case ENETRESET:
+ case EHOSTUNREACH:
+ case ECONNABORTED:
+ case ECONNRESET:
+ case ENETUNREACH:
+ case ETIMEDOUT:
+ nlSetError(NL_SOCK_DISCONNECT);
+ break;
+
+ default:
+ nlSetError(NL_SYSTEM_ERROR);
+ break;
+ }
+
+ return NL_INVALID;
+}
+
+NLboolean sock_SetBlocking(SOCKET socket, NLboolean arg)
+{
+ int rc;
+ unsigned long i = 1;
+
+ if(arg == NL_TRUE)
+ {
+ i = 0;
+ }
+ rc = ioctl(socket, FIONBIO, &i);
+ if(rc == SOCKET_ERROR)
+ {
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean sock_SetBroadcast(SOCKET socket)
+{
+ int i = 1;
+
+ if(setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, (int)sizeof(i)) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean sock_SetReuseAddr(nl_socket_t *sock)
+{
+ int i = 1;
+
+ if(setsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, (int)sizeof(i)) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ sock->reuseaddr = NL_TRUE;
+ return NL_TRUE;
+}
+
+static NLboolean sock_SetTCPNoDelay(nl_socket_t *sock, NLboolean arg)
+{
+ NLenum type = sock->type;
+ SOCKET realsocket = (SOCKET)sock->realsocket;
+ int i;
+
+ if(type == NL_TCP || type == NL_TCP_PACKETS)
+ {
+ arg = (NLboolean)(arg != (NLboolean)0 ? NL_TRUE : NL_FALSE);
+ i = (int)arg;
+ if(setsockopt(realsocket, IPPROTO_TCP, TCP_NODELAY, (char *)&i, (int)sizeof(i)) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ }
+ sock->TCPNoDelay = arg;
+ return NL_TRUE;
+}
+
+static NLboolean sock_SetMulticastTTL(nl_socket_t *sock, NLint ttl)
+{
+ SOCKET realsocket = (SOCKET)sock->realsocket;
+ unsigned char cttl;
+
+ /* make sure we have a valid TTL */
+ if(ttl > 255) ttl = 255;
+ if(ttl < 1) ttl = 1;
+ cttl = (unsigned char)ttl;
+
+ /* first try setsockopt by passing a 'char', the Unix standard */
+ if(setsockopt(realsocket, IPPROTO_IP, IP_MULTICAST_TTL,
+ (char *)&cttl, (int)sizeof(cttl)) == SOCKET_ERROR)
+ {
+ /* if that failed, we might be on a Windows system
+ that requires an 'int' */
+ if(setsockopt(realsocket, IPPROTO_IP, IP_MULTICAST_TTL,
+ (char *)&ttl, (int)sizeof(ttl)) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ }
+ sock->TTL = ttl;
+ return NL_TRUE;
+}
+
+static NLsocket sock_SetSocketOptions(NLsocket s)
+{
+ nl_socket_t *sock = nlSockets[s];
+ NLenum type = sock->type;
+ SOCKET realsocket = (SOCKET)sock->realsocket;
+
+ if(type == NL_RELIABLE || type == NL_RELIABLE_PACKETS)
+ {
+ sock->reliable = NL_TRUE;
+ if(type == NL_RELIABLE_PACKETS)
+ {
+ sock->packetsync = NL_TRUE;
+ }
+ }
+ else
+ {
+ sock->reliable = NL_FALSE;
+ }
+ if(sock->driver == NL_IP)
+ {
+ if(sock_SetTCPNoDelay(sock, sock->TCPNoDelay) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_INVALID;
+ }
+ }
+ if(reuseaddress == NL_TRUE)
+ {
+ if(sock_SetReuseAddr(sock) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_INVALID;
+ }
+ }
+
+ if(sock_SetBlocking(realsocket, sock->blocking) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_INVALID;
+ }
+
+ return s;
+}
+
+static NLuint sock_GetHostAddress(void)
+{
+ struct hostent *local;
+ char buff[MAXHOSTNAMELEN];
+
+ if(gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
+ {
+ return INADDR_NONE;
+ }
+ buff[MAXHOSTNAMELEN - 1] = '\0';
+ local = gethostbyname(buff);
+ if(!local)
+ return (NLuint)htonl(0x7f000001);
+ return *(NLuint *)local->h_addr_list[0];
+}
+
+static NLushort sock_GetPort(SOCKET socket)
+{
+ struct sockaddr_in addr;
+ socklen_t len;
+
+ len = (socklen_t)sizeof(struct sockaddr_in);
+ if(getsockname(socket, (struct sockaddr *) &addr, &len) == SOCKET_ERROR)
+ {
+ return 0;
+ }
+
+ return ntohs(addr.sin_port);
+}
+
+NLboolean sock_Init(void)
+{
+#ifdef HL_WINDOWS_APP
+ WSADATA libmibWSAdata;
+
+ /* We must have Winsock 2.0 */
+ if(WSAStartup(MAKEWORD(2, 0),&libmibWSAdata) != 0)
+ {
+ return NL_FALSE;
+ }
+ if(htMutexInit(&portlock) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+#endif
+ if(htMutexInit(&rpMutex) != 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ if((rpGroup = nlGroupCreate()) == NL_INVALID)
+ {
+ return NL_FALSE;
+ }
+ ouraddress = sock_GetHostAddress();
+ if(ouraddress == (NLuint)INADDR_NONE)
+ {
+ return NL_FALSE;
+ }
+
+ bindaddress = INADDR_ANY;
+ return NL_TRUE;
+}
+
+void sock_Shutdown(void)
+{
+#ifdef HL_WINDOWS_APP
+ (void)WSACleanup();
+ (void)htMutexDestroy(&portlock);
+ (void)htMutexDestroy(&rpMutex);
+ (void)nlGroupDestroy(rpGroup);
+ rpGroup = NL_INVALID;
+#endif
+ if(alladdr != NULL)
+ {
+ free(alladdr);
+ alladdr = NULL;
+ }
+}
+
+NLboolean sock_Listen(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ if(sock->listen == NL_TRUE)
+ {
+ return NL_TRUE;
+ }
+ if(sock->reliable == NL_TRUE) /* TCP */
+ {
+ /* check for unbound socket */
+ if(sock->localport == 0)
+ {
+ NLint result;
+
+ /* bind socket */
+#ifdef NL_INCLUDE_IPX
+ if(sock->driver == NL_IPX)
+ {
+ ((struct sockaddr_ipx *)&sock->addressin)->sa_family = AF_IPX;
+ memset(((struct sockaddr_ipx *)&sock->addressin)->sa_netnum, 0, 4);
+ memset(((struct sockaddr_ipx *)&sock->addressin)->sa_nodenum, 0, 6);
+ ((struct sockaddr_ipx *)&sock->addressin)->sa_socket = 0;
+ result = bind((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin,
+ (int)sizeof(struct sockaddr_ipx));
+ }
+ else
+#endif
+ {
+ ((struct sockaddr_in *)&sock->addressin)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&sock->addressin)->sin_addr.s_addr = bindaddress;
+ ((struct sockaddr_in *)&sock->addressin)->sin_port = 0;
+ result = sock_bind((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin,
+ (int)sizeof(struct sockaddr_in));
+ }
+
+ if(result == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ }
+ if(listen((SOCKET)sock->realsocket, backlog) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ }
+
+ sock->listen = NL_TRUE;
+ return NL_TRUE;
+}
+
+static SOCKET sock_AcceptUDP(NLsocket nlsocket, /*@out@*/struct sockaddr_in *newaddr)
+{
+ nl_socket_t *sock = nlSockets[nlsocket];
+ struct sockaddr_in ouraddr;
+ SOCKET newsocket;
+ NLushort localport;
+ NLbyte buffer[NL_MAX_STRING_LENGTH];
+ socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
+ NLint slen = (NLint)sizeof(NL_CONNECT_STRING);
+ NLbyte reply = (NLbyte)0x00;
+ NLint count = 0;
+
+ /* Get the packet and remote host address */
+ if(recvfrom((SOCKET)sock->realsocket, buffer, (int)sizeof(buffer), 0,
+ (struct sockaddr *)newaddr, &len) < (int)sizeof(NL_CONNECT_STRING))
+ {
+ nlSetError(NL_NO_PENDING);
+ return INVALID_SOCKET;
+ }
+ /* Let's check for the connection string */
+ buffer[slen - 1] = (NLbyte)0; /* null terminate for peace of mind */
+ if(strcmp(buffer, NL_CONNECT_STRING) != 0)
+ {
+ nlSetError(NL_NO_PENDING);
+ return INVALID_SOCKET;
+ }
+ /* open up a new socket on this end */
+ newsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if(newsocket == INVALID_SOCKET)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+
+ ouraddr.sin_family = AF_INET;
+ ouraddr.sin_addr.s_addr = bindaddress;
+ /* system assigned port number */
+ ouraddr.sin_port = 0;
+
+ if(sock_bind(newsocket, (struct sockaddr *)&ouraddr, len) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+ /* get the new port */
+ localport = sock_GetPort(newsocket);
+
+ /* create the return message */
+ writeShort(buffer, count, localport);
+ writeString(buffer, count, (NLchar *)TEXT(NL_REPLY_STRING));
+
+ /* send back the reply with our new port */
+ if(sendto((SOCKET)sock->realsocket, buffer, count, 0, (struct sockaddr *)newaddr,
+ (int)sizeof(struct sockaddr_in)) < count)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+ /* send back a 0 length packet from our new port, needed for firewalls */
+ if(sendto(newsocket, &reply, 0, 0,
+ (struct sockaddr *)newaddr,
+ (int)sizeof(struct sockaddr_in)) < 0)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+ /* connect the socket */
+ if(connect(newsocket, (struct sockaddr *)newaddr,
+ (int)sizeof(struct sockaddr_in)) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ (void)closesocket(newsocket);
+ return INVALID_SOCKET;
+ }
+
+ return newsocket;
+}
+
+NLsocket sock_AcceptConnection(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ nl_socket_t *newsock = NULL;
+ NLsocket newsocket = NL_INVALID;
+ SOCKET realsocket = INVALID_SOCKET;
+ struct sockaddr_in newaddr;
+ socklen_t len = (socklen_t)sizeof(newaddr);
+
+ memset(&newaddr, 0, sizeof(newaddr));
+ if(sock->listen != NL_TRUE)
+ {
+ nlSetError(NL_NOT_LISTEN);
+ return NL_INVALID;
+ }
+
+ if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS) /* TCP */
+ {
+ SOCKET s = 101;
+
+ /* !@#$% metrowerks compiler, try to get it to actually produce some code */
+ s = accept((SOCKET)(sock->realsocket), (struct sockaddr *)&newaddr, &len);
+
+ realsocket = s;
+ if(realsocket == INVALID_SOCKET)
+ {
+ if(sockerrno == (int)EWOULDBLOCK || errno == EAGAIN)/* yes, we need to use errno here */
+ {
+ nlSetError(NL_NO_PENDING);
+ }
+ else
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ }
+ return NL_INVALID;
+ }
+
+ }
+ else if(sock->type == NL_UNRELIABLE)/* UDP*/
+ {
+ realsocket = sock_AcceptUDP(socket, &newaddr);
+
+ if(realsocket == INVALID_SOCKET)
+ {
+ /* error is already set in sock_AcceptUDP */
+ return NL_INVALID;
+ }
+ }
+ else /* broadcast or multicast */
+ {
+ nlSetError(NL_WRONG_TYPE);
+ return NL_INVALID;
+ }
+
+ newsocket = nlGetNewSocket();
+ if(newsocket == NL_INVALID)
+ {
+ return NL_INVALID;
+ }
+ if(nlLockSocket(newsocket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ newsock = nlSockets[newsocket];
+
+ /* update the remote address */
+ memcpy((char *)&newsock->addressin, (char *)&newaddr, sizeof(struct sockaddr_in));
+ newsock->realsocket = (NLint)realsocket;
+ newsock->localport = sock_GetPort(realsocket);
+ newsock->remoteport = sock_GetPortFromAddr((NLaddress *)&newsock->addressin);
+
+ newsock->type = sock->type;
+ newsock->TCPNoDelay = sock->TCPNoDelay;
+ newsock->connected = NL_TRUE;
+ newsock->blocking = sock->blocking;
+ if(newsock->type == NL_RELIABLE_PACKETS)
+ {
+ sock_AddSocket(newsocket);
+ }
+ return sock_SetSocketOptions(newsocket);
+}
+
+NLsocket sock_OpenINT(NLushort port, NLenum type, NLenum driver)
+{
+ nl_socket_t *newsock;
+ NLsocket newsocket;
+ SOCKET realsocket;
+
+ switch (type) {
+
+ case NL_RELIABLE: /* TCP/SPX */
+ case NL_RELIABLE_PACKETS:
+#ifdef NL_INCLUDE_IPX
+ if(driver == NL_IPX)
+ {
+ realsocket = socket(PF_IPX, SOCK_SEQPACKET, NSPROTO_SPXII);
+ type = NL_RELIABLE;
+ }
+ else
+#endif
+ {
+ realsocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ }
+ break;
+
+ case NL_UNRELIABLE: /* UDP/IPX */
+ case NL_BROADCAST: /* UDP/IPX broadcast */
+ case NL_UDP_MULTICAST: /* UDP multicast */
+#ifdef NL_INCLUDE_IPX
+ if(driver == NL_IPX)
+ {
+ if(type == NL_UDP_MULTICAST)
+ {
+ nlSetError(NL_INVALID_ENUM);
+ return NL_INVALID;
+ }
+ realsocket = socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX);
+ }
+ else
+#endif
+ {
+ realsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ }
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_INVALID;
+ }
+
+ if(realsocket == INVALID_SOCKET)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_INVALID;
+ }
+
+ newsocket = nlGetNewSocket();
+ if(newsocket == NL_INVALID)
+ {
+ return NL_INVALID;
+ }
+ if(nlLockSocket(newsocket, NL_BOTH) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ newsock = nlSockets[newsocket];
+ newsock->realsocket = (NLint)realsocket;
+ newsock->type = type;
+ newsock->TCPNoDelay = nlTCPNoDelay;
+
+ if(sock_SetSocketOptions(newsocket) == NL_INVALID)
+ {
+ nlUnlockSocket(newsocket, NL_BOTH);
+ (void)sock_Close(newsocket);
+ return NL_INVALID;
+ }
+ /* do not bind a TCP/SPX socket here if the port is 0; let connect assign the port */
+ if((type == NL_RELIABLE || type == NL_RELIABLE_PACKETS) && port == 0)
+ {
+ newsock->localport = 0;
+ }
+ else
+ {
+ NLint result;
+
+#ifdef NL_INCLUDE_IPX
+ if(driver == NL_IPX)
+ {
+ ((struct sockaddr_ipx *)&newsock->addressin)->sa_family = AF_IPX;
+ memset(((struct sockaddr_ipx *)&newsock->addressin)->sa_netnum, 0, 4);
+ memset(((struct sockaddr_ipx *)&newsock->addressin)->sa_nodenum, 0, 6);
+ ((struct sockaddr_ipx *)&newsock->addressin)->sa_socket = htons((unsigned short)port);
+ result = bind((SOCKET)realsocket, (struct sockaddr *)&newsock->addressin,
+ (int)sizeof(struct sockaddr_ipx));
+ }
+ else
+#endif
+ {
+ ((struct sockaddr_in *)&newsock->addressin)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&newsock->addressin)->sin_addr.s_addr = bindaddress;
+ ((struct sockaddr_in *)&newsock->addressin)->sin_port = htons((unsigned short)port);
+ result = sock_bind(realsocket, (struct sockaddr *)&newsock->addressin,
+ (int)sizeof(struct sockaddr_in));
+ }
+ if(result == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ nlUnlockSocket(newsocket, NL_BOTH);
+ (void)sock_Close(newsocket);
+ return NL_INVALID;
+ }
+ if(type == NL_BROADCAST)
+ {
+ if(sock_SetBroadcast(realsocket) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ nlUnlockSocket(newsocket, NL_BOTH);
+ (void)sock_Close(newsocket);
+ return NL_INVALID;
+ }
+#ifdef NL_INCLUDE_IPX
+ if(driver == NL_IPX)
+ {
+ ((struct sockaddr_ipx *)&newsock->addressout)->sa_family = AF_IPX;
+ memset(((struct sockaddr_ipx *)&newsock->addressout)->sa_netnum, 0, 4);
+ memset(((struct sockaddr_ipx *)&newsock->addressout)->sa_nodenum, 0xff, 6);
+ ((struct sockaddr_ipx *)&newsock->addressout)->sa_socket = htons((unsigned short)port);
+ }
+ else
+#endif
+ {
+ ((struct sockaddr_in *)&newsock->addressout)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&newsock->addressout)->sin_addr.s_addr = INADDR_BROADCAST;
+ ((struct sockaddr_in *)&newsock->addressout)->sin_port = htons((unsigned short)port);
+ }
+ }
+#ifdef NL_INCLUDE_IPX
+ if(driver == NL_IPX)
+ {
+ newsock->localport = ipx_GetPort(realsocket);
+ }
+ else
+#endif
+ {
+ newsock->localport = sock_GetPort(realsocket);
+ }
+ }
+ if(type == NL_RELIABLE_PACKETS)
+ {
+ sock_AddSocket(newsocket);
+ }
+ newsock->driver = driver;
+ nlUnlockSocket(newsocket, NL_BOTH);
+ return newsocket;
+}
+
+NLsocket sock_Open(NLushort port, NLenum type)
+{
+ return sock_OpenINT(port, type, NL_IP);
+}
+
+static NLboolean sock_ConnectUDP(NLsocket socket, const NLaddress *address)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ time_t begin, t;
+ socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
+
+ sock->conerror = NL_FALSE;
+#ifdef NL_INCLUDE_IPX
+ if(sock->driver == NL_IPX)
+ {
+ len = (socklen_t)sizeof(struct sockaddr_ipx);
+ }
+#endif
+ if(sendto((SOCKET)sock->realsocket, (char *)NL_CONNECT_STRING, (NLint)sizeof(NL_CONNECT_STRING),
+ 0, (struct sockaddr *)address, len)
+ == SOCKET_ERROR)
+ {
+ if(sock->blocking == NL_TRUE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ }
+ else
+ {
+ sock->conerror = NL_TRUE;
+ }
+ return NL_FALSE;
+ }
+
+ (void)time(&begin);
+
+ /* try for six seconds */
+ while((time(&t) - begin) < 6)
+ {
+ NLbyte buffer[NL_MAX_STRING_LENGTH];
+ NLbyte *pbuffer = buffer;
+ NLushort newport;
+ NLint slen = (NLint)(sizeof(NL_REPLY_STRING) + sizeof(newport));
+ NLint received;
+ NLbyte reply = (NLbyte)0;
+
+ received = recvfrom((SOCKET)sock->realsocket, (char *)buffer, (int)sizeof(buffer), 0,
+ (struct sockaddr *)&sock->addressin, &len);
+
+ if(received == SOCKET_ERROR)
+ {
+ if(sockerrno != (int)EWOULDBLOCK)
+ {
+ if(sock->blocking == NL_TRUE)
+ {
+ nlSetError(NL_CON_REFUSED);
+ }
+ else
+ {
+ sock->conerror = NL_TRUE;
+ }
+ return NL_FALSE;
+ }
+ }
+ if(received >= slen)
+ {
+ NLint count = 0;
+
+ /* retrieve the port number */
+ readShort(buffer, count, newport);
+#ifdef NL_INCLUDE_IPX
+ if(sock->driver == NL_IPX)
+ {
+ ((struct sockaddr_ipx *)&sock->addressin)->sa_socket = htons(newport);
+ }
+ else
+#endif
+ {
+ ((struct sockaddr_in *)&sock->addressin)->sin_port = htons(newport);
+ }
+ /* Lets check for the reply string */
+ pbuffer[slen - 1] = (NLbyte)0; /* null terminate for peace of mind */
+ pbuffer += sizeof(newport);
+ if(strcmp(pbuffer, NL_REPLY_STRING) == 0)
+ {
+ if(connect((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin, len)
+ == SOCKET_ERROR)
+ {
+ if(sock->blocking == NL_TRUE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ }
+ else
+ {
+ sock->conerror = NL_TRUE;
+ }
+ return NL_FALSE;
+ }
+ /* send back a 0 length packet to the new port, needed for firewalls */
+ if(send((SOCKET)sock->realsocket, &reply, 0, 0) == SOCKET_ERROR)
+ {
+ if(sock->blocking == NL_TRUE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ }
+ else
+ {
+ sock->conerror = NL_TRUE;
+ }
+ return NL_FALSE;
+ }
+ /* success! */
+#ifdef NL_INCLUDE_IPX
+ if(sock->driver == NL_IPX)
+ {
+ sock->localport = ipx_GetPort((SOCKET)sock->realsocket);
+ sock->remoteport = ipx_GetPortFromAddr((NLaddress *)&sock->addressin);
+ }
+ else
+#endif
+ {
+ sock->localport = sock_GetPort((SOCKET)sock->realsocket);
+ sock->remoteport = sock_GetPortFromAddr((NLaddress *)&sock->addressin);
+ }
+ sock->connected = NL_TRUE;
+ sock->connecting = NL_FALSE;
+ return NL_TRUE;
+ }
+ }
+ htThreadSleep(NL_CONNECT_SLEEP);
+ }
+
+ if(sock->blocking == NL_TRUE)
+ {
+ nlSetError(NL_CON_REFUSED);
+ }
+ else
+ {
+ sock->conerror = NL_TRUE;
+ }
+ sock->connecting = NL_FALSE;
+ return NL_FALSE;
+}
+
+static void *sock_ConnectUDPAsynchInt(void /*@owned@*/*addr)
+{
+ NLaddress_ex_t *address = (NLaddress_ex_t *)addr;
+
+ (void)sock_ConnectUDP(address->socket, address->address);
+ free(addr);
+ return NULL;
+}
+
+static NLboolean sock_ConnectUDPAsynch(NLsocket socket, const NLaddress *address)
+{
+ NLaddress_ex_t /*@dependent@*/*addr;
+ nl_socket_t *sock = nlSockets[socket];
+
+ addr = (NLaddress_ex_t *)malloc(sizeof(NLaddress_ex_t));
+ if(addr == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_FALSE;
+ }
+ addr->address = (NLaddress *)address;
+ addr->socket = socket;
+ sock->connecting = NL_TRUE;
+ sock->conerror = NL_FALSE;
+ if(htThreadCreate(sock_ConnectUDPAsynchInt, (void *)addr, NL_FALSE) == (HThreadID)HT_INVALID)
+ {
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+static NLboolean sock_ConnectMulticast(NLsocket socket, const NLaddress *address)
+{
+ struct ip_mreq mreq;
+ nl_socket_t *sock = nlSockets[socket];
+
+ if(sock->reliable == NL_TRUE)
+ {
+ nlSetError(NL_WRONG_TYPE);
+ return NL_FALSE;
+ }
+ if(!IN_MULTICAST(ntohl(((struct sockaddr_in *)address)->sin_addr.s_addr)))
+ {
+ nlSetError(NL_BAD_ADDR);
+ return NL_FALSE;
+ }
+
+ memcpy((char *)&sock->addressin, (char *)address, sizeof(NLaddress));
+ memcpy((char *)&sock->addressout, (char *)address, sizeof(NLaddress));
+
+ /* join the multicast group */
+ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)address)->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = bindaddress;
+
+ if(setsockopt((SOCKET)sock->realsocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&mreq, (int)sizeof(mreq)) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ sock->localport = sock_GetPort((SOCKET)sock->realsocket);
+ sock->remoteport = sock_GetPortFromAddr((NLaddress *)&sock->addressout);
+
+ return sock_SetMulticastTTL(sock, multicastTTL);
+}
+
+NLboolean sock_Connect(NLsocket socket, const NLaddress *address)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ memcpy((char *)&sock->addressin, (char *)address, sizeof(NLaddress));
+
+ if(sock->connected == NL_TRUE)
+ {
+ nlSetError(NL_CONNECTED);
+ return NL_FALSE;
+ }
+ if(sock->connecting == NL_TRUE)
+ {
+ nlSetError(NL_CON_PENDING);
+ return NL_FALSE;
+ }
+ if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS)
+ {
+ socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
+
+#ifdef NL_INCLUDE_IPX
+ if(sock->driver == NL_IPX)
+ {
+ len = (socklen_t)sizeof(struct sockaddr_ipx);
+ if(connect((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin, len)
+ == SOCKET_ERROR)
+ {
+ if(sock->blocking == NL_FALSE &&
+ (sockerrno == (int)EWOULDBLOCK || sockerrno == (int)EINPROGRESS))
+ {
+ sock->connecting = NL_TRUE;
+ }
+ else
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ }
+ sock->localport = ipx_GetPort((SOCKET)sock->realsocket);
+ sock->remoteport = ipx_GetPortFromAddr((NLaddress *)&sock->addressin);
+ }
+ else
+#endif
+ {
+ if(sock_connect((SOCKET)sock->realsocket, (struct sockaddr *)&sock->addressin, len)
+ == SOCKET_ERROR)
+ {
+ if(sock->blocking == NL_FALSE &&
+ (sockerrno == (int)EWOULDBLOCK || sockerrno == (int)EINPROGRESS))
+ {
+ sock->connecting = NL_TRUE;
+ }
+ else
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ }
+ sock->localport = sock_GetPort((SOCKET)sock->realsocket);
+ sock->remoteport = sock_GetPortFromAddr((NLaddress *)&sock->addressin);
+ }
+ if(sock->connecting == NL_FALSE)
+ {
+ sock->connected = NL_TRUE;
+ }
+ return NL_TRUE;
+ }
+ else if(sock->type == NL_UDP_MULTICAST)
+ {
+ return sock_ConnectMulticast(socket, &sock->addressin);
+ }
+ else if(sock->type == NL_UNRELIABLE)
+ {
+ if(sock->blocking == NL_TRUE)
+ {
+ return sock_ConnectUDP(socket, &sock->addressin);
+ }
+ else
+ {
+ return sock_ConnectUDPAsynch(socket, &sock->addressin);
+ }
+ }
+ else
+ {
+ nlSetError(NL_WRONG_TYPE);
+ }
+ return NL_FALSE;
+}
+
+void sock_Close(NLsocket socket)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ struct ip_mreq mreq;
+
+ if(sock->type == NL_UDP_MULTICAST)
+ {
+ /* leave the multicast group */
+ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)&sock->addressout)->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = bindaddress;
+
+ (void)setsockopt((SOCKET)sock->realsocket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (char *)&mreq, (int)sizeof(mreq));
+ }
+ if(sock->type == NL_RELIABLE_PACKETS)
+ {
+ /* check for unsent data */
+ if(sock->sendlen > 0)
+ {
+ int tries = 200;
+
+ /* 200 * 50 ms = up to a 10 second delay to allow data to be sent */
+ while(tries-- > 0 && sock->sendlen > 0)
+ {
+ htThreadSleep(50);
+ }
+ }
+ sock_DeleteSocket(socket);
+ }
+ if((sock->type == NL_RELIABLE_PACKETS || sock->type == NL_RELIABLE) && sock->listen == NL_FALSE)
+ {
+ struct linger l = {1, 1};
+
+ (void)setsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_LINGER, (const char *)&l, (int)sizeof(l));
+ (void)shutdown((SOCKET)sock->realsocket, SD_RECEIVE);
+ }
+ else
+ {
+ (void)shutdown((SOCKET)sock->realsocket, SD_BOTH);
+ }
+ (void)closesocket((SOCKET)sock->realsocket);
+}
+
+/* internal function to read reliable packets from TCP stream */
+static NLint sock_ReadPacket(NLsocket socket, NLvoid /*@out@*/ *buffer, NLint nbytes,
+ NLboolean checkonly)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ /* skip error reporting if checkonly is TRUE */
+ /* check for sync */
+ if(sock->packetsync == NL_FALSE)
+ {
+ if(checkonly == NL_FALSE)
+ {
+ nlSetError(NL_PACKET_SYNC);
+ }
+ else
+ {
+ sock->readable = NL_TRUE;
+ }
+ return NL_INVALID;
+ }
+
+ if(sock->message_end == NL_TRUE && checkonly == NL_FALSE && sock->reclen == 0)
+ {
+ sock->message_end = NL_FALSE;
+ nlSetError(NL_MESSAGE_END);
+ return NL_INVALID;
+ }
+ /* allocate some temp storage the first time through */
+ if(sock->inbuf == NULL)
+ {
+ sock->inbuflen = (nbytes + nbytes / 4 + NL_HEADER_LEN);
+
+ if(sock->inbuflen < 1024)
+ {
+ sock->inbuflen = 1024;
+ }
+ else if(sock->inbuflen > NL_MAX_PACKET_LENGTH + NL_MAX_PACKET_LENGTH/4)
+ {
+ sock->inbuflen = NL_MAX_PACKET_LENGTH + NL_MAX_PACKET_LENGTH/4;
+ }
+ sock->inbuf = (NLbyte *)malloc((size_t)sock->inbuflen);
+ if(sock->inbuf == NULL)
+ {
+ if(checkonly == NL_FALSE)
+ {
+ sock->inbuflen = 0;
+ nlSetError(NL_OUT_OF_MEMORY);
+ }
+ return NL_INVALID;
+ }
+ }
+ /* if inbuf is empty, get some data */
+ if(sock->reclen < NL_HEADER_LEN)
+ {
+ NLint count;
+
+ count = recv((SOCKET)sock->realsocket, (char *)(sock->inbuf + sock->reclen), (sock->inbuflen - sock->reclen), 0);
+ if(count == SOCKET_ERROR)
+ {
+ if(checkonly == NL_FALSE)
+ {
+ return sock_Error();
+ }
+ else
+ {
+ sock->readable = NL_TRUE;
+ return NL_INVALID;
+ }
+ }
+ if(count == 0)
+ {
+ if(checkonly == NL_FALSE)
+ {
+ nlSetError(NL_MESSAGE_END);
+ }
+ else
+ {
+ sock->message_end = NL_TRUE;
+ sock->readable = NL_TRUE;
+ }
+ return NL_INVALID;
+ }
+ sock->reclen += count;
+ }
+ /* start parsing the packet */
+ if(sock->reclen >= NL_HEADER_LEN)
+ {
+ NLboolean done = NL_FALSE;
+ NLushort len;
+ NLint c = 2;
+
+ /* check for valid packet */
+ if(sock->inbuf[0] != 'N' || sock->inbuf[1] != 'L')
+ {
+ /* packet is not valid, we are somehow out of sync,
+ or we are talking to a regular TCP stream */
+ if(checkonly == NL_FALSE)
+ {
+ nlSetError(NL_PACKET_SYNC);
+ }
+ else
+ {
+ sock->readable = NL_TRUE;
+ }
+ sock->packetsync = NL_FALSE;
+ return NL_INVALID;
+ }
+
+ /* read the length of the packet */
+ readShort(sock->inbuf, c, len);
+ if(len > NL_MAX_PACKET_LENGTH)
+ {
+ /* packet is not valid, or we are talking to a regular TCP stream */
+ if(checkonly == NL_FALSE)
+ {
+ nlSetError(NL_PACKET_SYNC);
+ }
+ else
+ {
+ sock->readable = NL_TRUE;
+ }
+ sock->packetsync = NL_FALSE;
+ return NL_INVALID;
+ }
+ /* check to see if we need to make the inbuf storage larger */
+ if((NLint)len > sock->inbuflen)
+ {
+ NLint newbuflen;
+ NLbyte *temp;
+
+ newbuflen = (len + len / 4 + NL_HEADER_LEN);
+ temp = (NLbyte *)realloc(sock->inbuf, (size_t)newbuflen);
+ if(temp == NULL)
+ {
+ if(checkonly == NL_FALSE)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ }
+ return NL_INVALID;
+ }
+ sock->inbuf = temp;
+ sock->inbuflen = newbuflen;
+ }
+ if(checkonly == NL_FALSE)
+ {
+ if(len > (NLushort)nbytes)
+ {
+ nlSetError(NL_BUFFER_SIZE);
+ return NL_INVALID;
+ }
+ }
+ /* see if we need to get more of the packet */
+ if(len > (NLushort)(sock->reclen - c))
+ {
+ done = NL_FALSE;
+ while(done == NL_FALSE)
+ {
+ NLint count;
+
+ if(checkonly == NL_FALSE)
+ {
+ count = recv((SOCKET)sock->realsocket,
+ (char *)(sock->inbuf + sock->reclen),
+ (sock->inbuflen - sock->reclen), 0);
+ }
+ else
+ {
+ /* we are calling this from PollGroup, so it cannot block */
+ fd_set fdset;
+ struct timeval t = {0,0};
+
+ FD_ZERO(&fdset);
+ FD_SET((SOCKET)sock->realsocket, &fdset);
+ if(select(sock->realsocket + 1, &fdset, NULL, NULL, &t) == 1)
+ {
+ count = recv((SOCKET)sock->realsocket,
+ (char *)(sock->inbuf + sock->reclen),
+ (sock->inbuflen - sock->reclen), 0);
+ }
+ else
+ {
+ /* socket would block, so break */
+ break;
+ }
+ }
+ if(count == SOCKET_ERROR)
+ {
+ if(checkonly == NL_FALSE)
+ {
+ /* check to see if we already have all the packet */
+ if(len <= (NLushort)(sock->reclen - c))
+ {
+ done = NL_TRUE;
+ }
+ else
+ {
+ /* report the error */
+ return sock_Error();
+ }
+ }
+ else
+ {
+ done = NL_TRUE;
+ }
+ }
+ else if(count == 0)
+ {
+ sock->message_end = NL_TRUE;
+ sock->readable = NL_TRUE;
+ done = NL_TRUE;
+ }
+ else
+ {
+ sock->reclen += count;
+ if(len <= (NLushort)(sock->reclen - c))
+ {
+ done = NL_TRUE;
+ }
+ }
+ }
+ }
+ /* see if we now have all of the packet */
+ if(len <= (NLushort)(sock->reclen - c))
+ {
+ sock->readable = NL_TRUE;
+
+ if(checkonly == NL_FALSE)
+ {
+ /* copy the packet */
+ memcpy(buffer, (sock->inbuf + c), (size_t)len);
+
+ /* check for another packet */
+ sock->reclen -= (len + c);
+ if(sock->reclen > 0)
+ {
+ /* move it down to the beginning of inbuf */
+ memmove(sock->inbuf, (sock->inbuf + c + len), (size_t)sock->reclen);
+ }
+ /* quick check to see if we have another complete packet buffered */
+ if(sock->reclen >= NL_HEADER_LEN)
+ {
+ NLushort templen;
+
+ /* read the length of the packet */
+ c = 2;
+ readShort(sock->inbuf, c, templen);
+
+ /* check the length */
+ if(templen <= (NLushort)(sock->reclen - c))
+ {
+ /* we have another complete packet, so mark as readable for PollGroup */
+ sock->readable = NL_TRUE;
+ }
+ else
+ {
+ sock->readable = NL_FALSE;
+ }
+ }
+ else
+ {
+ sock->readable = NL_FALSE;
+ }
+ return (NLint)len;
+ }
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+NLint sock_Read(NLsocket socket, NLvoid *buffer, NLint nbytes)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ NLint count;
+
+ if(nbytes < 0)
+ {
+ return 0;
+ }
+ if(sock->type == NL_RELIABLE || sock->type == NL_RELIABLE_PACKETS) /* TCP */
+ {
+ /* check for a non-blocking connection pending */
+ if(sock->connecting == NL_TRUE)
+ {
+ fd_set fdset;
+ struct timeval t = {0,0};
+ int serrval = -1;
+ socklen_t serrsize = (socklen_t)sizeof(serrval);
+
+
+ FD_ZERO(&fdset);
+ FD_SET((SOCKET)sock->realsocket, &fdset);
+ if(select(sock->realsocket + 1, NULL, &fdset, NULL, &t) == 1)
+ {
+ /* Check the socket status */
+ (void)getsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_ERROR, (char *)&serrval, &serrsize );
+ if(serrval != 0)
+ {
+ if(serrval == (int)ECONNREFUSED)
+ {
+ nlSetError(NL_CON_REFUSED);
+ }
+ else if(serrval == (int)EINPROGRESS || serrval == (int)EWOULDBLOCK)
+ {
+ nlSetError(NL_CON_PENDING);
+ }
+ return NL_INVALID;
+ }
+ /* the connect has completed */
+ sock->connected = NL_TRUE;
+ sock->connecting = NL_FALSE;
+ }
+ else
+ {
+ /* check for a failed connect */
+ FD_ZERO(&fdset);
+ FD_SET((SOCKET)sock->realsocket, &fdset);
+ if(select(sock->realsocket + 1, NULL, NULL, &fdset, &t) == 1)
+ {
+ nlSetError(NL_CON_REFUSED);
+ }
+ else
+ {
+ nlSetError(NL_CON_PENDING);
+ }
+ return NL_INVALID;
+ }
+ }
+ /* check for reliable packets */
+ if(sock->type == NL_RELIABLE_PACKETS)
+ {
+ return sock_ReadPacket(socket, buffer, nbytes, NL_FALSE);
+ }
+ count = recv((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
+ if(count == 0)
+ {
+ /* end of message */
+ nlSetError(NL_MESSAGE_END);
+ return NL_INVALID;
+ }
+ }
+ else /* UDP */
+ {
+ /* check for a non-blocking connection pending */
+ if(sock->connecting == NL_TRUE)
+ {
+ nlSetError(NL_CON_PENDING);
+ return NL_INVALID;
+ }
+ /* check for a connection error */
+ if(sock->conerror == NL_TRUE)
+ {
+ nlSetError(NL_CON_REFUSED);
+ return NL_INVALID;
+ }
+ if(sock->connected == NL_TRUE)
+ {
+ count = recv((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
+ }
+ else
+ {
+ socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
+
+ count = recvfrom((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0,
+ (struct sockaddr *)&sock->addressin, &len);
+ }
+ }
+ if(count == SOCKET_ERROR)
+ {
+ return sock_Error();
+ }
+ return count;
+}
+
+static NLboolean allocateBuffer(nl_socket_t *sock, NLint nbytes)
+{
+ NLint size = NLMIN(NLMAX((nbytes + NL_HEADER_LEN) * 2, 1024), (NL_MAX_PACKET_LENGTH + NL_HEADER_LEN));
+
+ /* first call */
+ if(sock->outbuf == NULL)
+ {
+ sock->outbuf = (NLbyte *)malloc((size_t)size);
+ if(sock->outbuf == NULL)
+ {
+ sock->outbuflen = 0;
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_FALSE;
+ }
+ sock->outbuflen = size;
+ }
+ else
+ {
+ if(size > sock->outbuflen)
+ {
+ NLbyte *temp;
+
+ temp = (NLbyte *)realloc(sock->outbuf, (size_t)size);
+ if(temp == NULL)
+ {
+ sock->outbuflen = 0;
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_FALSE;
+ }
+ sock->outbuf = temp;
+ sock->outbuflen = size;
+ }
+ }
+ return NL_TRUE;
+}
+
+static NLint sock_WritePacket(NLsocket socket, const NLvoid *buffer, NLint nbytes)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ NLint count;
+ NLbyte temp[NL_HEADER_LEN];
+ NLint c = 0;
+
+ /* allocate memory for outbuf */
+ if(sock->outbuf == NULL)
+ {
+ if(allocateBuffer(sock, nbytes) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ }
+ else
+ {
+ /* send any unsent data from last packet */
+ sock_WritePacketCheckPending(socket);
+ }
+
+ /* check to see if we already have some pending data */
+ if(sock->sendlen > 0)
+ {
+ /* to comply with the way UDP packets act */
+ /* if the send buffer has unsent data return 0 */
+ return 0;
+ }
+
+ /* ID for packets is 'NL'*/
+ writeByte(temp, c, 'N');
+ writeByte(temp, c, 'L');
+ /* add the packet length */
+ writeShort(temp, c, (NLushort)nbytes);
+
+ count = send((SOCKET)sock->realsocket, (char *)temp, c, 0);
+
+ if(count == SOCKET_ERROR)
+ {
+ if(sockerrno == (int)EWOULDBLOCK)
+ {
+ count = 0;
+ }
+ else
+ {
+ return sock_Error();
+ }
+ }
+ if(count < c)
+ {
+ int dif = c - count;
+
+ /* check outbuf size */
+ if(allocateBuffer(sock, nbytes) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ /* store it */
+ memcpy((sock->outbuf + sock->sendlen), (temp + count), (size_t)(dif));
+ sock->sendlen += (dif);
+ memcpy((sock->outbuf + sock->sendlen), ((NLbyte *)buffer), (size_t)(nbytes));
+ sock->sendlen += (nbytes);
+ rpBufferedCount++;
+ }
+ else
+ {
+ count = send((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
+ if(count == SOCKET_ERROR)
+ {
+ if(sockerrno == (int)EWOULDBLOCK)
+ {
+ count = 0;
+ }
+ else
+ {
+ return sock_Error();
+ }
+ }
+ /* make sure all was sent */
+ if(count < nbytes)
+ {
+ int dif = nbytes - count;
+
+ /* check outbuf size */
+ if(allocateBuffer(sock, nbytes) == NL_FALSE)
+ {
+ return NL_INVALID;
+ }
+ /* store it */
+ memcpy((sock->outbuf + sock->sendlen), ((NLbyte *)buffer + count), (size_t)(dif));
+ sock->sendlen += dif;
+ rpBufferedCount++;
+ }
+ }
+ count = nbytes;
+ return count;
+}
+
+NLint sock_Write(NLsocket socket, const NLvoid *buffer, NLint nbytes)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ NLint count;
+
+ if(nbytes < 0)
+ {
+ return 0;
+ }
+ if((sock->type == NL_RELIABLE) || (sock->type == NL_RELIABLE_PACKETS)) /* TCP */
+ {
+ if(sock->connecting == NL_TRUE)
+ {
+ fd_set fdset;
+ struct timeval t = {0,0};
+ int serrval = -1;
+ socklen_t serrsize = (socklen_t)sizeof(serrval);
+
+
+ FD_ZERO(&fdset);
+ FD_SET((SOCKET)sock->realsocket, &fdset);
+ if(select(sock->realsocket + 1, NULL, &fdset, NULL, &t) == 1)
+ {
+ /* Check the socket status */
+ (void)getsockopt((SOCKET)sock->realsocket, SOL_SOCKET, SO_ERROR, (char *)&serrval, &serrsize );
+ if(serrval != 0)
+ {
+ if(serrval == (int)ECONNREFUSED)
+ {
+ nlSetError(NL_CON_REFUSED);
+ }
+ else if(serrval == (int)EINPROGRESS || serrval == (int)EWOULDBLOCK)
+ {
+ nlSetError(NL_CON_PENDING);
+ }
+ return NL_INVALID;
+ }
+ /* the connect has completed */
+ sock->connected = NL_TRUE;
+ sock->connecting = NL_FALSE;
+ }
+ else
+ {
+ /* check for a failed connect */
+ FD_ZERO(&fdset);
+ FD_SET((SOCKET)sock->realsocket, &fdset);
+ if(select(sock->realsocket + 1, NULL, NULL, &fdset, &t) == 1)
+ {
+ nlSetError(NL_CON_REFUSED);
+ }
+ else
+ {
+ nlSetError(NL_CON_PENDING);
+ }
+ return NL_INVALID;
+ }
+ }
+ /* check for reliable packets */
+ if(sock->type == NL_RELIABLE_PACKETS)
+ {
+ if(nbytes > NL_MAX_PACKET_LENGTH)
+ {
+ nlSetError(NL_PACKET_SIZE);
+ return NL_INVALID;
+ }
+ return sock_WritePacket(socket, buffer, nbytes);
+ }
+ count = send((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
+ }
+ else /* unconnected UDP */
+ {
+ int maxpacket = NL_MAX_PACKET_LENGTH;
+ int sizesockaddr = (int)sizeof(struct sockaddr_in);
+
+ /* check for a non-blocking connection pending */
+ if(sock->connecting == NL_TRUE)
+ {
+ nlSetError(NL_CON_PENDING);
+ return NL_INVALID;
+ }
+ /* check for a connection error */
+ if(sock->conerror == NL_TRUE)
+ {
+ nlSetError(NL_CON_REFUSED);
+ return NL_INVALID;
+ }
+#ifdef NL_INCLUDE_IPX
+ if(sock->driver == NL_IPX)
+ {
+ maxpacket = 1466;
+ sizesockaddr = (int)sizeof(struct sockaddr_ipx);
+ }
+#endif
+ if(nbytes > maxpacket)
+ {
+ nlSetError(NL_PACKET_SIZE);
+ return NL_INVALID;
+ }
+ if(sock->type == NL_UDP_MULTICAST)
+ {
+ count = sendto((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0,
+ (struct sockaddr *)&sock->addressout,
+ (int)sizeof(struct sockaddr_in));
+ }
+ else if(sock->connected == NL_TRUE)
+ {
+ count = send((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0);
+ }
+ else
+ {
+ count = sendto((SOCKET)sock->realsocket, (char *)buffer, nbytes, 0,
+ (struct sockaddr *)&sock->addressout, sizesockaddr);
+ }
+ }
+ if(count == SOCKET_ERROR)
+ {
+ return sock_Error();
+ }
+ return count;
+}
+
+NLchar *sock_AddrToString(const NLaddress *address, NLchar *string)
+{
+ NLulong addr;
+ NLushort port;
+
+ addr = ntohl(((struct sockaddr_in *)address)->sin_addr.s_addr);
+ port = ntohs(((struct sockaddr_in *)address)->sin_port);
+ if(port == 0)
+ {
+ _stprintf(string, TEXT("%lu.%lu.%lu.%lu"), (addr >> 24) & 0xff, (addr >> 16)
+ & 0xff, (addr >> 8) & 0xff, addr & 0xff);
+ }
+ else
+ {
+ _stprintf(string, TEXT("%lu.%lu.%lu.%lu:%u"), (addr >> 24) & 0xff, (addr >> 16)
+ & 0xff, (addr >> 8) & 0xff, addr & 0xff, port);
+ }
+ return string;
+}
+
+NLboolean sock_StringToAddr(const NLchar *string, NLaddress *address)
+{
+ NLulong a1, a2, a3, a4;
+ NLulong ipaddress, port = 0;
+ int ret;
+
+ ret = _stscanf((const NLchar *)string, (const NLchar *)TEXT("%lu.%lu.%lu.%lu:%lu"), &a1, &a2, &a3, &a4, &port);
+
+ if(a1 > 255 || a2 > 255 || a3 > 255 || a4 > 255 || port > 65535 || ret < 4)
+ {
+ /* bad address */
+ ((struct sockaddr_in *)address)->sin_family = AF_INET;
+ ((struct sockaddr_in *)address)->sin_addr.s_addr = INADDR_NONE;
+ ((struct sockaddr_in *)address)->sin_port = 0;
+ nlSetError(NL_BAD_ADDR);
+ address->valid = NL_FALSE;
+ return NL_FALSE;
+ }
+ else
+ {
+ ipaddress = (a1 << 24) | (a2 << 16) | (a3 << 8) | a4;
+ ((struct sockaddr_in *)address)->sin_family = AF_INET;
+ ((struct sockaddr_in *)address)->sin_addr.s_addr = htonl(ipaddress);
+ ((struct sockaddr_in *)address)->sin_port = htons((NLushort)port);
+ address->valid = NL_TRUE;
+ return NL_TRUE;
+ }
+}
+
+NLboolean sock_GetLocalAddr(NLsocket socket, NLaddress *address)
+{
+ nl_socket_t *sock = nlSockets[socket];
+ socklen_t len;
+
+ memset(address, 0, sizeof(NLaddress));
+ ((struct sockaddr_in *)address)->sin_family = AF_INET;
+ address->valid = NL_TRUE;
+ len = (socklen_t)sizeof(struct sockaddr_in);
+ /* if the socket is connected, this will get us
+ the correct address on a multihomed system*/
+ if(getsockname((SOCKET)sock->realsocket, (struct sockaddr *)address, &len) == SOCKET_ERROR)
+ {
+ /* ignore error if socket has not been bound or connected yet */
+ if(sockerrno != (int)EINVAL)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ address->valid = NL_FALSE;
+ return NL_FALSE;
+ }
+ }
+
+ /* if not connected, substitute the NIC address */
+ if(((struct sockaddr_in *)address)->sin_addr.s_addr == INADDR_ANY)
+ {
+ ((struct sockaddr_in *)address)->sin_addr.s_addr = ouraddress;
+ }
+ sock_SetAddrPort(address, sock->localport);
+ return NL_TRUE;
+}
+
+NLaddress *sock_GetAllLocalAddr(NLint *count)
+{
+ struct hostent *local;
+ char buff[MAXHOSTNAMELEN];
+ int i = 0;
+
+ if(gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NULL;
+ }
+ buff[MAXHOSTNAMELEN - 1] = '\0';
+ local = gethostbyname(buff);
+ if(local == NULL)
+ {
+ if(sockerrno == (int)ENETDOWN)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NULL;
+ }
+ }
+ /* count the number of returned IP addresses */
+ *count = 0;
+ if(local != NULL)
+ {
+ while(local->h_addr_list[i++] != NULL)
+ {
+ (*count)++;
+ }
+ }
+ /* allocate storage for address */
+ if(alladdr != NULL)
+ {
+ free(alladdr);
+ }
+ if(*count == 0)
+ {
+ *count = 1;
+ alladdr = (NLaddress *)malloc(sizeof(NLaddress));
+ memset(alladdr, 0, sizeof(NLaddress));
+
+ /* fill in the localhost address */
+ ((struct sockaddr_in *)alladdr)->sin_family = AF_INET;
+ ((struct sockaddr_in *)alladdr)->sin_addr.s_addr = (NLuint)htonl(0x7f000001);
+ alladdr->valid = NL_TRUE;
+ }
+ else
+ {
+ alladdr = (NLaddress *)malloc(sizeof(NLaddress) * *count);
+ memset(alladdr, 0, sizeof(NLaddress) * *count);
+
+ /* fill in the addresses */
+ i = 0;
+ while(local->h_addr_list[i] != NULL)
+ {
+ NLaddress *addr = &alladdr[i];
+
+ ((struct sockaddr_in *)addr)->sin_family = AF_INET;
+ ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(NLuint *)local->h_addr_list[i];
+ addr->valid = NL_TRUE;
+ i++;
+ }
+ }
+ return alladdr;
+}
+
+NLboolean sock_SetLocalAddr(const NLaddress *address)
+{
+ /* should we check against all the local addresses? */
+ bindaddress = ouraddress = (NLuint)((struct sockaddr_in *)address)->sin_addr.s_addr;
+ return NL_TRUE;
+}
+
+NLchar *sock_GetNameFromAddr(const NLaddress *address, NLchar *name)
+{
+ struct hostent *hostentry;
+ NLchar tempname[MAXHOSTNAMELEN];
+
+ hostentry = gethostbyaddr((char *)&((struct sockaddr_in *)address)->sin_addr,
+ (int)sizeof(struct in_addr), AF_INET);
+ if(hostentry != NULL)
+ {
+ NLushort port = sock_GetPortFromAddr(address);
+#ifdef _UNICODE
+ NLchar temp[MAXHOSTNAMELEN];
+ /* convert from multibyte char string to wide char string */
+ mbstowcs(temp, (const char *)hostentry->h_name, MAXHOSTNAMELEN);
+ temp[MAXHOSTNAMELEN - 1] = '\0';
+#else
+ NLchar *temp = (NLchar *)hostentry->h_name;
+#endif
+ if(port != 0)
+ {
+ _sntprintf(tempname, (size_t)(NL_MAX_STRING_LENGTH), (const NLchar *)TEXT("%s:%hu"), (const NLchar *)temp, port);
+ }
+ else
+ {
+ _tcsncpy(tempname, (const NLchar *)temp, (size_t)(NL_MAX_STRING_LENGTH));
+ }
+ tempname[NL_MAX_STRING_LENGTH - 1] = (NLchar)'\0';
+ }
+ else
+ {
+ if(((struct sockaddr_in *)address)->sin_addr.s_addr == (unsigned long)INADDR_NONE)
+ {
+ _tcsncpy(tempname, (const NLchar *)TEXT("Bad address"), (size_t)(NL_MAX_STRING_LENGTH));
+ }
+ else
+ {
+ (void)sock_AddrToString(address, tempname);
+ }
+ }
+ /* special copy in case this was called as sock_GetNameFromAddrAsync */
+ name[0] = (NLchar)'\0';
+ _tcsncpy(&name[1], (const NLchar *)&tempname[1], (size_t)(NL_MAX_STRING_LENGTH - 1));
+ name[0] = tempname[0];
+ return name;
+}
+
+static void *sock_GetNameFromAddrAsyncInt(void /*@owned@*/ * addr)
+{
+ NLaddress_ex_t *address = (NLaddress_ex_t *)addr;
+
+ (void)sock_GetNameFromAddr(address->address, address->name);
+ free(address->address);
+ free(address);
+ return NULL;
+}
+
+NLboolean sock_GetNameFromAddrAsync(const NLaddress *address, NLchar *name)
+{
+ NLaddress_ex_t *addr;
+
+ memset(name, 0, sizeof(NLchar) * NL_MAX_STRING_LENGTH);
+ addr = (NLaddress_ex_t *)malloc(sizeof(NLaddress_ex_t));
+ if(addr == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_FALSE;
+ }
+ addr->address = (NLaddress *)malloc(sizeof(NLaddress));
+ if(addr->address == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ free(addr);
+ return NL_FALSE;
+ }
+ memcpy(addr->address, address, sizeof(NLaddress));
+ addr->name = name;
+ if(htThreadCreate(sock_GetNameFromAddrAsyncInt, (void *)addr, NL_FALSE) == (HThreadID)HT_INVALID)
+ {
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean sock_GetAddrFromName(const NLchar *name, NLaddress *address)
+{
+ struct hostent *hostentry;
+ NLushort port = 0;
+ int pos;
+ NLbyte temp[NL_MAX_STRING_LENGTH];
+
+ address->valid = NL_FALSE;
+ /* first check to see if we have a numeric address already */
+ (void)sock_StringToAddr(name, address);
+ /* clear out an NL_BAD_ADDR error */
+ if(nlGetError() == NL_BAD_ADDR)
+ {
+ nlSetError(NL_NO_ERROR);
+ }
+ if(((struct sockaddr_in *)address)->sin_addr.s_addr != (unsigned long)INADDR_NONE)
+ {
+ /* we are already done! */
+ address->valid = NL_TRUE;
+ return NL_TRUE;
+ }
+
+#ifdef _UNICODE
+ /* convert from wide char string to multibyte char string */
+ (void)wcstombs(temp, (const NLchar *)name, NL_MAX_STRING_LENGTH);
+#else
+ strncpy(temp, name, NL_MAX_STRING_LENGTH);
+#endif
+ temp[NL_MAX_STRING_LENGTH - 1] = (NLbyte)'\0';
+ pos = (int)strcspn(temp, (const char *)":");
+ if(pos > 0)
+ {
+ NLbyte *p = &temp[pos+1];
+
+ temp[pos] = (NLbyte)'\0';
+ (void)sscanf(p, "%hu", &port);
+ }
+ hostentry = gethostbyname((const char *)temp);
+
+ if(hostentry != NULL)
+ {
+ ((struct sockaddr_in *)address)->sin_family = AF_INET;
+ ((struct sockaddr_in *)address)->sin_port = htons(port);
+ ((struct sockaddr_in *)address)->sin_addr.s_addr = *(NLulong *)hostentry->h_addr_list[0];
+ address->valid = NL_TRUE;
+ }
+ else
+ {
+ ((struct sockaddr_in *)address)->sin_family = AF_INET;
+ ((struct sockaddr_in *)address)->sin_addr.s_addr = INADDR_NONE;
+ ((struct sockaddr_in *)address)->sin_port = 0;
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+static void *sock_GetAddrFromNameAsyncInt(void /*@owned@*/ *addr)
+{
+ NLaddress_ex_t *address = (NLaddress_ex_t *)addr;
+
+ (void)sock_GetAddrFromName(address->name, address->address);
+ address->address->valid = NL_TRUE;
+ free(address->name);
+ free(address);
+ return NULL;
+}
+
+NLboolean sock_GetAddrFromNameAsync(const NLchar *name, NLaddress *address)
+{
+ NLaddress_ex_t *addr;
+
+ address->valid = NL_FALSE;
+ addr = (NLaddress_ex_t *)malloc(sizeof(NLaddress_ex_t));
+ if(addr == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ return NL_FALSE;
+ }
+ addr->name = (NLchar *)malloc(NL_MAX_STRING_LENGTH);
+ if(addr->name == NULL)
+ {
+ nlSetError(NL_OUT_OF_MEMORY);
+ free(addr);
+ return NL_FALSE;
+ }
+ _tcsncpy(addr->name, name, (size_t)NL_MAX_STRING_LENGTH);
+ addr->name[NL_MAX_STRING_LENGTH - 1] = '\0';
+ addr->address = address;
+ if(htThreadCreate(sock_GetAddrFromNameAsyncInt, (void *)addr, NL_FALSE) == (HThreadID)HT_INVALID)
+ {
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean sock_AddrCompare(const NLaddress *address1, const NLaddress *address2)
+{
+ if(((struct sockaddr_in *)address1)->sin_family != ((struct sockaddr_in *)address2)->sin_family)
+ return NL_FALSE;
+
+ if(((struct sockaddr_in *)address1)->sin_addr.s_addr
+ != ((struct sockaddr_in *)address2)->sin_addr.s_addr)
+ return NL_FALSE;
+
+ if(((struct sockaddr_in *)address1)->sin_port
+ != ((struct sockaddr_in *)address2)->sin_port)
+ return NL_FALSE;
+
+ return NL_TRUE;
+}
+
+NLushort sock_GetPortFromAddr(const NLaddress *address)
+{
+ return ntohs(((struct sockaddr_in *)address)->sin_port);
+}
+
+void sock_SetAddrPort(NLaddress *address, NLushort port)
+{
+ ((struct sockaddr_in *)address)->sin_port = htons((NLushort)port);
+}
+
+NLint sock_GetSystemError(void)
+{
+ NLint err = sockerrno;
+
+#ifdef HL_WINDOWS_APP
+ if(err < WSABASEERR)
+ {
+ if(errno > 0)
+ {
+ err = errno;
+ }
+ }
+#endif
+ return err;
+}
+
+NLint sock_PollGroup(NLint group, NLenum name, NLsocket *sockets, NLint number, NLint timeout)
+{
+ NLint numselect, count = 0;
+ NLint numsockets = NL_MAX_GROUP_SOCKETS;
+ NLsocket temp[NL_MAX_GROUP_SOCKETS];
+ NLboolean reliable[NL_MAX_GROUP_SOCKETS];
+ NLboolean result;
+ NLsocket *ptemp = temp;
+ int i, found = 0;
+ fd_set fdset;
+ SOCKET highest;
+ struct timeval t = {0,0}; /* {seconds, useconds}*/
+ struct timeval *tp = &t;
+
+ nlGroupLock();
+ highest = nlGroupGetFdset(group, &fdset);
+
+ if(highest == INVALID_SOCKET)
+ {
+ /* error is set by nlGroupGetFdset */
+ nlGroupUnlock();
+ return NL_INVALID;
+ }
+
+ result = nlGroupGetSocketsINT(group, ptemp, &numsockets);
+ nlGroupUnlock();
+
+ if(result == NL_FALSE)
+ {
+ /* any error is set by nlGroupGetSockets */
+ return NL_INVALID;
+ }
+ if(numsockets == 0)
+ {
+ return 0;
+ }
+
+ if(name == NL_READ_STATUS)
+ {
+ /* check for buffered reliable packets */
+ for(i=0;i<numsockets;i++)
+ {
+ nl_socket_t *s = nlSockets[ptemp[i]];
+
+ if(s->type == NL_RELIABLE_PACKETS && s->readable == NL_TRUE)
+ {
+ /* mark as readable */
+ reliable[i] = NL_TRUE;
+ found++;
+ /* change the timeout to 0, or non-blocking since we */
+ /* have at least one reliable packet to read */
+ timeout = 0;
+ }
+ else
+ {
+ reliable[i] = NL_FALSE;
+ }
+ }
+ }
+
+ /* check for full blocking call */
+ if(timeout < 0)
+ {
+ tp = NULL;
+ }
+ else /* set t values */
+ {
+ t.tv_sec = timeout/1000;
+ t.tv_usec = (timeout%1000) * 1000;
+ }
+
+ /* call select to check the status */
+ switch(name) {
+
+ case NL_READ_STATUS:
+ numselect = select((int)highest, &fdset, NULL, NULL, tp);
+ break;
+
+ case NL_WRITE_STATUS:
+ numselect = select((int)highest, NULL, &fdset, NULL, tp);
+ break;
+
+ case NL_ERROR_STATUS:
+ numselect = select((int)highest, NULL, NULL, &fdset, tp);
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_INVALID;
+ }
+ if(numselect == SOCKET_ERROR)
+ {
+ if(sockerrno == (int)ENOTSOCK)
+ {
+ /* one of the sockets has been closed */
+ nlSetError(NL_INVALID_SOCKET);
+ }
+ else if(sockerrno == (int)EINTR)
+ {
+ /* select was interrupted by the system, maybe because the app is exiting */
+ return 0;
+ }
+ else
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ }
+ return NL_INVALID;
+ }
+
+ if(numselect > number)
+ {
+ nlSetError(NL_BUFFER_SIZE);
+ return NL_INVALID;
+ }
+ /* fill *sockets with a list of the sockets ready to be read */
+ numselect += found;
+ i = 0;
+ while(numsockets-- > 0 && numselect > count)
+ {
+ nl_socket_t *s = nlSockets[*ptemp];
+
+ if((reliable[i] == NL_TRUE ) || (FD_ISSET(s->realsocket, &fdset) != 0))
+ {
+ /* if checking for read status, must check for a complete packet */
+ if(s->type == NL_RELIABLE_PACKETS && s->listen == NL_FALSE && name == NL_READ_STATUS)
+ {
+ (void)nlLockSocket(*ptemp, NL_READ);
+ if(s->readable != NL_TRUE)
+ {
+ if(s->inuse == NL_TRUE)
+ {
+ (void)sock_ReadPacket(*ptemp, NULL, 0, NL_TRUE);
+ }
+ else
+ {
+ s->readable = NL_FALSE;
+ }
+ }
+ if(s->readable == NL_TRUE)
+ {
+ /* we do have a complete packet */
+ *sockets = *ptemp;
+ sockets++;
+ count++;
+ }
+ nlUnlockSocket(*ptemp, NL_READ);
+ }
+ else
+ {
+ *sockets = *ptemp;
+ sockets++;
+ count ++;
+ }
+ }
+ i++;
+ ptemp++;
+ }
+ return count;
+}
+
+NLboolean sock_PollSocket(NLsocket socket, NLenum name, NLint timeout)
+{
+ NLint numselect;
+ nl_socket_t *sock = nlSockets[socket];
+ fd_set fdset;
+ struct timeval t = {0,0}; /* {seconds, useconds}*/
+ struct timeval *tp = &t;
+
+ nlSetError(NL_NO_ERROR);
+ if(name == NL_READ_STATUS)
+ {
+ /* check for buffered reliable packets */
+ nl_socket_t *s = nlSockets[socket];
+
+ if(s->type == NL_TCP_PACKETS && s->readable == NL_TRUE)
+ {
+ return NL_TRUE;
+ }
+ }
+
+ /* check for full blocking call */
+ if(timeout < 0)
+ {
+ tp = NULL;
+ }
+ else /* set t values */
+ {
+ t.tv_sec = timeout/1000;
+ t.tv_usec = (timeout%1000) * 1000;
+ }
+ FD_ZERO(&fdset);
+ FD_SET((SOCKET)(sock->realsocket), &fdset);
+ /* call select to check the status */
+ switch(name) {
+
+ case NL_READ_STATUS:
+ numselect = select((int)(sock->realsocket + 1), &fdset, NULL, NULL, tp);
+ break;
+
+ case NL_WRITE_STATUS:
+ numselect = select((int)(sock->realsocket + 1), NULL, &fdset, NULL, tp);
+ break;
+
+ case NL_ERROR_STATUS:
+ numselect = select((int)(sock->realsocket + 1), NULL, NULL, &fdset, tp);
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ if(numselect == SOCKET_ERROR)
+ {
+ if(sockerrno == (int)ENOTSOCK)
+ {
+ /* the socket has been closed */
+ nlSetError(NL_INVALID_SOCKET);
+ }
+ else if(sockerrno == (int)EINTR)
+ {
+ /* select was interrupted by the system, maybe because the app is exiting */
+ return NL_FALSE;
+ }
+ else
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ }
+ }
+ else if(numselect == 1)
+ {
+ return NL_TRUE;
+ }
+ return NL_FALSE;
+}
+
+NLboolean sock_Hint(NLenum name, NLint arg)
+{
+ switch(name) {
+
+ case NL_LISTEN_BACKLOG:
+ backlog = arg;
+ break;
+
+ case NL_MULTICAST_TTL:
+ if(arg < 1)
+ {
+ arg = 1;
+ }
+ else if(arg > 255)
+ {
+ arg = 255;
+ }
+ multicastTTL = arg;
+ break;
+
+ case NL_REUSE_ADDRESS:
+ reuseaddress = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
+ break;
+
+ case NL_TCP_NO_DELAY:
+ nlTCPNoDelay = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
+ break;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+
+NLboolean sock_SetSocketOpt(NLsocket socket, NLenum name, NLint arg)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ sock->blocking = (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE);
+ if(sock_SetBlocking((SOCKET)sock->realsocket, sock->blocking) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ break;
+ case NL_MULTICAST_TTL:
+ if(sock->type == NL_UDP_MULTICAST)
+ {
+ return(sock_SetMulticastTTL(sock, multicastTTL));
+ }
+ else
+ {
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+
+ case NL_REUSE_ADDRESS:
+ if(sock_SetReuseAddr(sock) == NL_FALSE)
+ {
+ nlSetError(NL_SYSTEM_ERROR);
+ return NL_FALSE;
+ }
+ break;
+ case NL_TCP_NO_DELAY:
+ return (sock_SetTCPNoDelay(sock, (NLboolean)(arg != 0 ? NL_TRUE : NL_FALSE)));
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+ return NL_TRUE;
+}
+NLint sock_GetSocketOpt(NLsocket socket, NLenum name)
+{
+ nl_socket_t *sock = nlSockets[socket];
+
+ switch (name) {
+
+ case NL_BLOCKING_IO:
+ return (NLint)sock->blocking;
+
+ case NL_MULTICAST_TTL:
+ if(sock->type == NL_UDP_MULTICAST)
+ {
+ return sock->TTL;
+ }
+ else
+ {
+ nlSetError(NL_INVALID_ENUM);
+ return NL_FALSE;
+ }
+
+ case NL_REUSE_ADDRESS:
+ return (NLint)sock->reuseaddr;
+
+ case NL_TCP_NO_DELAY:
+ return (NLint)sock->TCPNoDelay;
+
+ default:
+ nlSetError(NL_INVALID_ENUM);
+ return NL_INVALID;
+ }
+}
+
diff --git a/util/network/network.cpp b/util/network/network.cpp
new file mode 100644
index 00000000..c44238ee
--- /dev/null
+++ b/util/network/network.cpp
@@ -0,0 +1,454 @@
+#ifdef HAVE_NETWORKING
+#include "hawknl/nl.h"
+#endif
+#include "network.h"
+#include "globals.h"
+#include "util/debug.h"
+#include <string>
+#include <sstream>
+#include <string.h>
+#include "util/system.h"
+#include "util/compress.h"
+
+using namespace std;
+
+/* TODO: Wrap open_sockets with a mutex */
+namespace Network{
+
+NetworkException::~NetworkException() throw (){
+}
+
+MessageEnd::MessageEnd(){
+}
+
+InvalidPortException::InvalidPortException( int port, const string message ):
+NetworkException(""){
+ ostringstream num;
+ num << port;
+ num << ". ";
+ num << message;
+ this->setMessage( "Invalid port " + num.str() );
+}
+
+Message::Message():
+id((uint32_t) -1),
+timestamp(0),
+readFrom(0){
+ memset(data, 0, sizeof(data));
+ position = data;
+}
+
+Message::Message(const Message & m):
+timestamp(m.timestamp),
+readFrom(m.readFrom){
+ memcpy( data, m.data, sizeof(data) );
+ position = data;
+ position += m.position - m.data;
+ path = m.path;
+ id = m.id;
+}
+
+Message & Message::operator=( const Message & m ){
+ memcpy(data, m.data, sizeof(data));
+ position = data;
+ position += m.position - m.data;
+ path = m.path;
+ id = m.id;
+ timestamp = m.timestamp;
+ readFrom = m.readFrom;
+ return *this;
+}
+
+Message::Message(Socket socket){
+#ifdef HAVE_NETWORKING
+ position = data;
+ id = read32( socket );
+ readBytes( socket, data, DATA_SIZE );
+ int str = read16( socket );
+ if ( str != -1 ){
+ /* cap strings at 1024 bytes */
+ char buf[1024];
+ str = (signed)(sizeof( buf ) - 1) < str ? (signed)(sizeof(buf) - 1) : str;
+ readBytes( socket, (uint8_t *) buf, str );
+ buf[str] = 0;
+ /* this is a string copy, not an assignment to a temporary pointer */
+ this->path = buf;
+ }
+ timestamp = System::currentMicroseconds();
+ readFrom = socket;
+#endif
+}
+
+uint8_t * Message::dump( uint8_t * buffer ) const {
+ *(uint32_t *) buffer = id;
+ buffer += sizeof(id);
+ memcpy( buffer, data, DATA_SIZE );
+ buffer += DATA_SIZE;
+ if ( path != "" ){
+ *(uint16_t *) buffer = path.length() + 1;
+ buffer += sizeof(uint16_t);
+ memcpy( buffer, path.c_str(), path.length() + 1 );
+ buffer += path.length() + 1;
+ } else {
+ *(uint16_t *) buffer = (uint16_t) -1;
+ buffer += sizeof(uint16_t);
+ }
+ return buffer;
+}
+
+/*
+template <typename M>
+int messageSize(const M& message);
+*/
+
+/*
+template <>
+int messageSize<Message>(Message const & message){
+ return message.size();
+}
+
+template <>
+int messageSize<Message*>(Message* const & message){
+ return message->size();
+}
+*/
+static int messageSize(Message const & message){
+ return message.size();
+}
+
+static int messageSize(Message* const & message){
+ return message->size();
+}
+
+/*
+template <class M>
+uint8_t * messageDump(const M& message, uint8_t * buffer);
+
+template <>
+uint8_t * messageDump<Message>(const Message & message, uint8_t * buffer){
+ return message.dump(buffer);
+}
+
+template <>
+uint8_t * messageDump<Message*>(Message* const & message, uint8_t * buffer){
+ return message->dump(buffer);
+}
+*/
+static uint8_t * messageDump(const Message & message, uint8_t * buffer){
+ return message.dump(buffer);
+}
+
+static uint8_t * messageDump(Message* const & message, uint8_t * buffer){
+ return message->dump(buffer);
+}
+
+template <typename M>
+static int totalSize(const vector<M> & messages){
+ int size = 0;
+ for (typename vector<M>::const_iterator it = messages.begin(); it != messages.end(); it++){
+ // size += messageSize<M>(*it);
+ size += messageSize(*it);
+ }
+ return size;
+}
+
+template <class M>
+static void dump(const std::vector<M> & messages, uint8_t * buffer ){
+ for (typename vector<M>::const_iterator it = messages.begin(); it != messages.end(); it++ ){
+ buffer = messageDump(*it, buffer);
+ }
+}
+
+#ifdef HAVE_NETWORKING
+template <class M>
+static void doSendAllMessages(const vector<M> & messages, Socket socket){
+ int length = totalSize<M>(messages);
+ uint8_t * data = new uint8_t[length];
+ dump<M>(messages, data);
+ // Compress::testCompression((unsigned char *) data, length);
+ sendBytes(socket, data, length);
+ delete[] data;
+}
+
+void sendAllMessages(const vector<Message> & messages, Socket socket){
+ doSendAllMessages<Message>(messages, socket);
+}
+
+void sendAllMessages(const vector<Message*> & messages, Socket socket){
+ doSendAllMessages<Message*>(messages, socket);
+}
+#endif
+
+void Message::send( Socket socket ) const {
+ /*
+ send16( socket, id );
+ sendBytes( socket, data, DATA_SIZE );
+ if ( path != "" ){
+ send16( socket, path.length() + 1 );
+ sendStr( socket, path );
+ } else {
+ send16( socket, -1 );
+ }
+ */
+#ifdef HAVE_NETWORKING
+ uint8_t * buffer = new uint8_t[ size() ];
+ dump( buffer );
+ sendBytes( socket, buffer, size() );
+ delete[] buffer;
+#endif
+}
+
+void Message::reset(){
+ position = data;
+}
+
+Message & Message::operator<<(int x){
+ if (position > data + DATA_SIZE - sizeof(uint16_t)){
+ throw NetworkException("Tried to set too much data");
+ }
+
+ *(int16_t *) position = x;
+ position += sizeof(int16_t);
+
+ return *this;
+}
+
+Message & Message::operator<<(unsigned int x){
+ if (position > data + DATA_SIZE - sizeof(uint32_t)){
+ throw NetworkException("Tried to set too much data");
+ }
+
+ *(int32_t *) position = x;
+ position += sizeof(int32_t);
+ return *this;
+}
+
+Message & Message::operator>>(int & x){
+ if (position > data + DATA_SIZE - sizeof(uint16_t)){
+ throw NetworkException("Tried to read too much data");
+ }
+
+ x = *(int16_t *) position;
+ position += sizeof(int16_t);
+ return *this;
+}
+
+Message & Message::operator>>(unsigned int & x){
+ if (position > data + DATA_SIZE - sizeof(uint32_t)){
+ throw NetworkException("Tried to read too much data");
+ }
+
+ x = *(int32_t *) position;
+ position += sizeof(int32_t);
+ return *this;
+}
+
+Message & Message::operator>>(std::string & out){
+ out = path;
+ return *this;
+}
+
+Message & Message::operator<<( string p ){
+ path = p;
+ return *this;
+}
+
+int Message::size() const {
+ return sizeof(id) + DATA_SIZE +
+ (path != "" ? sizeof(uint16_t) + path.length() + 1 : sizeof(uint16_t));
+}
+
+#ifdef HAVE_NETWORKING
+
+static string getHawkError(){
+ return string(" HawkNL error: '") +
+ string( nlGetErrorStr( nlGetError() ) ) +
+ string( "' HawkNL system error: '" ) +
+ string( nlGetSystemErrorStr( nlGetSystemError() ) );
+}
+
+template<typename X>
+static X readX(Socket socket){
+ X data;
+ readBytes(socket, (uint8_t*) &data, sizeof(X));
+ return data;
+}
+
+int16_t read16( Socket socket ){
+ return readX<uint16_t>(socket);
+ /*
+ uint8_t data[ sizeof(uint16_t) ];
+ readBytes( socket, data, sizeof(uint16_t) );
+ return *(uint16_t *)data;
+ */
+
+ /*
+ uint16_t b;
+ int read = nlRead( socket, &b, sizeof(int16_t) );
+ if ( read != sizeof(int16_t) ){
+ throw NetworkException( string("Could not read 16 bits.") + getHawkError() );
+ }
+ return b;
+ */
+}
+
+int32_t read32( Socket socket ){
+ return readX<uint32_t>(socket);
+}
+
+void send16( Socket socket, int16_t bytes ){
+ /*
+ if ( nlWrite( socket, &length, sizeof(int16_t) ) != sizeof(int16_t) ){
+ throw NetworkException( string("Could not send 16 bits.") + getHawkError() );
+ }
+ */
+ sendBytes( socket, (uint8_t *) &bytes, sizeof(bytes) );
+}
+
+string readStr( Socket socket, const uint16_t length ){
+
+ char buffer[ length + 1 ];
+ NLint bytes = nlRead( socket, buffer, length );
+ if ( bytes == NL_INVALID ){
+ throw NetworkException( string("Could not read string.") + getHawkError() );
+ }
+ buffer[ length ] = 0;
+ bytes += 1;
+ return string( buffer );
+
+}
+
+void sendStr( Socket socket, const string & str ){
+ if ( nlWrite( socket, str.c_str(), str.length() + 1 ) != (signed)(str.length() + 1) ){
+ throw NetworkException( string("Could not write string.") + getHawkError() );
+ }
+}
+
+void sendBytes( Socket socket, const uint8_t * data, int length ){
+ const uint8_t * position = data;
+ int written = 0;
+ while ( written < length ){
+ /* put htons here for endianess compatibility */
+ int bytes = nlWrite( socket, position, length - written );
+ if ( bytes == NL_INVALID ){
+ throw NetworkException( string("Could not send bytes.") + getHawkError() );
+ }
+ written += bytes;
+ position += bytes;
+ }
+}
+
+void readBytes( Socket socket, uint8_t * data, int length ){
+ uint8_t * position = data;
+ int read = 0;
+ while ( read < length ){
+ /* put htons here for endianess compatibility */
+ int bytes = nlRead( socket, position, length - read );
+ if ( bytes == NL_INVALID ){
+ switch (nlGetError()){
+ case NL_MESSAGE_END : throw MessageEnd();
+ default : throw NetworkException(string("Could not read bytes.") + getHawkError());
+ }
+ }
+ read += bytes;
+ position += bytes;
+ }
+}
+
+Socket open( int port ) throw (InvalidPortException){
+ // NLsocket server = nlOpen( port, NL_RELIABLE_PACKETS );
+ Global::debug(1, "network") << "Attemping to open port " << port << endl;
+ Socket server = nlOpen( port, NL_RELIABLE );
+ /* server will either be NL_INVALID (-1) or some low integer. hawknl
+ * sockets are mapped internally to real sockets, so don't be surprised
+ * if you get a socket back like 0.
+ */
+ if ( server == NL_INVALID ){
+ throw InvalidPortException(port, nlGetSystemErrorStr(nlGetSystemError()));
+ }
+ Global::debug(1, "network") << "Successfully opened a socket: " << server << endl;
+ open_sockets.push_back( server );
+ return server;
+}
+
+Socket connect( string server, int port ) throw ( NetworkException ) {
+ NLaddress address;
+ nlGetAddrFromName( server.c_str(), &address );
+ nlSetAddrPort( &address, port );
+ Socket socket = open( 0 );
+ if ( nlConnect( socket, &address ) == NL_FALSE ){
+ close( socket );
+ throw NetworkException( "Could not connect" );
+ }
+ return socket;
+}
+
+void close( Socket s ){
+ for ( vector< Socket >::iterator it = open_sockets.begin(); it != open_sockets.end(); ){
+ if ( *it == s ){
+ Global::debug(1, "network") << "Closing socket " << s << endl;
+ nlClose( *it );
+ Global::debug(1, "network") << "Closed" << endl;
+ it = open_sockets.erase( it );
+ } else {
+ it++;
+ }
+ }
+}
+
+void closeAll(){
+ Global::debug(1, "network") << "Closing all sockets" << std::endl;
+ for ( vector< Socket >::iterator it = open_sockets.begin(); it != open_sockets.end(); it++ ){
+ nlClose( *it );
+ }
+ open_sockets.clear();
+}
+
+void init(){
+ nlInit();
+ nlSelectNetwork( NL_IP );
+ nlEnable( NL_BLOCKING_IO );
+ // nlDisable( NL_BLOCKING_IO );
+}
+
+void blocking( bool b ){
+ if ( b ){
+ nlEnable( NL_BLOCKING_IO );
+ } else {
+ nlDisable( NL_BLOCKING_IO );
+ }
+}
+
+void listen( Socket s ) throw( NetworkException ){
+ if ( nlListen( s ) == NL_FALSE ){
+ throw CannotListenException( string(nlGetSystemErrorStr( nlGetSystemError() )) );
+ }
+}
+
+Socket accept( Socket s ) throw( NetworkException ){
+ Socket connection = nlAcceptConnection( s );
+ if ( connection == NL_INVALID ){
+ /*
+ if ( nlGetError() == NL_NO_PENDING ){
+ error = NO_CONNECTIONS_PENDING;
+ } else {
+ error = NETWORK_ERROR;
+ }
+ return s;
+ */
+ if ( nlGetError() == NL_NO_PENDING ){
+ throw NoConnectionsPendingException();
+ }
+ throw NetworkException("Could not accept connection");
+ }
+ open_sockets.push_back( connection );
+ return connection;
+}
+
+void shutdown(){
+ nlShutdown();
+}
+
+#endif
+
+}
diff --git a/util/network/network.h b/util/network/network.h
new file mode 100644
index 00000000..60fc8122
--- /dev/null
+++ b/util/network/network.h
@@ -0,0 +1,140 @@
+#ifndef _paintown_network_h
+#define _paintown_network_h
+
+#include <stdint.h>
+#ifdef HAVE_NETWORKING
+#include "hawknl/nl.h"
+#endif
+#include <string>
+#include <vector>
+#include <exception>
+
+namespace Network{
+
+#ifdef HAVE_NETWORKING
+typedef NLsocket Socket;
+#else
+typedef int Socket;
+#endif
+
+const int NO_CONNECTIONS_PENDING = 1;
+const int NETWORK_ERROR = 2;
+
+const int DATA_SIZE = 16;
+
+class NetworkException: public std::exception{
+public:
+ NetworkException( const std::string message = "" ):std::exception(),message(message){}
+
+ inline const std::string getMessage() const {
+ return message;
+ }
+
+ ~NetworkException() throw();
+
+protected:
+ inline void setMessage( const std::string & m ){
+ this->message = m;
+ }
+
+private:
+ std::string message;
+};
+
+class NoConnectionsPendingException: public NetworkException{
+public:
+ NoConnectionsPendingException(const std::string message = ""):
+ NetworkException(message){
+ }
+};
+
+class MessageEnd: public NetworkException {
+public:
+ MessageEnd();
+};
+
+class InvalidPortException: public NetworkException{
+public:
+ InvalidPortException( int port, const std::string message = "" );
+};
+
+class CannotListenException: public NetworkException{
+public:
+ CannotListenException( const std::string message = "" ):
+ NetworkException( message ){
+ }
+};
+
+struct Message{
+ Message();
+ Message( const Message & m );
+ Message( Socket socket );
+
+ uint32_t id;
+ uint8_t data[ DATA_SIZE ];
+ uint8_t * position;
+
+ Message & operator=( const Message & m );
+ Message & operator<<( int x );
+ Message & operator<<( unsigned int x );
+ Message & operator<<( std::string p );
+ Message & operator>>( int & x );
+ Message & operator>>( unsigned int & x );
+ Message & operator>>(std::string & out);
+
+ int size() const;
+ uint8_t * dump( uint8_t * buffer ) const;
+
+ void send( Socket socket ) const;
+ void reset();
+
+ std::string path;
+
+ /* time in microseconds
+ * a 64-bit variable can hold
+ * us ms s m h d
+ * years = 2**64.0 / (1000 * 1000 * 60 * 60 * 24 * 365)
+ * years = 584942.417355072
+ * worth of microseconds
+ */
+ uint64_t timestamp;
+ Socket readFrom;
+};
+
+/*
+template <class M>
+int totalSize(const std::vector<M> & messages);
+
+template <class M>
+void dump(const std::vector<M> & messages, uint8_t * buffer );
+*/
+
+#ifdef HAVE_NETWORKING
+void sendAllMessages(const std::vector<Message> & messages, Socket socket);
+void sendAllMessages(const std::vector<Message*> & messages, Socket socket);
+
+int16_t read16( Socket socket );
+int32_t read32( Socket socket );
+void send16( Socket socket, int16_t length );
+std::string readStr( Socket socket, const uint16_t length );
+void sendStr( Socket socket, const std::string & str );
+void sendBytes( Socket socket, const uint8_t * data, int length );
+void readBytes( Socket socket, uint8_t * data, int length );
+void init();
+void shutdown();
+void blocking( bool b );
+
+void listen( Socket s ) throw( NetworkException );
+Socket accept( Socket s ) throw( NetworkException );
+
+Socket open( int port ) throw( InvalidPortException );
+Socket connect( std::string server, int port ) throw ( NetworkException );
+void close( Socket );
+void closeAll();
+
+static std::vector< Socket > open_sockets;
+#endif
+
+}
+
+#endif

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 11:37 AM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68813
Default Alt Text
(309 KB)

Event Timeline