#include "windows.h"
#include "types.h"
#include "winsock.h"
#include "wsasync.h"

#ifdef UNDER_CE
#include <ceconfig.h>
#endif

DWORD CopyHostEnt(PHOSTENT lpWinsockHostEnt, PHOSTENT lpHostEnt,
        LPDWORD lpdwHostEntBufferSize);

#define ProxyDbgAssert(x) ASSERT(x)
// If Count is not already aligned, then
// round Count up to an even multiple of "Pow2".  "Pow2" must be a power of 2.
//
// DWORD
// ROUND_UP_COUNT(
//     IN DWORD Count,
//     IN DWORD Pow2
//     );
#define ROUND_UP_COUNT(Count,Pow2) \
        ( ((Count)+(Pow2)-1) & (~((Pow2)-1)) )
#define ALIGN_DWORD             4

#ifdef DEBUG

DBGPARAM dpCurSettings = {
    TEXT("WSASYNC"), {
    TEXT("Init"),     TEXT("HostName"),TEXT("Undefined"),TEXT("Undefined"),
    TEXT("Recv"),TEXT("Send"),TEXT("Undefined"),TEXT("Undefined"),
    TEXT("Undefined"),TEXT("Undefined"),TEXT("Interface"),TEXT("Misc"),
    TEXT("Alloc"),    TEXT("Function"), TEXT("Warning"),  TEXT("Error") },
    0x0000c000
};

#define ZONE_INIT		DEBUGZONE(0)		// 0x0001
#define ZONE_HNAME		DEBUGZONE(1)		// 0x0002
//#define ZONE_???		DEBUGZONE(2)		// 0x0004
//#define ZONE_???		DEBUGZONE(3)		// 0x0008
#define ZONE_RECV		DEBUGZONE(4)		// 0x0010
#define ZONE_SEND		DEBUGZONE(5)		// 0x0020
#define ZONE_SELECT		DEBUGZONE(6)		// 0x0040
#define ZONE_CLOSE		DEBUGZONE(7)		// 0x0080
//#define ZONE_???		DEBUGZONE(8)		// 0x0100
#define ZONE_MSG		DEBUGZONE(9)		// 0x0200
#define ZONE_INTERFACE	DEBUGZONE(10)		// 0x0400
#define ZONE_MISC		DEBUGZONE(11)		// 0x0800
#define ZONE_ALLOC		DEBUGZONE(12)		// 0x1000
#define ZONE_FUNCTION	DEBUGZONE(13)		// 0x2000
#define ZONE_WARN		DEBUGZONE(14)		// 0x4000
#define ZONE_ERROR		DEBUGZONE(15)		// 0x8000

#endif


typedef struct GetNames {
	struct GetNames	*pNext;
	HANDLE			hThread;
	HWND			hWnd;
	uint			wMsg;
	char			*pBuf;
    DWORD           dwBufLen;
	char			*pName;
	DWORD			Status;
} GetNames;

GetNames			*v_pNameList;
CRITICAL_SECTION	v_NameListCS;
BOOL                v_fNameListInit = FALSE;

#define MAXALIASES		15		// We only support 5 aliases
#define AVG_HOST_LEN	40		// To calculate buff space
#define MAXADDRS		15		// Max of 5 IP addrs

typedef struct FULL_HOSTENT {
	HOSTENT	hostent;
	PSTR	host_aliases[MAXALIASES+1];
	char	hostbuf[(MAXALIASES+1)*AVG_HOST_LEN];
	PSTR	h_addr_ptrs[MAXADDRS + 1];
	uchar	hostaddr[MAXADDRS*4];
} FULL_HOSTENT;


GetNames **_FindName(HANDLE hThread) {
	GetNames	**ppName;

	ppName = &v_pNameList;
	while (*ppName && hThread != (*ppName)->hThread)
		ppName = &(*ppName)->pNext;

	return ppName;

}	// _FindName()

// HANDLE CreateThread(NULL, 0, Addr, pParam, NULL, ThreadId);
// BOOL PostMessage(hWnd, wMsg, wParam, lParam);


void CallGetHostByName(DWORD Name) {
	GetNames		**ppName, *pName = (GetNames *)Name;
	HOSTENT			*pHostent;
#if 0
	FULL_HOSTENT	*pFull;
	int				cLen, i;
	char			*p;
#endif
	DWORD			lParam;

	EnterCriticalSection(&v_NameListCS);
	// put it in list of pending items
	pName->pNext = v_pNameList;
	v_pNameList = pName;
	LeaveCriticalSection(&v_NameListCS);

	pHostent = gethostbyname(pName->pName);

	DEBUGMSG(ZONE_HNAME, (TEXT("gethostbyname returned %x\r\n"), pHostent));
	// take this task out of the pending items list
	EnterCriticalSection(&v_NameListCS);
	ppName = _FindName(pName->hThread);
	ASSERT(*ppName);
	ASSERT(*ppName == pName);
	*ppName = pName->pNext;
	pName->pNext = NULL;
	LeaveCriticalSection(&v_NameListCS);

	if (pName->Status != 0xffffffff) {
		if (pHostent) {
#if 0
			lParam = 0;
			pFull = (FULL_HOSTENT *)pName->pBuf;
			memcpy(pFull, pHostent, sizeof(FULL_HOSTENT));
			// now change the pointers to point to the correct places
			pFull->hostent.h_name = pFull->hostbuf;
			cLen = strlen(pFull->hostbuf) + 1;

			p = pFull->hostbuf + cLen;

			// do the aliases
			pFull->hostent.h_aliases = pFull->host_aliases;
			i = 0;
			while (pHostent->h_aliases[i]) {
				p += strlen(pHostent->h_aliases[i]) + 1;
				pFull->hostent.h_aliases[i++] = p;
			}
			// h_addrtype & h_length should have been copied with memcpy


			// do the h_addr_list
			pFull->hostent.h_addr_list = pFull->h_addr_ptrs;
            while(pHostent->h_addr_list[i]) {
                pFull->h_adddr_ptrs[i] =
            }

            p = pFull->hostaddr;
			i = 0;
			while (pHostent->h_addr_list[i]) {
				pFull->h_addr_ptrs[i] = p;
				(int *)p = *(int *)pHostent->h_addr_list[i++];
				p += 4;
			}
#endif
            lParam = CopyHostEnt(pHostent, (PHOSTENT)pName->pBuf,
                    &pName->dwBufLen);
			lParam <<= 16;
            lParam += pName->dwBufLen;
        } else {	// if (pHostent)
			// we must have some error condition
			lParam = GetLastError();
			lParam <<= 16;
    		lParam += sizeof(FULL_HOSTENT);
		}
		// BUGBUG: we don't retry on failure
		PostMessage(pName->hWnd, pName->wMsg, (WPARAM)pName->hThread, lParam);
	}	// if (pName->Status)

	LocalFree(pName->pName);
	LocalFree(pName);

}	// CallGetHostByName()


HANDLE WSAAsyncGetHostByName(HWND hWnd, unsigned wMsg, const char FAR *name,
							 char FAR * buf, int buflen) {
	HANDLE		hThread;
	DWORD		ThreadId;
	GetNames	*pName;
	DWORD		Status = 0;
    int         cc;

	if (buflen < sizeof(HOSTENT)) {
		Status = WSAENOBUFS;
	} else if (pName = LocalAlloc(LPTR, sizeof(*pName))) {
		pName->hWnd = hWnd;
		pName->wMsg = wMsg;
		pName->pBuf = buf;
        pName->dwBufLen = (DWORD)buflen;
        cc = strlen(name) + 1;
        if (pName->pName = LocalAlloc(LPTR, cc)) {
            memcpy(pName->pName, name, cc);
		    pName->Status = 0;
            if (!v_fNameListInit) {
		        InitializeCriticalSection(&v_NameListCS);
                v_fNameListInit = TRUE;
            }
		    EnterCriticalSection(&v_NameListCS);
		    pName->hThread = hThread = CreateThread(NULL, 0,
			    (LPTHREAD_START_ROUTINE)CallGetHostByName, pName, 0, &ThreadId);

		    LeaveCriticalSection(&v_NameListCS);
		    CloseHandle(hThread);
        } else {
            LocalFree(pName);
		    Status = WSAENOBUFS;
        }
	} else {
		Status = WSAENOBUFS;
	}

	if (Status) {
		SetLastError(Status);
		return (HANDLE)0;
	} else
		return (HANDLE)hThread;
}	// WSAASyncGetHostByName()


int WSACancelAsyncRequest (HANDLE hAsyncTaskHandle) {
	GetNames	**ppName;
	int			Status;

	EnterCriticalSection(&v_NameListCS);
	ppName = _FindName(hAsyncTaskHandle);
	if (*ppName) {
		(*ppName)->Status = 0xffffffff;
		LeaveCriticalSection(&v_NameListCS);
		Status = 0;
	} else {
		LeaveCriticalSection(&v_NameListCS);
		Status = SOCKET_ERROR;
		SetLastError(WSAEINVAL);
	}

	return Status;
}	// WSACancelAsyncRequest()


typedef int (*WSRecvFn)(SOCKET, char *, int, int);
typedef int (*WSSendFn)(SOCKET, const char *, int, int);
typedef int (*WSCloseFn)(SOCKET);

WSRecvFn v_pRecv;
WSSendFn v_pSend;
WSCloseFn v_pClose;
SOCKADDR_IN	SockAddr;

#ifndef IP_LOOPBACK
#define IP_LOOPBACK	0x100007f
#endif

static fd_set	ReadSet, WriteSet, ExcSet;
static int		v_fDone;
static SOCKET	v_Sock= INVALID_SOCKET;
static SOCKET	v_WakeSock;
static SOCKET	v_SendSock;
static int		v_SelEvents;
static int		v_Disabled;
static HWND		v_hWnd;
static int		v_wMsg;
static int		v_fAlready;	// implicitly set to FALSE

CRITICAL_SECTION	v_EventCS;

void SelectWorker(DWORD Sock);

int WSAAsyncSelect (SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent) {
	static int		fInit = FALSE;
	HINSTANCE		hinst;
	HANDLE			hThread;
	DWORD			ThreadId;
	int				True = 1;
    int             len;

	if (! fInit) {
		fInit = TRUE;
		InitializeCriticalSection(&v_EventCS);
		if (hinst = LoadLibrary(TEXT("winsock.dll"))) {
			v_pRecv = (WSRecvFn)GetProcAddressW(hinst, TEXT("recv"));
			v_pSend = (WSSendFn)GetProcAddressW(hinst, TEXT("send"));
			v_pClose = (WSCloseFn)GetProcAddressW(hinst, TEXT("closesocket"));
			if (! (v_pRecv && v_pSend && v_pClose)) {
				DEBUGMSG(ZONE_WARN | ZONE_ERROR,
					(TEXT("Couldn't get ProcAddr of winsock recv/send\r\n")));
				SetLastError(WSAENOBUFS);
				return SOCKET_ERROR;
			}
		} else {
			DEBUGMSG(ZONE_WARN | ZONE_ERROR,
					(TEXT("Couldn't LoadLibrary winsock.dll\r\n")));
			SetLastError(WSAENOBUFS);
			return SOCKET_ERROR;
		}
		// now WakeSock and SendSock initialized at init time only
		v_WakeSock = socket(AF_INET, SOCK_DGRAM, 0);
		if (INVALID_SOCKET == v_WakeSock) {
			DEBUGMSG(ZONE_WARN|ZONE_ERROR,
				(TEXT("Can't create dgram socket\r\n")));
			SetLastError(WSAENOBUFS);
			return SOCKET_ERROR;
		}
		memset ((char *)&SockAddr, 0, sizeof(SockAddr));
		SockAddr.sin_family = AF_INET;
		SockAddr.sin_port = 0;
		SockAddr.sin_addr.S_un.S_addr = IP_LOOPBACK;
		if (SOCKET_ERROR == bind(v_WakeSock, (SOCKADDR *)&SockAddr,
			sizeof(SockAddr))) {
			DEBUGMSG(ZONE_WARN|ZONE_ERROR, (TEXT("Can't bind WakeSock\r\n")));
			return SOCKET_ERROR;
		}

		v_SendSock = socket(AF_INET, SOCK_DGRAM, 0);
		if (INVALID_SOCKET == v_SendSock) {
			DEBUGMSG(ZONE_WARN|ZONE_ERROR,
				(TEXT("Can't create send socket\r\n")));
			v_pClose(v_WakeSock);
			SetLastError(WSAENOBUFS);
			return SOCKET_ERROR;
		}
        len = sizeof(SockAddr);
	    getsockname (v_WakeSock, (SOCKADDR *)&SockAddr, &len);
		connect(v_SendSock, (SOCKADDR *)&SockAddr, sizeof(SockAddr));
	}	// if (! fInit)

	EnterCriticalSection(&v_EventCS);
	if (! lEvent) {
		v_fDone = TRUE;
		LeaveCriticalSection(&v_EventCS);
		return 0;
	}

	if (v_fAlready) {
		LeaveCriticalSection(&v_EventCS);
		return 0;
	} else {
		v_fAlready = TRUE;
		v_fDone = FALSE;
		v_hWnd = hWnd;
		v_wMsg = wMsg;
		v_SelEvents = lEvent;
		ASSERT(INVALID_SOCKET == v_Sock);
		v_Sock = s;
		v_Disabled = 0;
		LeaveCriticalSection(&v_EventCS);

		// set socket to non-blocking
		if (SOCKET_ERROR == ioctlsocket(s, FIONBIO, &True)) {
			DEBUGMSG(ZONE_WARN, (TEXT("ioctlsocket FIONBIO failed w/ %d\r\n"),
				GetLastError()));
		}

		hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SelectWorker,
			(void *)s, 0, &ThreadId);
		CloseHandle(hThread);
	}
	return 0;
}

void SelectWorker(DWORD Sock) {
	SOCKET	s = (SOCKET) Sock;
	char	c;
	DWORD	lParam = 0;
	int		Status;
#ifdef OS_WINCE
	TIMEVAL tv = {0, 25000};
#endif // OS_WINCE
	

	while (2) {
		FD_ZERO(&ReadSet);
		FD_ZERO(&WriteSet);
		FD_ZERO(&ExcSet);
		if (INVALID_SOCKET != v_WakeSock) {
			FD_SET(v_WakeSock, &ReadSet);
		}
		EnterCriticalSection(&v_EventCS);
		if (v_fDone) {	// do this here b/c of CS
			v_fAlready = FALSE;
			// LeaveCriticalSection(&v_EventCS);
			break;
		}

		if (v_SelEvents & ~v_Disabled & (FD_WRITE | FD_CONNECT)) {
			FD_SET(s, &WriteSet);
			DEBUGMSG(ZONE_MSG, (TEXT("W\r\n")));
		}
		if (v_SelEvents & ~v_Disabled & FD_READ) {
			FD_SET(s, &ReadSet);
			DEBUGMSG(ZONE_MSG, (TEXT("R\r\n")));
		}
		//FD_SET(s, &ExcSet);

		LeaveCriticalSection(&v_EventCS);
		DEBUGMSG(ZONE_SELECT, (TEXT("calling select\r\n")));

#ifdef OS_WINCE
		/* When select(...) is called with a NULL timeval parameter,
		   it does not return after closesocket(...) is called on
		   that socket.  To work around that behavior, use a time-
		   out on the call to select(...) (and take advantage of
		   the while(2) wrapping this code-block. */

        // This was only made for HPCs, WBT was always fine using the old way,
        // so we're going to keep it the same.        
        if (g_CEConfig != CE_CONFIG_WBT)
        {
    		Status = select(0, &ReadSet, &WriteSet, NULL, &tv);
        }
        else
        {
    		Status = select(0, &ReadSet, &WriteSet, NULL, NULL);
        }
#else // OS_WINCE
		Status = select(0, &ReadSet, &WriteSet, NULL, NULL);
#endif // OS_WINCE

		

		if (SOCKET_ERROR == Status) {
			//v_fDone = TRUE;
			Status = GetLastError();
			DEBUGMSG(ZONE_WARN|ZONE_SELECT,
				(TEXT("Select returned error: %d \r\n"), Status));
		} else {
			if (FD_ISSET(v_WakeSock, &ReadSet)) {
				v_pRecv(v_WakeSock, &c, 1, 0);
			}
			EnterCriticalSection(&v_EventCS);

			if (FD_ISSET(s, &WriteSet)) {
				// we need to report connect events only once
				if (v_SelEvents & ~v_Disabled & FD_CONNECT) {
					v_Disabled |= FD_CONNECT;
					lParam = FD_CONNECT;
					DEBUGMSG(ZONE_MSG, (TEXT("p-C\r\n")));
					PostMessage(v_hWnd, v_wMsg, (WPARAM)s, lParam);
				}
				if (v_SelEvents & ~v_Disabled & FD_WRITE) {
					v_Disabled |= FD_WRITE;
					lParam = FD_WRITE;
					DEBUGMSG(ZONE_MSG, (TEXT("p-W\r\n")));
					PostMessage(v_hWnd, v_wMsg, (WPARAM)s, lParam);
				}
			}
			if (FD_ISSET(s, &ReadSet)) {
				v_Disabled |= FD_READ;
				lParam = FD_READ;
				DEBUGMSG(ZONE_MSG, (TEXT("p-R\r\n")));
				PostMessage(v_hWnd, v_wMsg, (WPARAM)s, lParam);
			}
			if (FD_ISSET(s, &ExcSet)) {
				DEBUGMSG(ZONE_WARN, (TEXT("Selects ExcSet is set!!\r\n")));
			}
			LeaveCriticalSection(&v_EventCS);
		}	// else SOCKET_ERROR == Status
	}
	// note we have the CS here!!!
	v_Sock = INVALID_SOCKET;
	v_hWnd = NULL;
	LeaveCriticalSection(&v_EventCS);

	return;

}	// SelectWorker()


int recv(SOCKET s, char *buf, int len, int flags) {
	char	c = (char)7;
	int		Status;

	DEBUGMSG(ZONE_RECV, (TEXT("+recv\r\n")));
	Status = v_pRecv(s, buf, len, flags);

	EnterCriticalSection(&v_EventCS);
	if (v_Sock != INVALID_SOCKET && v_Sock == s) {
		// BUGBUG: should we check for errors as well?
		if (! Status) {	// recv'd 0 bytes
			DEBUGMSG(ZONE_MSG, (TEXT("p-Close\r\n")));
			PostMessage(v_hWnd, v_wMsg, (WPARAM)s, FD_CLOSE);
			// after this we don't want to re-enable FD_READ's
		} else if (v_Disabled & FD_READ) {
			v_Disabled &= ~FD_READ;
			v_pSend(v_SendSock, &c, 1, 0);
		}
	}
	LeaveCriticalSection(&v_EventCS);

	DEBUGMSG(ZONE_RECV, (TEXT("-recv\r\n")));
	return Status;

}	// recv

int send(SOCKET s, const char *buf, int len, int flags) {
	char	c = (char)8;
	int		Status;

	DEBUGMSG(ZONE_SEND, (TEXT("+send\r\n")));
	Status = v_pSend(s, buf, len, flags);

	EnterCriticalSection(&v_EventCS);
	if (v_Sock != INVALID_SOCKET && v_Sock == s) {
		// BUGBUG: should we check for errors??
		if (v_Disabled & FD_WRITE) {
			v_Disabled &= ~FD_WRITE;
			v_pSend(v_SendSock, &c, 1, 0);
		}
	}
	LeaveCriticalSection(&v_EventCS);

	DEBUGMSG(ZONE_SEND, (TEXT("-send\r\n")));
	return Status;

}	// send()

int closesocket(SOCKET s) {
	int	Status;

	DEBUGMSG(ZONE_CLOSE, (TEXT("+close\r\n")));
	Status = v_pClose(s);

	EnterCriticalSection(&v_EventCS);
	if (v_Sock != INVALID_SOCKET && v_Sock == s) {
		v_fDone = TRUE;
	}
	LeaveCriticalSection(&v_EventCS);

	DEBUGMSG(ZONE_CLOSE, (TEXT("-close\r\n")));
	return Status;
}	// closesocket()


BOOL __stdcall
dllentry (
    HANDLE  hinstDLL,
    DWORD   Op,
    LPVOID  lpvReserved
    )
{
	switch (Op) {
	case DLL_PROCESS_ATTACH :
		DEBUGREGISTER(hinstDLL);
		DEBUGMSG (ZONE_INIT, (TEXT(" CXPORT:dllentry ProcessAttach\r\n")));
		break;
	case DLL_PROCESS_DETACH :
		break;
	default :
		break;
	}
	return TRUE;
}

DWORD
CopyHostEnt(
    PHOSTENT lpWinsockHostEnt,
    PHOSTENT lpHostEnt,
    LPDWORD lpdwHostEntBufferSize
    )
/*++

Arguments:

Return Value:

    Windows Error Code.

--*/
{
    DWORD dwSize;
    LPSTR *lpAliasNames;
    LPSTR *lpDestAliasNames;
    LPSTR *lpAddrList;
    LPSTR *lpDestAddrList;
    LPBYTE lpNextVariable;
    LPBYTE lpEndBuffer;
    DWORD dwNumAliasNames = 0;
    DWORD dwNumAddresses = 0;
    DWORD dwDnsNameLen;

    //
    // compute the size required.
    //

    dwSize = sizeof(HOSTENT);

    dwDnsNameLen =
        ROUND_UP_COUNT(
            (strlen(lpWinsockHostEnt->h_name) + sizeof(CHAR)),
            ALIGN_DWORD );

    dwSize += dwDnsNameLen;

    lpAliasNames = lpWinsockHostEnt->h_aliases;
    while( *lpAliasNames != NULL ) {

        dwSize += ROUND_UP_COUNT(
            (strlen(*lpAliasNames) + sizeof(CHAR)),
            ALIGN_DWORD );

        dwSize += sizeof(LPSTR);
        dwNumAliasNames++;
        lpAliasNames++;
    }

    dwSize += sizeof(LPSTR);

    lpAddrList = lpWinsockHostEnt->h_addr_list;

    while( *lpAddrList != NULL ) {
        dwSize += sizeof(DWORD);
        dwSize += sizeof(LPSTR);
        dwNumAddresses++;
        lpAddrList++;
    }

    dwSize += sizeof(LPSTR);

    if( dwSize > *lpdwHostEntBufferSize ) {
        *lpdwHostEntBufferSize = dwSize;
        return( WSAENOBUFS );
    }

    //
    // copy data.
    //

    lpNextVariable =  (LPBYTE)lpHostEnt + sizeof(HOSTENT);
    lpEndBuffer = (LPBYTE)lpHostEnt + dwSize;

    //
    // copy fixed part.
    //

    lpHostEnt->h_addrtype = lpWinsockHostEnt->h_addrtype;
    lpHostEnt->h_length = lpWinsockHostEnt->h_length;

    //
    // copy variable parts.
    //

    lpHostEnt->h_name = (LPSTR)lpNextVariable;

    strcpy( lpHostEnt->h_name, lpWinsockHostEnt->h_name );

    lpNextVariable += dwDnsNameLen;
    ProxyDbgAssert( lpNextVariable < lpEndBuffer);


    lpHostEnt->h_aliases = (LPSTR *)lpNextVariable;
    lpNextVariable += (dwNumAliasNames + 1) * sizeof(LPSTR);
    ProxyDbgAssert( lpNextVariable < lpEndBuffer);

    lpAliasNames = lpWinsockHostEnt->h_aliases;
    lpDestAliasNames = lpHostEnt->h_aliases;

    while( *lpAliasNames != NULL ) {

        *lpDestAliasNames = (LPSTR)lpNextVariable;
        strcpy( *lpDestAliasNames, *lpAliasNames );

        lpNextVariable += ROUND_UP_COUNT(
            (strlen(*lpAliasNames) + sizeof(CHAR)),
            ALIGN_DWORD );

        ProxyDbgAssert( lpNextVariable < lpEndBuffer);

        lpDestAliasNames++;
        lpAliasNames++;
    }

    *lpDestAliasNames = NULL;

    lpHostEnt->h_addr_list = (LPSTR *)lpNextVariable;
    lpNextVariable += (dwNumAddresses + 1) * sizeof(LPSTR);
    ProxyDbgAssert( lpNextVariable < lpEndBuffer);

    lpAddrList = lpWinsockHostEnt->h_addr_list;
    lpDestAddrList = lpHostEnt->h_addr_list;

    while( *lpAddrList != NULL ) {

        *lpDestAddrList = (LPSTR)lpNextVariable;
        *(LPDWORD)(*lpDestAddrList) = *(LPDWORD)(*lpAddrList);

        lpNextVariable += sizeof(DWORD);
        ProxyDbgAssert( lpNextVariable <= lpEndBuffer);

        lpDestAddrList++;
        lpAddrList++;
    }

    *lpDestAddrList = NULL;

    return( ERROR_SUCCESS );
}


// ----------------------------------------------------------------
//
// 	The Windows Sockets WSAAsyncGetHostByName function gets host
// 	information corresponding to a host name asynchronously.
//
// 	HANDLE WSAAsyncGetHostByName ( HWND hWnd, unsigned int wMsg, const
// 	char FAR * name, char FAR * buf, int buflen );
//
//	Parameters
//
//	hWnd
//
// 	[in] The handle of the window that will receive a message when the
// 	asynchronous request completes.
//
// 	wMsg
//
// 	[in] The message to be received when the asynchronous request
// 	completes.
//
// 	name
//
// 	[in] A pointer to the null-terminated name of the host.
//
// 	buf
//
// 	[out] A pointer to the data area to receive the HOSTENT data. It must
// 	be larger than the size of a HOSTENT structure because the supplied
// 	data area is used by Windows Sockets to contain not only a HOSTENT
// 	structure but any and all of the data referenced by members of the
// 	HOSTENT structure. A buffer of MAXGETHOSTSTRUCT bytes is recommended.
//
// 	buflen
//
// 	[in] The size of data area the buf parameter.
//
// Remarks
//
// 	This function is an asynchronous version of gethostbyname, and is
// 	used to retrieve host name and address information corresponding to a
// 	host name. Windows Sockets initiates the operation and returns to the
// 	caller immediately, passing back an opaque "asynchronous task handle"
// 	that whichthe application can use to identify the operation. When the
// 	operation is completed, the results (if any) are copied into the
// 	buffer provided by the caller and a message is sent to the
// 	application's window.
//
// 	When the asynchronous operation is complete the application's window
// 	hWnd receives message wMsg. The wParam parameter contains the
// 	asynchronous task handle as returned by the original function call.
// 	The high 16 bits of lParam contain any error code. The error code can
// 	be any error as defined in WINSOCK2.H. An error code of zero
// 	indicates successful completion of the asynchronous operation. On
// 	successful completion, the buffer supplied to the original function
// 	call contains a HOSTENT structure. To access the elements of this
// 	structure, the original buffer address should be cast to a HOSTENT
// 	structure pointer and accessed as appropriate.
//
// 	If the error code is WSAENOBUFS, the size of the buffer specified by
// 	buflen in the original call was too small to contain all the
// 	resulting information. In this case, the low 16 bits of lParam
// 	contain the size of buffer required to supply all the requisite
// 	information. If the application decides that the partial data is
// 	inadequate, it can reissue the WSAAsyncGetHostByAddr function call
// 	with a buffer large enough to receive all the desired information
// 	(that is, no smaller than the low 16 bits of lParam).
//
// 	The buffer supplied to this function is used by Windows Sockets to
// 	construct a HOSTENT structure together with the contents of data
// 	areas referenced by members of the same HOSTENT structure. To avoid
// 	the WSAENOBUFS error, the application should provide a buffer of at
// 	least MAXGETHOSTSTRUCT bytes (as defined in WINSOCK2.H).
//
// 	The error code and buffer length should be extracted from the lParam
// 	using the macros WSAGETASYNCERROR and WSAGETASYNCBUFLEN, defined in
// 	WINSOCK2.H as:
//
// 	#define WSAGETASYNCERROR(lParam) HIWORD(lParam) #define
// 	WSAGETASYNCBUFLEN(lParam) LOWORD(lParam) The use of these macros will
// 	maximize the portability of the source code for the application.
//
// 	WSAAsyncGetHostByName is guaranteed to resolve the string returned by
// 	a successful call to gethostname.
//
// Return Values
//
// 	The return value specifies whether or not the asynchronous operation
// 	was successfully initiated. Note that it does not imply success or
// 	failure of the operation itself.
//
// 	If the operation was successfully initiated, WSAAsyncGetHostByName
// 	returns a nonzero value of type HANDLE that is the asynchronous task
// 	handle (not to be confused with a Windows HTASK) for the request.
// 	This value can be used in two ways. It can be used to cancel the
// 	operation using WSACancelAsyncRequest. It can also be used to match
// 	up asynchronous operations and completion messages by examining the
// 	wParam message parameter.
//
// 	If the asynchronous operation could not be initiated,
// 	WSAAsyncGetHostByName returns a zero value, and a specific error
// 	number can be retrieved by calling WSAGetLastError.
//
// Error Codes
//
// 	The following error codes can be set when an application window
// 	receives a message. As described above, they can be extracted from
// 	the lParam in the reply message using the WSAGETASYNCERROR macro.
//
// 	WSAENETDOWN The network subsystem has failed.
//
// 	WSAENOBUFS Insufficient buffer space is available.
//
// 	WSAEFAULT name or buf is not in a valid part of the process address
// 	space.
//
// 	WSAHOST_NOT_FOUND Authoritative Answer Host not found.
//
// 	WSATRY_AGAIN Non-Authoritative Host not found, or SERVERFAIL.
//
// 	WSANO_RECOVERY Nonrecoverable errors, FORMERR, REFUSED, NOTIMP.
//
// 	WSANO_DATA Valid name, no data record of requested type.
//
// 	The following errors can occur at the time of the function call, and
// 	indicate that the asynchronous operation could not be initiated.
//
// 	WSANOTINITIALISED A successful WSAStartup must occur before using
// 	this function.
//
// 	WSAENETDOWN The network subsystem has failed.
//
// 	WSAEINPROGRESS A blocking Windows Sockets 1.1 call is in progress, or
// 	the service provider is still processing a callback function.
//
// 	WSAEWOULDBLOCK The asynchronous operation cannot be scheduled at this
// 	time due to resource or other constraints within the Windows Sockets
// 	implementation.
//
// ----------------------------------------------------------------


// 
// ----------------------------------------------------------------
//
// The Windows Sockets WSACancelAsyncRequest function cancels an
// incomplete asynchronous operation.
//
//    int WSACancelAsyncRequest (
//     HANDLE hAsyncTaskHandle
//    );
//
// Parameters
// 	hAsyncTaskHandle
// 	[in] Specifies the asynchronous operation to be canceled.
//
// Remarks
//    The WSACancelAsyncRequest function is used to cancel an asynchronous
//    operation that was initiated by one of the WSAAsyncGetXByY functions
//    such as WSAAsyncGetHostByName. The operation to be canceled is
//    identified by the hAsyncTaskHandle parameter, which should be set to
//    the asynchronous task handle as returned by the initiating
//    WSAAsyncGetXByY function.
//
// Return Values
// 	The value returned by WSACancelAsyncRequest is zero if the operation
// 	was successfully canceled. Otherwise, the value SOCKET_ERROR is
// 	returned, and a specific error number may be retrieved by calling
// 	WSAGetLastError.
//
// Comments
// 	An attempt to cancel an existing asynchronous WSAAsyncGetXByY
// 	operation can fail with an error code of WSAEALREADY for two reasons.
// 	First, the original operation has already completed and the
// 	application has dealt with the resultant message. Second, the
// 	original operation has already completed but the resultant message is
// 	still waiting in the application window queue.
//
// Note
// 	It is unclear whether the application can usefully distinguish
// 	between WSAEINVAL and WSAEALREADY, since in both cases the error
// 	indicates that there is no asynchronous operation in progress with
// 	the indicated handle. [Trivial exception: zero is always an invalid
// 	asynchronous task handle.] The Windows Sockets specification does not
// 	prescribe how a conformant Windows Sockets provider should
// 	distinguish between the two cases. For maximum portability, a Windows
// 	Sockets application should treat the two errors as equivalent.
//
//
// Error Codes
// 	WSANOTINITIALISED A successful WSAStartup must occur before using
// 	this function.
//
// 	WSAENETDOWN	The network subsystem has failed.
//
// 	WSAEINVAL Indicates that the specified asynchronous task handle was
// 	invalid
//
// 	WSAEINPROGRESS A blocking Windows Sockets 1.1 call is in progress, or
// 	the service provider is still processing a callback function.
//
// 	WSAEALREADY The asynchronous routine being canceled has already
// 	completed.
//
// ----------------------------------------------------------------


// ----------------------------------------------------------------
//
//
// The Windows Sockets WSAAsyncSelect function requests Windows message-based notification of network events for a socket.
//
// int WSAAsyncSelect (
//     SOCKET s,
//     HWND hWnd,
//     unsigned int wMsg,
//     long lEvent
//    );
//
// Parameters
// 	s
// 	[in] A descriptor identifying the socket for which event notification
// 	is required.
//
// 	hWnd
// 	[in] A handle identifying the window that should receive a message
// 	when a network event occurs.
//
// 	wMsg
// 	[in] The message to be received when a network event occurs.
//
// 	lEvent
// 	[in] A bitmask that specifies a combination of network events in
// 	which the application is interested.
//
// Remarks
// 	This function is used to request that the Windows Sockets DLL should
// 	send a message to the window hWnd whenever it detects any of the
// 	network events specified by the lEvent parameter. The message that
// 	should be sent is specified by the wMsg parameter. The socket for
// 	which notification is required is identified by s.
//
// 	This function automatically sets socket s to nonblocking mode,
// 	regardless of the value of lEvent. See ioctlsocket about how to set
// 	the nonoverlapped socket back to blocking mode.
//
// 	The lEvent parameter is constructed by or'ing any of the values
// 	specified in the following list.
//
// 	Value		Meaning
// 	FD_READ		Want to receive notification of readiness for reading
//
// 	FD_WRITE	Want to receive notification of readiness for writing
//
// 	FD_OOB		Want to receive notification of the arrival of
// 				out-of-band data
//
// 	FD_ACCEPT	Want to receive notification of incoming connections
//
// 	FD_CONNECT	Want to receive notification of completed connection
//
// 	FD_CLOSE	Want to receive notification of socket closure
//
// 	FD_QOS		Want to receive notification of socket Quality of Service
// 				(QOS) changes
//
// 	FD_GROUP_QOS Want to receive notification of socket group Quality of
// 				Service (QOS) changes
//
// 	Issuing a WSAAsyncSelect for a socket cancels any previous
// 	WSAAsyncSelect or WSAEventSelect for the same socket. For example, to
// 	receive notification for both reading and writing, the application
// 	must call WSAAsyncSelect with both FD_READ and FD_WRITE, as follows:
//
// 	rc = WSAAsyncSelect(s, hWnd, wMsg, FD_READ|FD_WRITE);
//
// 	It is not possible to specify different messages for different
// 	events. The following code will not work; the second call will cancel
// 	the effects of the first, and only FD_WRITE events will be reported
// 	with message wMsg2:
//
// 	rc = WSAAsyncSelect(s, hWnd, wMsg1, FD_READ);
// 	rc = WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE);
//
// 	To cancel all notification (that is, to indicate that Windows Sockets
// 	should send no further messages related to network events on the
// 	socket) lEvent should be set to zero.
//
// 	rc = WSAAsyncSelect(s, hWnd, 0, 0);
//
// 	Although in this instance WSAAsyncSelect immediately disables event
// 	message posting for the socket, it is possible that messages can be
// 	waiting in the application's message queue. The application must
// 	therefore be prepared to receive network event messages even after
// 	cancellation. Closing a socket with closesocket also cancels
// 	WSAAsyncSelect message sending, but the same caveat about messages in
// 	the queue prior to the closesocket still applies.
//
// 	Since an accept'ed socket has the same properties as the listening
// 	socket used to accept it, any WSAAsyncSelect events set for the
// 	listening socket apply to the accepted socket. For example, if a
// 	listening socket has WSAAsyncSelect events FD_ACCEPT, FD_READ, and
// 	FD_WRITE, then any socket accepted on that listening socket will also
// 	have FD_ACCEPT, FD_READ, and FD_WRITE events with the same wMsg value
// 	used for messages. If a different wMsg or events are desired, the
// 	application should call WSAAsyncSelect, passing the accepted socket
// 	and the desired new information.
//
// 	When one of the nominated network events occurs on the specified
// 	socket s, the application's window hWnd receives message wMsg. The
// 	wParam parameter identifies the socket on which a network event has
// 	occurred. The low word of lParam specifies the network event that has
// 	occurred. The high word of lParam contains any error code. The error
// 	code be any error as defined in WINSOCK2.H.  Note Upon receipt of an
// 	event notification message the WSAGetLastError function cannot be
// 	used to check the error value, because the error value returned can
// 	differ from the value in the high word of lParam.
//
// 	The error and event codes can be extracted from the lParam using the
// 	macros WSAGETSELECTERROR and WSAGETSELECTEVENT, defined in WINSOCK2.H
// 	as:
//
// 	#define WSAGETSELECTERROR(lParam)       HIWORD(lParam)
// 	#define WSAGETSELECTEVENT(lParam)       LOWORD(lParam)
//
// 	The use of these macros will maximize the portability of the source
// 	code for the application.
//
// 	The possible network event codes that can be returned are as follows:
//
// 	Value	Meaning
// 	 FD_READ Socket s ready for reading
//
// 	FD_WRITE Socket s ready for writing
//
// 	FD_OOB Out-of-band data ready for reading on socket s
//
// 	FD_ACCEPT Socket s ready for accepting a new incoming connection
//
// 	FD_CONNECT Connection initiated on socket s completed
//
// 	FD_CLOSE Connection identified by socket s has been closed
//
// 	FD_QOS Quality of Service associated with socket s has changed
//
// 	FD_GROUP_QOS Quality of Service associated with the socket group to
// 	which s belongs has changed
//
// Return Values
//
// 	The return value is zero if the application's declaration of interest
// 	in the network event set was successful. Otherwise, the value
// 	SOCKET_ERROR is returned, and a specific error number can be
// 	retrieved by calling WSAGetLastError.
//
// Comments
//
// 	Although WSAAsyncSelect can be called with interest in multiple
// 	events, the application window will receive a single message for each
// 	network event.
//
// 	As in the case of the select function, WSAAsyncSelect will frequently
// 	be used to determine when a data transfer operation (send or recv)
// 	can be issued with the expectation of immediate success.
// 	Nevertheless, a robust application must be prepared for the
// 	possibility that it can receive a message and issue a Windows Sockets
// 	2 call that returns WSAEWOULDBLOCK immediately. For example, the
// 	following sequence of events is possible:
//
// 	1. data arrives on socket s; Windows Sockets 2 posts WSAAsyncSelect
// 	message
//
// 	2. application processes some other message
//
// 	3. while processing, application issues an ioctlsocket(s,
// 	FIONREAD...) and notices that there is data ready to be read
//
// 	4. application issues a recv(s,...) to read the data
//
// 	5. application loops to process next message, eventually reaching the
// 	WSAAsyncSelect message indicating that data is ready to read
//
// 	6. application issues recv(s,...), which fails with the error
// 	WSAEWOULDBLOCK.
//
// 	Other sequences are possible.
//
// 	The Windows Sockets DLL will not continually flood an application
// 	with messages for a particular network event. Having successfully
// 	posted notification of a particular event to an application window,
// 	no further message(s) for that network event will be posted to the
// 	application window until the application makes the function call that
// 	implicitly re-enables notification of that network event.
//
// 	Event	Re-enabling function
//
// 	FD_READ recv, recvfrom, WSARecv, or WSARecvFrom
//
// 	FD_WRITE send, sendto, WSASend, or WSASendTo
//
// 	FD_OOB recv, recvfrom, WSARecv, or WSARecvFrom
//
// 	FD_ACCEPT accept or WSAAccept unless the error code is WSATRY_AGAIN
// 	indicating that the condition function returned CF_DEFER
//
// 	FD_CONNECT NONE
//
// 	FD_CLOSE NONE
//
// 	FD_QOS WSAIoctl with command SIO_GET_QOS
//
// 	FD_GROUP_QOS WSAIoctl with command SIO_GET_GROUP_QOS
//
// 	Any call to the re-enabling routine, even one that fails, results in
// 	re-enabling of message posting for the relevant event.
//
// 	For FD_READ, FD_OOB, and FD_ACCEPT events, message posting is
// 	"level-triggered." This means that if the re-enabling routine is
// 	called and the relevant condition is still met after the call, a
// 	WSAAsyncSelect message is posted to the application. This allows an
// 	application to be event-driven and not be concerned with the amount
// 	of data that arrives at any one time. Consider the following sequence:
//
// 	1. Network transport stack receives 100 bytes of data on socket s and
// 	causes Windows Sockets 2 to post an FD_READ message.
//
// 	2. The application issues recv( s, buffptr, 50, 0) to read 50 bytes.
//
// 	3. Another FD_READ message is posted since there is still data to be
// 	read.
//
// 	With these semantics, an application need not read all available data
// 	in response to an FD_READ messageľa single recv in response to each
// 	FD_READ message is appropriate. If an application issues multiple
// 	recv calls in response to a single FD_READ, it can receive multiple
// 	FD_READ messages. Such an application may need to disable FD_READ
// 	messages before starting the recv calls by calling WSAAsyncSelect
// 	with the FD_READ event not set.
//
// 	The FD_QOS and FD_GROUP_QOS events are considered edge triggered. A
// 	message will be posted exactly once when a QOS change occurs. Further
// 	messages will not be forthcoming until either the provider detects a
// 	further change in QOS or the application renegotiates the QOS for the
// 	socket.
//
// 	If any event has already happened when the application calls
// 	WSAAsyncSelect or when the re-enabling function is called, then a
// 	message is posted as appropriate. For example, consider the following
// 	sequence:
//
// 	1. an application calls listen,
//
// 	2. a connect request is received but not yet accepted,
//
// 	3. the application calls WSAAsyncSelect specifying that it wants to
// 	receive FD_ACCEPT messages for the socket. Due to the persistence of
// 	events, Windows Sockets 2 posts an FD_ACCEPT message immediately.
//
// 	The FD_WRITE event is handled slightly differently. An FD_WRITE
// 	message is posted when a socket is first connected with
// 	connect/WSAConnect (after FD_CONNECT, if also registered) or accepted
// 	with accept/WSAAccept, and then after a send operation fails with
// 	WSAEWOULDBLOCK and buffer space becomes available. Therefore, an
// 	application can assume that sends are possible starting from the
// 	first FD_WRITE message and lasting until a send returns
// 	WSAEWOULDBLOCK. After such a failure the application will be notified
// 	that sends are again possible with an FD_WRITE message.
//
// 	The FD_OOB event is used only when a socket is configured to receive
// 	out-of-band data separately. (See section Out-Of-Band data for a
// 	discussion of this topic.) If the socket is configured to receive
// 	out-of-band data in-line, the out-of-band (expedited) data is treated
// 	as normal data and the application should register an interest in,
// 	and will receive, FD_READ events, not FD_OOB events. An application
// 	may set or inspect the way in which out-of-band data is to be handled
// 	by using setsockopt or getsockopt for the SO_OOBINLINE option.
//
// 	The error code in an FD_CLOSE message indicates whether the socket
// 	close was graceful or abortive. If the error code is zero, then the
// 	close was graceful; if the error code is WSAECONNRESET, then the
// 	socket's virtual circuit was reset. This only applies to
// 	connection-oriented sockets such as SOCK_STREAM.
//
// 	The FD_CLOSE message is posted when a close indication is received
// 	for the virtual circuit corresponding to the socket. In TCP terms,
// 	this means that the FD_CLOSE is posted when the connection goes into
// 	the TIME WAIT or CLOSE WAIT states. This results from the remote end
// 	performing a shutdown on the send side or a closesocket. FD_CLOSE
// 	should only be posted after all data is read from a socket, but an
// 	application should check for remaining data upon receipt of FD_CLOSE
// 	to avoid any possibility of losing data.
//
// 	Please note your application will receive ONLY an FD_CLOSE message to
// 	indicate closure of a virtual circuit, and only when all the received
// 	data has been read if this is a graceful close. It will not receive
// 	an FD_READ message to indicate this condition.
//
// 	The FD_QOS or FD_GROUP_QOS message is posted when any field in the
// 	flow specification associated with socket s or the socket group that
// 	s belongs to has changed, respectively. Applications should use
// 	WSAIoctl with command SIO_GET_QOS or SIO_GET_GROUP_QOS to get the
// 	current QOS for socket s or for the socket group s belongs to,
// 	respectively.
//
// 	Here is a summary of events and conditions for each asynchronous
// 	notification message:
//
// 	FD_READ:
//
// 	1. when WSAAsyncSelect called, if there is data currently available
// 	to receive,
//
// 	2. when data arrives, if FD_READ not already posted,
//
// 	3. after recv or recvfrom called (with or without MSG_PEEK), if data
// 	is still available to receive.  Note when setsockopt SO_OOBINLINE is
// 	enabled "data" includes both normal data and out-of-band (OOB) data
// 	in the instances noted above.  FD_WRITE:
//
// 	1. when WSAAsyncSelect called, if a send or sendto is possible
//
// 	2. after connect or accept called, when connection established
//
// 	3. after send or sendto fail with WSAEWOULDBLOCK, when send or sendto
// 	are likely to succeed,
//
// 	4. after bind on a datagram socket.
//
// 	FD_OOB: Only valid when setsockopt SO_OOBINLINE is disabled (default).
//
// 	1. when WSAAsyncSelect called, if there is OOB data currently
// 	available to receive with the MSG_OOB flag,
//
// 	2. when OOB data arrives, if FD_OOB not already posted,
//
// 	3. after recv or recvfrom called with or without MSG_OOB flag, if OOB
// 	data is still available to receive.
//
// 	FD_ACCEPT:
//
// 	1. when WSAAsyncSelect called, if there is currently a connection
// 	request available to accept,
//
// 	2. when a connection request arrives, if FD_ACCEPT not already
// 	posted,
//
// 	3. after accept called, if there is another connection request
// 	available to accept.
//
// 	FD_CONNECT:
//
// 	1. when WSAAsyncSelect called, if there is currently a connection
// 	established,
//
// 	2. after connect called, when connection is established (even when
// 	connect succeeds immediately, as is typical with a datagram socket)
//
// 	FD_CLOSE: Only valid on connection-oriented sockets (for example,
// 	SOCK_STREAM) 1. when WSAAsyncSelect called, if socket connection has
// 	been closed,
//
// 	2. after remote system initiated graceful close, when no data
// 	currently available to receive (note: if data has been received and
// 	is waiting to be read when the remote system initiates a graceful
// 	close, the FD_CLOSE is not delivered until all pending data has been
// 	read),
//
// 	3. after local system initiates graceful close with shutdown and
// 	remote system has responded with "End of Data" notification (for
// 	example, TCP FIN), when no data currently available to receive,
//
// 	4. when remote system terminates connection (for example, sent TCP
// 	RST), and lParam will contain WSAECONNRESET error value.
//
//
// 	Note FD_CLOSE is not posted after closesocket is called.  FD_QOS:
//
// 	1. when WSAAsyncSelect called, if the QOS associated with the socket
// 	has been changed,
//
// 	2. after WSAIoctl with SIO_GET_QOS called, when the QOS is changed.
//
// 	FD_GROUP_QOS:
//
// 	1. when WSAAsyncSelect called, if the group QOS associated with the
// 	socket has been changed,
//
// 	2. after WSAIoctl with SIO_GET_GROUP_QOS called, when the group QOS
// 	is changed.  Error Codes
//
// 	WSANOTINITIALISED A successful WSAStartup must occur before using
// 	this function.
//
// 	WSAENETDOWN The network subsystem has failed.
//
// 	WSAEINVAL Indicates that one of the specified parameters was invalid
// 	such as the window handle not referring to an existing window, or the
// 	specified socket is in an invalid state.
//
// 	WSAEINPROGRESS A blocking Windows Sockets 1.1 call is in progress, or
// 	the service provider is still processing a callback function.
//
// 	WSAENOTSOCK The descriptor is not a socket.  Additional error codes
// 	may be set when an application window receives a message. This error
// 	code is extracted from the lParam in the reply message using the
// 	WSAGETSELECTERROR macro. Possible error codes for each network event
// 	are:
//
// 	Event: FD_CONNECT
//
// 	Error Code Meaning
//
// 	WSAEADDRINUSE The specified address is already in use.
//
// 	WSAEADDRNOTAVAIL The specified address is not available from the
// 	local machine.
//
// 	WSAEAFNOSUPPORT Addresses in the specified family cannot be used with
// 	this socket.
//
// 	WSAECONNREFUSED The attempt to connect was forcefully rejected.
//
// 	WSAENETUNREACH The network cannot be reached from this host at this
// 	time.
//
// 	WSAEFAULT The namelen parameter is incorrect.
//
// 	WSAEINVAL The socket is already bound to an address.
//
// 	WSAEISCONN The socket is already connected.
//
// 	WSAEMFILE No more file descriptors are available.
//
// 	WSAENOBUFS No buffer space is available. The socket cannot be
// 	connected.
//
// 	WSAENOTCONN The socket is not connected.
//
// 	WSAETIMEDOUT Attempt to connect timed out without establishing a
// 	connection.
//
//
//
// 	Event: FD_CLOSE
//
// 	Error Code Meaning
//
// 	WSAENETDOWN The network subsystem has failed.
//
// 	WSAECONNRESET The connection was reset by the remote side.
//
// 	WSAECONNABORTED The connection was terminated due to a time-out or
// 	other failure.
//
//
// 	Event: FD_READ
//
// 	Event: FD_WRITE
//
// 	Event: FD_OOB
//
// 	Event: FD_ACCEPT
//
// 	Event: FD_QOS
//
// 	Event: FD_GROUP_QOS
//
// 	Error Code Meaning
//
// 	WSAENETDOWN The network subsystem has failed.
//
// ----------------------------------------------------------------
